diff --git a/addons/AutoRA/AutoRA.lua b/addons/AutoRA/AutoRA.lua index d68d89a914..49dd1bb19e 100644 --- a/addons/AutoRA/AutoRA.lua +++ b/addons/AutoRA/AutoRA.lua @@ -1,4 +1,106 @@ ---Copyright (c) 2013, Banggugyangu +_addon.author = 'Banggugyangu' +_addon.version = '3.0.0' +_addon.commands = {'autora', 'ara'} + +require('functions') +local config = require('config') + +local defaults = { + HaltOnTp = true, + Delay = 1.5 +} + +local settings = config.load(defaults) + +local auto = false +local player_id + +windower.send_command('bind ^d ara start') +windower.send_command('bind !d ara stop') + +local shoot = function() + windower.send_command('input /shoot ') +end + +local start = function() + auto = true + windower.add_to_chat(17, 'AutoRA STARTING~~~~~~~~~~~~~~') + + shoot() +end + +local stop = function() + auto = false + windower.add_to_chat(17, 'AutoRA STOPPING ~~~~~~~~~~~~~~') +end + +local haltontp = function() + settings.HaltOnTp = not settings.HaltOnTp + + if settings.HaltOnTp then + windower.add_to_chat(17, 'AutoRA will halt upon reaching 1000 TP') + else + windower.add_to_chat(17, 'AutoRA will no longer halt upon reaching 1000 TP') + end +end + +local check = function() + if not auto then + return + end + + local player = windower.ffxi.get_player() + if not player or not player.target_index then + return + end + + if player.vitals.tp >= 1000 and settings.HaltOnTp then + auto = false + windower.add_to_chat(17, 'AutoRA HALTING AT 1000 TP ~~~~~~~~~~~~~~') + elseif player.status == 1 then + shoot() + end +end + +windower.register_event('action', function(action) + if auto and action.actor_id == player_id and action.category == 2 then + check:schedule(settings.Delay) + end +end) + +windower.register_event('addon command', function(command) + command = command and command:lower() or 'help' + + if command == 'start' then + start() + elseif command == 'stop' then + stop() + elseif command == 'shoot' then + shoot() + elseif command == 'reload' then + setDelay() + elseif command == 'haltontp' then + haltontp() + elseif command == 'help' then + windower.add_to_chat(17, 'AutoRA v' .. _addon.version .. 'commands:') + windower.add_to_chat(17, '//ara [options]') + windower.add_to_chat(17, ' start - Starts auto attack with ranged weapon') + windower.add_to_chat(17, ' stop - Stops auto attack with ranged weapon') + windower.add_to_chat(17, ' haltontp - Toggles automatic halt upon reaching 1000 TP') + windower.add_to_chat(17, ' help - Displays this help text') + windower.add_to_chat(17, ' ') + windower.add_to_chat(17, 'AutoRA will only automate ranged attacks if your status is "Engaged". Otherwise it will always fire a single ranged attack.') + windower.add_to_chat(17, 'To start auto ranged attacks without commands use the key: Ctrl+D') + windower.add_to_chat(17, 'To stop auto ranged attacks in the same manner: Atl+D') + end +end) + +windower.register_event('load', 'login', 'logout', function() + local player = windower.ffxi.get_player() + player_id = player and player.id +end) + +--Copyright © 2013, Banggugyangu --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -23,149 +125,3 @@ --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. - - -windower.register_event('load',function () - - version = '2.1.2' - delay = 0 - RW_delay = 0 - Ammo_delay = 0 - retrn = 0 - halt_on_tp = true - windower.send_command('unbind ^d') - windower.send_command('unbind !d') - windower.send_command('bind ^d ara start') - windower.send_command('bind !d ara stop') - windower.send_command('alias ara lua c autora') - -end) - -function start() - windower.add_to_chat(17, 'AutoRA STARTING~~~~~~~~~~~~~~') - player = windower.ffxi.get_player() - if player.status == 1 then - auto = 1 - elseif player.status == 0 then - auto = 0 - end - shoot() -end - -function stop() - windower.add_to_chat(17, 'AutoRA STOPPING ~~~~~~~~~~~~~~') - auto = 0 -end - -function shoot() - windower.send_command('input /shoot ') -end - -function shootOnce() - windower.send_command('input /shoot ') -end - ---Function Author: Byrth -function split(msg, match) - local length = msg:len() - local splitarr = {} - local u = 1 - while u <= length do - local nextanch = msg:find(match,u) - if nextanch ~= nil then - splitarr[#splitarr+1] = msg:sub(u,nextanch-match:len()) - if nextanch~=length then - u = nextanch+match:len() - else - u = lengthlua - end - else - splitarr[#splitarr+1] = msg:sub(u,length) - u = length+1 - end - end - return splitarr -end - -function haltontp() - - if halt_on_tp == true then - windower.add_to_chat(17, 'AutoRA will no longer halt upon reaching 1000 TP') - halt_on_tp = false - elseif halt_on_tp == false then - windower.add_to_chat(17, 'AutoRA will halt upon reaching 1000 TP') - halt_on_tp = true - end - -end - -windower.register_event('action',function (act) - local actor = act.actor_id - local category = act.category - local player = windower.ffxi.get_player() - - if ((actor == (player.id or player.index))) then - if category == 2 then - if player.vitals['tp'] < 1000 then - if auto == 1 then - if player.status == 1 then - auto = 1 - elseif player.status == 0 then - auto = 0 - return - end - end - if auto == 1 then - windower.send_command('@wait 1.5;input /shoot ') - elseif auto == 0 then - end - else - if halt_on_tp == true then - windower.add_to_chat(17, 'AutoRA HALTING AT 1000 TP ~~~~~~~~~~~~~~') - return - else - if auto == 1 then - if player.status == 1 then - auto = 1 - elseif player.status == 0 then - auto = 0 - return - end - end - if auto == 1 then - windower.send_command('@wait 1.5;input /shoot ') - elseif auto == 0 then - end - end - end - end - end -end) - ---Function Designer: Byrth -windower.register_event('addon command',function (...) - local term = table.concat({...}, ' ') - local splitarr = split(term,' ') - if splitarr[1]:lower() == 'start' then - start() - elseif splitarr[1]:lower() == 'stop' then - stop() - elseif splitarr[1]:lower() == 'shoot' then - shoot() - elseif splitarr[1]:lower() == 'reload' then - setDelay() - elseif splitarr[1]:lower() == 'haltontp' then - haltontp() - elseif splitarr[1]:lower() == 'help' then - windower.add_to_chat(17, 'AutoRA v'..version..'commands:') - windower.add_to_chat(17, '//ara [options]') - windower.add_to_chat(17, ' start - Starts auto attack with ranged weapon') - windower.add_to_chat(17, ' stop - Stops auto attack with ranged weapon') - windower.add_to_chat(17, ' haltontp - Toggles automatic halt upon reaching 1000 TP') - windower.add_to_chat(17, ' help - Displays this help text') - windower.add_to_chat(17, ' ') - windower.add_to_chat(17, 'AutoRA will only automate ranged attacks if your status is "Engaged". Otherwise it will always fire a single ranged attack.') - windower.add_to_chat(17, 'To start auto ranged attacks without commands use the key: Ctrl+d') - windower.add_to_chat(17, 'To stop auto ranged attacks in the same manner: Atl+d') - end -end) diff --git a/addons/BattleStations/LICENSE b/addons/BattleStations/LICENSE new file mode 100644 index 0000000000..d719b9e710 --- /dev/null +++ b/addons/BattleStations/LICENSE @@ -0,0 +1,25 @@ +Copyright © 2018, Sjshovan (Apogee) +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 Battle Stations 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 Sjshovan (Apogee) 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. \ No newline at end of file diff --git a/addons/BattleStations/README.md b/addons/BattleStations/README.md new file mode 100644 index 0000000000..83fd082457 --- /dev/null +++ b/addons/BattleStations/README.md @@ -0,0 +1,225 @@ +**Author:** [Sjshovan (Apogee)](https://github.com/Ap0gee) +**Version:** v0.9.1 + + +# Battle Stations + +> A Windower 4 addon that allows the user to change or remove the default battle music in Final Fantasy 11 Online. + + +### Table of Contents + +- [Prerequisites](#prerequisites) +- [Installation](#installation) +- [Aliases](#aliases) +- [Usage](#usage) +- [Commands](#commands) +- [Support](#support) +- [Change Log](#change-log) +- [Known Issues](#known-issues) +- [TODOs](#todos) +- [License](#license) + +___ +### Prerequisites +1. [Final Fantasy 11 Online](http://www.playonline.com/ff11us/index.shtml) +2. [Windower 4](http://windower.net/) + +___ +### Installation + +**Windower:** +1. Navigate to the `Addons` section at the top of Windower. +2. Locate the `BattleStations` addon. +3. Click the download button. +4. Ensure the addon is switched on. + +**Manual:** +1. Navigate to . +2. Click on `Releases`. +3. Click on the `Source code (zip)` link within the latest release to download. +4. Extract the zipped folder to `Windower4/addons/`. +5. Rename the folder to remove the version tag (`-v0.9.0`). The folder should be named `BattleStations`. + +___ +### Aliases +The following aliases are available to Battle Stations commands: + +**battlestations:** stations | bs +**list:** l +**set:** s +**get:** g +**default:** d +**normal:** n +**reload:** r +**about:** a +**help:** h +**stations:** station | s +**radios:** receivers | receiver | radio | r +**all:** all | a | * + +___ +### Usage + +Manually load the addon by using one of the following commands: + + //lua load battlestations + //lua l battlestations + +___ +### Commands + +**help** + +Displays the available Battle Stations commands. Below are the equivalent ways of calling the command: + + //battlestations help + //stations help + //bs help + + //battlestations h + //stations h + //bs h + +**list _[radios|stations] [category#]_** + +Displays the available radios and or stations. Below are some useage examples of this command: + + //bs list + //bs l + + //bs list radios + //bs l radios + //bs l r + + //bs list stations + //bs l stations + //bs l s + + //bs l s 100 + +* _**[radios|stations]:**_ Optional parameter used to filter the list display to show only available radios or stations. If neither filter type is present, all available stations and radios will be listed. +* _**[category#]:**_ Optional parameter used to filter the list of stations by the given category number. The available category numbers are 100-107. + +**set _\ [radio]_** + +Sets the radio(s) to the given station. Below are some useage examples of this command: + + //bs set 100.1 + //bs s 100.1 + + //bs s 100.1 solo + //bs s 100.1 party + +* _**\:**_ Required parameter. +* _**[radio]:**_ Optional parameter used to specify which radio to set the given station to. If no radio type is present both radios will be set to the given station. + +**get _[radio]_** + +Displays the currently set station on the given radio(s). Below are some useage examples of this command: + + //bs get + //bs g + + //bs g solo + //bs g party + +* _**[radio]:**_ Optional parameter used to specify the radio for which you would like to display the currently set station. If no radio type is present, the currently set station for both radios will be displayed. + +**default _[radio]_** + +Sets the given radio(s) to the default station (Current Zone Music). Below are some useage examples of this command: + + //bs default + //bs d + + //bs d solo + //bs d party + +* _**[radio]:**_ Optional parameter used to specify which radio to set the default station to. If no radio type is present, both radios will be set to the default station. + + +**normal _[radio]_** + +Sets the given radio(s) to the original game music. Below are some useage examples of this command: + + //bs normal + //bs n + + //bs n solo + //bs n party + +* _**[radio]:**_ Optional parameter used to specify which radio to set the normal station to. If no radio type is present, both radios will be set to the normal station. + +**reload** + +Reloads the Battle Stations addon. Below are the equivalent ways of calling the command: + + //battlestations reload + //stations reload + //bs reload + + //battlestations r + //stations r + //bs r + +**about** + +Displays information about the Battle Stations addon. Below are the equivalent ways of calling the command: + + /battlestations about + //stations about + //bs about + + //battlestations a + //stations a + //bs a + +___ +### Support +**Having Issues with this addon?** +* Please let me know [here](https://github.com/Ap0gee/BattleStations/issues/new). + +**Have something to say?** +* Send me some feedback here: + +**Want to stay in the loop with my work?** +* You can follow me at: + +**Want to toss a coin to your modder?** +* You can do so here: + +___ +### Change Log + +**v0.9.1** - 12/29/2019 +- **Fix:** Resolved mismatched setting type error within the `bs normal` command. +- **Add:** New command added (about). +- **Update:** Silent song id changed to help prevent future game updates from overriding. +- **Update:** README Commands updated. +- **Update:** README Aliases updated. +- **Update:** README Known Issues updated. +- **Update:** README TODOS updated. + +**v0.9.0** - 6/19/2018 +- Initial release + +___ +### Known Issues + +- **Issue:** During campaign battles in the past, the music switches from the campaign music to the normal zone music while stations are set to `107.3`. + +___ +### TODOS + +- **TODO:** Consider providing aliases to stations to make references easier. +- **TODO:** Consider adding categories as a list type. +- **TODO:** Investigate methods for resolving the campaign battle music issue. +___ + +### License + +Copyright © 2018, [Sjshovan (Apogee)](https://github.com/Ap0gee). +Released under the [BSD License](LICENSE). + +*** \ No newline at end of file diff --git a/addons/BattleStations/battlestations.lua b/addons/BattleStations/battlestations.lua new file mode 100644 index 0000000000..5c2922ad1f --- /dev/null +++ b/addons/BattleStations/battlestations.lua @@ -0,0 +1,597 @@ +--[[ +Copyright © 2018, Sjshovan (Apogee) +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 Battle Stations 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 Sjshovan (Apogee) 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 = 'Battle Stations' +_addon.description = 'Change or remove the default battle music.' +_addon.author = 'Sjshovan (Apogee) sjshovan@gmail.com' +_addon.version = '0.9.1' +_addon.commands = {'battlestations', 'stations', 'bs'} + +local _logger = require('logger') +local _config = require('config') +local _packets = require('packets') + +require('functions') +require('constants') +require('helpers') + +local defaults = { + stations = { + solo = 107.3, + party = 107.3 + } +} + +local settings = _config.load(defaults) + +local help = { + commands = { + buildHelpSeperator('=', 28), + buildHelpTitle('Commands'), + buildHelpSeperator('=', 28), + buildHelpCommandEntry('list [radios|stations] [category#]', 'Display the available radios and or stations.'), + buildHelpCommandEntry('set [radio]', 'Set radio(s) to the given station.'), + buildHelpCommandEntry('get [radio]', 'Display currently set station on the given radio(s).'), + buildHelpCommandEntry('default [radio]', 'Set radio(s) to the default station (Current Zone Music).'), + buildHelpCommandEntry('normal [radio]', 'Set radio(s) to the original game music.'), + buildHelpCommandEntry('reload', 'Reload Battle Stations.'), + buildHelpCommandEntry('about', 'Display information about Battle Stations.'), + buildHelpCommandEntry('help', 'Display Battle Stations commands.'), + buildHelpSeperator('=', 28), + }, + + radios = { + buildHelpSeperator('=', 25), + buildHelpTitle('Radios'), + buildHelpSeperator('=', 25), + buildHelpRadioEntry(stations.receivers.solo:ucfirst(), 'Plays Solo Battle Music'), + buildHelpRadioEntry(stations.receivers.party:ucfirst(), 'Plays Party Battle Music'), + buildHelpSeperator('=', 25), + }, + + about = { + buildHelpSeperator('=', 23), + buildHelpTitle('About'), + buildHelpSeperator('=', 23), + buildHelpTypeEntry('Name', _addon.name), + buildHelpTypeEntry('Description', _addon.description), + buildHelpTypeEntry('Author', _addon.author), + buildHelpTypeEntry('Version', _addon.version), + buildHelpSeperator('=', 23), + }, + + aliases = { + list = { + stations = T{ + 's', + 'station', + 'stations', + }, + radios = T{ + 'r', + 'radio', + 'radios', + 'receiver', + 'receivers' + }, + categories = T{ + 'c', + 'cat', + 'category', + 'categories' + }, + all = T{ + '*', + 'a', + 'all', + } + } + } +} + +function displayHelp(table_help) + for index, command in pairs(table_help) do + displayResponse(command) + end +end + +function displayStations(range) + displayResponse(buildHelpSeperator('=', 27)) + displayResponse(buildHelpTitle('Stations')) + displayResponse(buildHelpSeperator('=', 27)) + + if range ~= nil then + if categoryValid(range) then + displayRangeFrequencies(range) + end + else + for i=100, 107, 1 do + range = tostring(i) + displayRangeFrequencies(range) + end + end + displayResponse(buildHelpSeperator('=', 26)) +end + +function displayRangeFrequencies(range, name) + local categories = stations.categories + + if categoryValid(range) then + local name = categories[range] + displayResponse(buildHelpStationCategoryEntry(range, name)) + displayFrequencies(range) + end +end + +function displayFrequencies(range) + for i=1, 9, 1 do + local frequency = range .. '.%s':format(tostring(i)) + if frequencyValid(frequency) then + local frequencyObj = getFrequencyObjByValue(frequency) + local response = buildHelpStationEntry(frequency, frequencyObj.callSign) + displayResponse(response) + end + end +end + +function displayCategories() + displayResponse(buildHelpSeperator('=', 27)) + displayResponse(buildHelpTitle('Categories')) + displayResponse(buildHelpSeperator('=', 27)) + for i=100, 107, 1 do + local range = tostring(i) + if categoryValid(range) then + local name = stations.categories[range] + displayResponse(buildHelpStationCategoryEntry(range, name)) + end + end + displayResponse(buildHelpSeperator('=', 27)) +end + +function getStations() + return settings.stations +end + +function setStation(radio, frequency) + if radio == stations.receivers.solo then + settings.stations.solo = frequency + elseif radio == stations.receivers.party then + settings.stations.party = frequency + else + settings.stations.solo = frequency + settings.stations.party = frequency + end + + settings:save() +end + +function resolveCurrentStations() + local current_stations = getStations() + local radio = 'solo' + local frequency = tostring(defaults.stations.solo) + local message_template = '%s station found in settings was not valid and was set to the default %s (%s).' + + if not frequencyValid(current_stations.solo) then + current_stations.solo = frequency + setStation(radio, frequency) + + displayResponse( + buildWarningMessage( + message_template:format( + radio:ucfirst():color(colors.secondary), + frequency:color(colors.primary), + getFrequencyObjByValue(frequency).callSign + ) + ) + ) + end + + if not frequencyValid(current_stations.party) then + radio = 'party' + frequency = tostring(defaults.stations.party) + current_stations.party = party_default + + setStation(radio, frequency) + + displayResponse( + buildWarningMessage( + message_template:format( + radio:ucfirst():color(colors.secondary), + frequency:color(colors.primary), + getFrequencyObjByValue(frequency).callSign + ) + ) + ) + end + + return current_stations +end + +function injectBattleMusic() + local current_stations = resolveCurrentStations() + local song = getFrequencyObjByValue(current_stations.solo).song + local music_type = music.types.battle_solo + + if playerInParty() then + music_type = music.types.battle_party + song = getFrequencyObjByValue(current_stations.party).song + end + + song = getConditionalSongTranslation(song) + + _packets.inject(_packets.new('incoming', packets.inbound.music_change.id, { + ['BGM Type'] = music_type, + ['Song ID'] = song + })) +end + +function getFrequencyObjByValue(frequency) + return stations.frequencies[tostring(frequency)] +end + +function getCurrentTime(formatted) + local timestamp = tostring(windower.ffxi.get_info().time) + local hours = (timestamp / 60):floor() + local minutes = timestamp % 60 + if formatted then + return "%s:%s":format(hours, minutes) + end + return timestamp +end + +function getZoneBGMTable() + local data = windower.packets.last_incoming(packets.inbound.zone_update.id) + local packet = _packets.parse('incoming', data) + return { + day = packet['Day Music'], + night = packet['Night Music'], + solo = packet['Solo Combat Music'], + party = packet['Party Combat Music'] + } +end + +function getConditionalSongTranslation(song) + local zone_bgm_table = getZoneBGMTable() + if song == music.songs.others.zone then + if timeIsDaytime() then + song = zone_bgm_table.day + else + song = zone_bgm_table.night + end + + if playerInReive() then + song = music.songs.seekers_of_adoulin.breaking_ground + end + + elseif song == music.songs.others.normal then + if playerInParty() then + song = zone_bgm_table.party + else + song = zone_bgm_table.solo + end + end + return song +end + +function getPlayerBuffs() + return T(windower.ffxi.get_player().buffs) +end + +function timeIsDaytime() + local current_time = tonumber(getCurrentTime()) + return current_time >= 6*60 and current_time <= 18*60 +end + +function playerIsFighting() + return windower.ffxi.get_player().status == player.statuses.fighting +end + +function playerInParty() + return windower.ffxi.get_party().alliance_count > 1 +end + +function playerInReive() + return getPlayerBuffs():contains(player.buffs.reiveMark) +end + +function frequencyValid(frequency) + return stations.frequencies[tostring(frequency)] ~= nil +end + +function radioValid(radio) + return stations.receivers[radio] ~= nil or radio == '*' +end + +function categoryValid(category) + return stations.categories[category] ~= nil +end + +function listTypeValid(list_type) + return help.lists[list_type] ~= nil +end + +function handleInjectionNeeds() + if needs_inject then + injectBattleMusic() + needs_inject = false; + end +end + +windower.register_event('load', function () + injectBattleMusic() +end) + +windower.register_event('unload', function() + local music_type = music.types.battle_solo + local zone_bgm_table = getZoneBGMTable() + local song = zone_bgm_table.solo + + if playerInParty() then + music_type = music.types.battle_party + song = zone_bgm_table.solo + end + + _packets.inject(_packets.new('incoming', packets.inbound.music_change.id, { + ['BGM Type'] = music_type, + ['Song ID'] = song, + })) +end) + +windower.register_event('action', function(act) + if act.actor_id == windower.ffxi.get_player().id then + if act.category == 4 and act.recast == 225 and act.targets[1].actions[1].animation == 939 then + if not playerInParty() then + functions.loop(injectBattleMusic, 1, 5) + end + end + end +end) + +windower.register_event('outgoing chunk', function(id, data) + if id == packets.outbound.action.id then + local packet = _packets.parse('outgoing', data) + if packet.Category == packets.outbound.action.categories.engage then + injectBattleMusic() + end + end +end) + +windower.register_event('addon command', function(command, ...) + if command then + command = command:lower() + else + displayHelp(help.commands) + return + end + + local command_args = {...} + + local respond = false + local response_message = '' + local success = true + + if command == 'list' or command == 'l' then + local list_type = (command_args[1] or '*'):lower() + local category = command_args[2] + + if help.aliases.list.stations:contains(list_type) then + if category then + if categoryValid(category) then + displayStations(category) + + else + respond = true + success = false + response_message = 'Category not recognized.' + end + else + displayStations() + end + + elseif help.aliases.list.radios:contains(list_type) then + displayHelp(help.radios) + + elseif help.aliases.list.categories:contains(list_type) then + displayCategories() + + elseif help.aliases.list.all:contains(list_type) then + displayHelp(help.radios) + displayStations() + + else + respond = true + success = false + response_message = 'List type not recognized.' + end + + elseif command == 'set' or command == 's' then + respond = true + + local frequency = command_args[1]:lower() + + local radio = (command_args[2] or '*'):lower() + + if not frequencyValid(frequency) then + success = false + response_message = 'Frequency not recognized.' + + elseif not radioValid(radio) then + success = false + response_message = 'Radio not recognized.' + else + needs_inject = true + + local context = 'radio' + + setStation(radio, tonumber(frequency)) + + if radio == '*' then + context = 'radios' + radio = 'Solo and Party' + end + + response_message = buildSetResponseMessage( + radio:ucfirst(), + context, + frequency, + getFrequencyObjByValue(frequency).callSign + )..'.' + end + + elseif command == 'get' or command == 'g' then + respond = true + + local current_stations = resolveCurrentStations() + local radio = (command_args[1] or '*'):lower() + local frequency = current_stations[radio] + local frequency2 = current_stations.party + local individual = false + + if not radioValid(radio) then + success = false + response_message = 'Radio not recognized.' + else + local context = 'radio is' + + if radio == '*' then + frequency = current_stations.solo + + if current_stations.party ~= current_stations.solo then + individual = true + else + context = 'radios are' + radio = 'Solo and Party' + end + end + + if not individual then + response_message = buildGetResponseMessage( + radio:ucfirst(), + context, + frequency, + getFrequencyObjByValue(frequency).callSign + )..'.' + + else + local solo_message = buildGetResponseMessage( + stations.receivers.solo:ucfirst(), + context, + frequency, + getFrequencyObjByValue(frequency).callSign + ) + + local party_message = buildGetResponseMessage( + stations.receivers.party:ucfirst(), + context, + frequency2, + getFrequencyObjByValue(frequency2).callSign + ) + + response_message = solo_message..' and '..party_message..'.' + end + end + + elseif command == 'default' or command == 'd' then + respond = true + + local radio = (command_args[1] or '*'):lower() + + if not radioValid(radio) then + success = false + response_message = 'Radio not recognized.' + else + needs_inject = true + + local frequency = defaults.stations.solo + local context = 'radio' + + setStation(radio, tonumber(frequency)) + + if radio == '*' then + context = 'radios' + radio = 'Solo and Party' + end + + response_message = buildSetResponseMessage( + radio:ucfirst(), + context, + frequency, + getFrequencyObjByValue(frequency).callSign + )..'.' + end + + elseif command == 'normal' or command == 'n' then + respond = true + + local radio = (command_args[1] or '*'):lower() + + if not radioValid(radio) then + success = false + response_message = 'Radio not recognized.' + else + needs_inject = true + + local frequency = '107.2' + local context = 'radio' + + setStation(radio, tonumber(frequency)) + + if radio == '*' then + context = 'radios' + radio = 'Solo and Party' + end + + response_message = buildSetResponseMessage( + radio:ucfirst(), + context, + frequency, + getFrequencyObjByValue(frequency).callSign + )..'.' + end + + elseif command == 'reload' or command == 'r' then + windower.send_command('lua r battlestations') + + elseif command == 'about' or command == 'a' then + displayHelp(help.about) + + elseif command == 'help' or command == 'h' then + displayHelp(help.commands) + + else + displayHelp(help.commands) + end + + if respond then + displayResponse( + buildCommandResponse(response_message, success) + ) + end + + handleInjectionNeeds() +end) \ No newline at end of file diff --git a/addons/BattleStations/constants.lua b/addons/BattleStations/constants.lua new file mode 100644 index 0000000000..950ecc103b --- /dev/null +++ b/addons/BattleStations/constants.lua @@ -0,0 +1,382 @@ +--[[ +Copyright © 2018, Sjshovan (Apogee) +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 Battle Stations 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 Sjshovan (Apogee) 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. +]] + +packets = { + inbound = { + music_change = { + id = 0x05F + }, + zone_update = { + id = 0x00A + } + }, + outbound = { + action = { + id = 0x1A, + categories = { + engage = 2, + disengage = 4 + + }, + } + }, +} + +player = { + statuses = { + idle = 0x00, + fighting = 0x01, + }, + buffs = { + reiveMark = 511 + } +} + +colors = { + primary = 200, + secondary = 207, + info = 0, + warn = 140, + danger = 167, + success = 158 +} + +music = { + songs = { + final_fantasy_xi = { + battle_theme = 101, + battle_theme_2 = 103, + battle_in_the_dungeon = 115, + battle_in_the_dungeon_2 = 102, + tough_battle = 125, + awakening = 119 + }, + rise_of_the_zilart = { + battle_theme_3 = 191, + battle_in_the_dungeon_3 = 192, + tough_battle_2 = 193, + fighters_of_the_crystal = 196, + ealdnarche = 198, + belief = 195 + }, + chains_of_promathia = { + onslaught = 219, + depths_of_the_soul = 218, + turmoil = 220, + ruler_of_the_skies = 232, + dusk_and_dawn = 224, + a_realm_of_emptiness = 137 + }, + treasures_of_aht_urhgan = { + mercenaries_delight = 138, + delve = 139, + rapid_onslaught_assault = 144, + fated_strife_besieged = 142, + hellriders = 143, + black_coffin = 172, + iron_colossus = 186, + ragnarok = 187 + }, + wings_of_the_goddess = { + clash_of_standards = 215, + on_this_blade = 216, + roar_of_the_battle_drums = 247, + run_maggot_run = 249, + under_a_clouded_moon = 250, + kindred_cry = 217, + provenance_watcher = 55, + goddess_divine = 46 + }, + seekers_of_adoulin = { + steel_sings_blades_dance = 57, + breaking_ground = 64, + buccaneers = 170, + keepers_of_the_wild = 62 + }, + add_ons = { + echoes_of_creation = 47, + luck_of_the_mog = 49, + a_feast_for_ladies = 50, + melodies_errant = 52, + shinryu = 53, + wail_of_the_void = 82 + }, + others = { + silent = 9999, + normal = 09, + zone = 00 + }, + }, + types = { + battle_solo = 2, + battle_party = 3, + idle_day = 0, + idle_night = 1 + } +} + +stations = { + receivers = T{ + solo = 'solo', + party = 'party' + }, + + categories = T{ + ['100'] = 'Final Fantasy XI', + ['101'] = 'Rise of the Zilart', + ['102'] = 'Chains of Promathia', + ['103'] = 'Treasures of Aht Urhgan', + ['104'] = 'Wings of the Goddess', + ['105'] = 'Seekers of Adoulin', + ['106'] = 'Add-Ons', + ['107'] = 'Others' + }, + + frequencies = T{ + + --(100) Final Fantasy XI -- + + ['100.1'] = { + callSign = 'Battle Theme', + song = music.songs.final_fantasy_xi.battle_theme + }, + ['100.2'] = { + callSign = 'Battle Theme 2', + song = music.songs.final_fantasy_xi.battle_theme_2 + }, + ['100.3'] = { + callSign = 'Battle in the Dungeon', + song = music.songs.final_fantasy_xi.battle_in_the_dungeon + }, + ['100.4'] = { + callSign = 'Battle in the Dungeon 2', + song = music.songs.final_fantasy_xi.battle_in_the_dungeon_2 + }, + ['100.5'] = { + callSign = 'Tough Battle', + song = music.songs.final_fantasy_xi.tough_battle + }, + ['100.6'] = { + callSign = 'Awakening', + song = music.songs.final_fantasy_xi.awakening + }, + + --(101) Rise of the Zilart -- + + ['101.1'] = { + callSign = 'Battle Theme 3', + song = music.songs.rise_of_the_zilart.battle_theme_3 + }, + ['101.2'] = { + callSign = 'Battle in the Dungeon 3', + song = music.songs.rise_of_the_zilart.battle_in_the_dungeon_3 + }, + ['101.3'] = { + callSign = 'Tough Battle 2', + song = music.songs.rise_of_the_zilart.tough_battle_2 + }, + ['101.4'] = { + callSign = 'Fighters of the Crystal', + song = music.songs.rise_of_the_zilart.fighters_of_the_crystal + }, + ['101.5'] = { + callSign = "Eald'narche", + song = music.songs.rise_of_the_zilart.ealdnarche + }, + ['101.6'] = { + callSign = 'Belief', + song = music.songs.rise_of_the_zilart.belief + }, + + --(102) Chains of Promathia -- + + ['102.1'] = { + callSign = 'Onslaught', + song = music.songs.chains_of_promathia.onslaught + }, + ['102.2'] = { + callSign = 'Depths of the Soul', + song = music.songs.chains_of_promathia.depths_of_the_soul + }, + ['102.3'] = { + callSign = 'Turmoil', + song = music.songs.chains_of_promathia.turmoil + }, + ['102.4'] = { + callSign = 'Ruler of the Skies', + song = music.songs.chains_of_promathia.ruler_of_the_skies + }, + ['102.5'] = { + callSign = 'Dusk and Dawn', + song = music.songs.chains_of_promathia.dusk_and_dawn + }, + ['102.6'] = { + callSign = 'A Realm of Emptiness', + song = music.songs.chains_of_promathia.a_realm_of_emptiness + }, + + --(103) Treasures of Aht Urhgan -- + + ['103.1'] = { + callSign = "Mercenaries' Delight", + song = music.songs.treasures_of_aht_urhgan.mercenaries_delight + }, + ['103.2'] = { + callSign = 'Delve', + song = music.songs.treasures_of_aht_urhgan.delve + }, + ['103.3'] = { + callSign = 'Rapid Onslaught -Assult-', + song = music.songs.treasures_of_aht_urhgan.rapid_onslaught_assault + }, + ['103.4'] = { + callSign = 'Fated Strife -Besieged-', + song = music.songs.treasures_of_aht_urhgan.fated_strife_besieged + }, + ['103.5'] = { + callSign = 'Hellriders', + song = music.songs.treasures_of_aht_urhgan.hellriders + }, + ['103.6'] = { + callSign = 'Black Coffin', + song = music.songs.treasures_of_aht_urhgan.black_coffin + }, + ['103.7'] = { + callSign = 'Iron Colossus', + song = music.songs.treasures_of_aht_urhgan.iron_colossus + }, + ['103.8'] = { + callSign = 'Ragnarok', + song = music.songs.treasures_of_aht_urhgan.ragnarok + }, + + --(104) Wings of the Goddess -- + + ['104.1'] = { + callSign = 'Clash of Standards', + song = music.songs.wings_of_the_goddess.clash_of_standards + }, + ['104.2'] = { + callSign = 'On this Blade', + song = music.songs.wings_of_the_goddess.on_this_blade + }, + ['104.3'] = { + callSign = 'Roar of the Battle Drums', + song = music.songs.wings_of_the_goddess.roar_of_the_battle_drums + }, + ['104.4'] = { + callSign = 'Run Maggot, Run!', + song = music.songs.wings_of_the_goddess.run_maggot_run + }, + ['104.5'] = { + callSign = 'Under a Clouded Moon', + song = music.songs.wings_of_the_goddess.under_a_clouded_moon + }, + ['104.6'] = { + callSign = 'Kindred Cry', + song = music.songs.wings_of_the_goddess.kindred_cry + }, + ['104.7'] = { + callSign = 'Provenance Watcher', + song = music.songs.wings_of_the_goddess.provenance_watcher + }, + ['104.8'] = { + callSign = 'Goddess Divine', + song = music.songs.wings_of_the_goddess.goddess_divine + }, + + --(105) Seekers of Adoulin -- + + ['105.1'] = { + callSign = 'Steel Sings, Blades Dance', + song = music.songs.seekers_of_adoulin.steel_sings_blades_dance + }, + ['105.2'] = { + callSign = 'Braking Ground', + song = music.songs.seekers_of_adoulin.breaking_ground + }, + ['105.3'] = { + callSign = 'Buccaneers', + song = music.songs.seekers_of_adoulin.buccaneers + }, + ['105.4'] = { + callSign = 'Keepers of the Wild', + song = music.songs.seekers_of_adoulin.keepers_of_the_wild + }, + + --(106) Add-Ons -- + + ['106.1'] = { + callSign = 'Echoes of Creation', + song = music.songs.add_ons.echoes_of_creation + }, + ['106.2'] = { + callSign = 'Luck of the Mog', + song = music.songs.add_ons.luck_of_the_mog + }, + ['106.3'] = { + callSign = 'A Feast for Ladies', + song = music.songs.add_ons.a_feast_for_ladies + }, + ['106.4'] = { + callSign = 'Melodies Errant', + song = music.songs.add_ons.melodies_errant + }, + ['106.5'] = { + callSign = 'Shinryu', + song = music.songs.add_ons.shinryu + }, + ['106.6'] = { + callSign = 'Wail of the Void', + song = music.songs.add_ons.wail_of_the_void + }, + + --(107) Others -- + + ['107.1'] = { + callSign = 'No Music', + song = music.songs.others.silent + }, + ['107.2'] = { + callSign = 'Original Music', + song = music.songs.others.normal + }, + ['107.3'] = { + callSign = 'Current Zone Music (Default)', + song = music.songs.others.zone + } + } +} + +return { + packets = packets, + player = player, + colors = colors, + music = music, + stations = stations +} \ No newline at end of file diff --git a/addons/BattleStations/helpers.lua b/addons/BattleStations/helpers.lua new file mode 100644 index 0000000000..17b2acfa2c --- /dev/null +++ b/addons/BattleStations/helpers.lua @@ -0,0 +1,121 @@ +--[[ +Copyright © 2018, Sjshovan (Apogee) +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 Battle Stations 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 Sjshovan (Apogee) 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. +]] + +local colors = require("constants").colors + +function buildHelpCommandEntry(command, description) + local entry_template = "%s %s %s %s" + local short_name = "bs":color(colors.primary) + local command = command:color(colors.secondary) + local sep = "=>":color(colors.primary) + local description = description:color(colors.info) + return entry_template:format(short_name, command, sep, description) +end + +function buildHelpTypeEntry(name, description) + local entry_template = "%s %s %s" + local name = name:color(colors.secondary) + local sep = "=>":color(colors.primary) + local description = description:color(colors.info) + return entry_template:format(name, sep, description) +end + +function buildHelpRadioEntry(name, description) + local entry_template = "%s %s %s" + local name = name:color(colors.secondary) + local sep = "=>":color(colors.primary) + local description = description:color(colors.info) + return entry_template:format(name, sep, description) +end + +function buildHelpStationEntry(frequency, callSign) + local entry_template = " %s %s %s" + local frequency = frequency:color(colors.secondary) + local sep = "=>":color(colors.primary) + local callSign = callSign:color(colors.info) + return entry_template:format(frequency, sep, callSign) +end + +function buildHelpStationCategoryEntry(range, name) + local entry_template = "(%s) %s" + local range = range:color(colors.primary) + local name = name:color(colors.danger) + return entry_template:format(range, name) +end + +function buildHelpTitle(context) + local title_template = "%s Help: %s" + local context = context:color(colors.danger) + return title_template:color(colors.primary):format(_addon.name, context) +end + +function buildHelpSeperator(character, count) + local sep = '' + for i = 1, count do + sep = sep .. character + end + return sep:color(colors.warn) +end + +function buildCommandResponse(message, success) + local response_template = '%s: %s' + local response_color = colors.success + local response_type = 'Success' + + if not success then + response_type = 'Error' + response_color = colors.danger + end + return response_template:format(response_type:color(response_color), message) +end + +function buildWarningMessage(message) + local message_template = '%s: %s' + local response_type = 'Note' + return message_template:format(response_type:color(colors.warn), message) +end + +function buildGetResponseMessage(radio, context, frequency, callSign) + local message_template = '%s %s currently set to %s (%s)' + radio = radio:color(colors.secondary) + frequency = tostring(frequency):color(colors.primary) + return message_template:format(radio, context, frequency, callSign) +end + +function buildSetResponseMessage(radio, context, frequency, callSign) + local message_template = '%s %s updated to station %s (%s)' + radio = radio:color(colors.secondary) + frequency = tostring(frequency):color(colors.primary) + return message_template:format(radio, context, frequency, callSign) +end + +function displayResponse(response, color) + color = color or colors.info + windower.add_to_chat(color, response) + windower.console.write(response:strip_colors()) +end \ No newline at end of file diff --git a/addons/Bonanza/Bonanza.lua b/addons/Bonanza/Bonanza.lua new file mode 100644 index 0000000000..0508fea742 --- /dev/null +++ b/addons/Bonanza/Bonanza.lua @@ -0,0 +1,192 @@ +--[[ +Copyright © 2018, from20020516 +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 Bonanza 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 from20020516 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 = 'Bonanza' +_addon.author = 'from20020516' +_addon.version = '1.1' +_addon.command = 'bonanza' + +extdata = require('extdata') +packets = require('packets') +require('logger') + +marble = {id=2559,price=2000,limit=10} --general settings + +win_numbers = {} +math.randomseed(os.time()) + +--search your bags for bonanza marble and get number then add prefix 0 +function search_marbles() + local marbles = {} + local bags = {0,1,2,4,5,6,7,9} + local items = windower.ffxi.get_items + for bag_ind=1,#bags do + for index=1,windower.ffxi.get_bag_info(bags[bag_ind]).max do + local item = items(bags[bag_ind],index) + if item.id == marble.id then --bonanza marble + local five_digits = string.format('%05s',extdata.decode(item).number) + table.insert(marbles,{bags[bag_ind],index,five_digits}) + end + end + end + return marbles; +end + +windower.register_event('addon command',function(...) + moogle = windower.ffxi.get_mob_by_name('Bonanza Moogle') + decides = {} + local cmd={...} + local count = marble.limit-#search_marbles() + for i=1,#cmd do + math.random() --shuffle rand + cmd[i] = tonumber(cmd[i]) and cmd[i]*1 or cmd[i] + end + if not cmd[1] or cmd[1] == 'help' then + local chat = windower.add_to_chat + local color = string.color + chat(1,'Bonanza - Command List:') + chat(207,'//bonanza '..color(' [number] ...',166)) + chat(160,' purchase specified marble(s).') + chat(207,'//bonanza '..color('random',166)) + chat(160,' purchase up to 10 marbles with at random.') + chat(207,'//bonanza '..color('sequence ',166)) + chat(160,' purchase up to 10 marbles with consecutive number.') + chat(160,' e.g. '..color('15250',166)..' then buying '..color('15250',166)..' to '..color('15259',166)..'.') + chat(207,'//bonanza '..color('last ',166)) + chat(160,' purchase up to 10 random marbles with tail of specified 0-9.') + local zero = color('0',166) + chat(160,' e.g. '..zero..' then buying 2224'..zero..', 6231'..zero..', 4586'..zero..'...') + elseif cmd[1] == 'judge' then + windower.chat.input('/smes') + elseif count == 0 then + error('you have already '..marble.limit..' marbles.') + elseif cmd[1] == 'random' then + for i=1,count do + table.insert(decides,math.random(0,99)+math.random(0,99)*100+math.random(0,9)*10000) + end + elseif cmd[1] == 'sequence' then + local n = math.min(cmd[2],10000-count) + for i=n,n+count-1 do + table.insert(decides,i) + end + elseif cmd[1] == 'last' and 10 > cmd[2] then + for i=1,count do + table.insert(decides,tonumber(math.random(0,9999)..cmd[2])) + end + elseif 100000 > cmd[1] and not cmd[marble.limit+1] then + decides = cmd + end + + if #decides > 0 then + talk_moogle() + end +end) + +function talk_moogle() + if #decides > 0 then + hide_ui = true + local packet = packets.new('outgoing',0x01A,{ + ['Target']=moogle.id, + ['Target Index']=moogle.index}) + packets.inject(packet) + end +end + +windower.register_event('incoming chunk',function(id,data) + if S{0x020,0x034}[id] and hide_ui then + --got a marble. + local p = packets.parse('incoming',data) + if id == 0x020 and p['Item'] == marble.id and p['Bag'] == 0 then + local item = windower.ffxi.get_items(0,p['Index']) + if extdata.decode(item).number == decides[1] then + hide_ui = false + table.remove(decides,1) + talk_moogle() + end + --responced to talk. + elseif id == 0x034 and p['NPC'] == moogle.id then + if moogle.distance > 36 then + error('not close enough to Bonanza Moogle.') + elseif marble.price > windower.ffxi.get_items().gil then + error('not have enough gils.') + else + local packet = packets.new('outgoing',0x05B) + local i = decides[1] + log('Purchase a Bonanza Marble #'..string.format('%05s',i)) + --packet part 1 + packet['Target']=moogle.id + packet['Option Index']=2+i%256*256 + packet['Target Index']=moogle.index + packet['Automated Message']=true + packet['_unknown1']=(i-i%256)/256 + packet['Zone']=p['Zone'] + packet['Menu ID']=p['Menu ID'] + packets.inject(packet) + --packet part 2 + packet['Option Index']=3 + packet['Automated Message']=false + packets.inject(packet) + return true; --hide ui + end + end + end +end) + +--get winning numbers(str) from /smes. +windower.register_event('incoming text',function(original,modified,mode) + local jis = windower.from_shift_jis(original) --valid in english environment + if mode == 200 and windower.regex.match(jis,'digit|けた') then + local numbers = windower.regex.match(jis,'["「]([0-9]+)[」"]')[1][1] + table.insert(win_numbers,6-string.len(numbers),numbers) + if #win_numbers == 5 then + scan_marbles() + end + end +end) + +function scan_marbles() + log('Winning numbers is..',unpack(win_numbers)) + local marbles = search_marbles() + local colors = {51,18,166,207,208,161} + for m=1,#marbles do + local number = marbles[m][3] + if S{1,2,4,9}[marbles[m][1]] and windower.ffxi.get_info().mog_house + or S{5,6,7}[marbles[m][1]] then + windower.ffxi.get_item(marbles[m][1],marbles[m][2]) + end + for r=1,5 do + local text = _addon.name..': #'..string.format("%02s",m)..' '..number..' ') + break; + elseif r == 5 then + windower.add_to_chat(colors[6],text..'6'..'>') + end + end + end + win_numbers = {} +end diff --git a/addons/Bonanza/README.md b/addons/Bonanza/README.md new file mode 100644 index 0000000000..b4be251662 --- /dev/null +++ b/addons/Bonanza/README.md @@ -0,0 +1,27 @@ +# Bonanza + +- Judge your Bonanza Marbles. activate with when you recive system message (/smes) with winning numbers. +- Purchase Bonanza Marbles with any combination of numbers. + +#### Japanese + +- モグボナンザの当せんを判定。当せん番号を含むシステムメッセージ (/smes) を受信するとボナンザマーブルを鑑定し、結果を出力します。 +- 任意の数字の組み合わせでボナンザマーブルを購入します。 + +## Commands + +- //bonanza judge + - same as in-game /smes. + +### Purchase marble (inject packets) + +- //bonanza `` `[number]`... + - purchase specified marble(s). +- //bonanza random + - purchase up to 10 marbles with at random. +- //bonanza sequence `` + - purchase up to 10 marbles with consecutive number. + - e.g. `15250` then buying 15250 to 15259. +- //bonanza last `` + - purchase up to 10 random marbles with tail of specified `0-9`. + - e.g. `0` then 2224**0**, 6231**0**, 4586**0**, 9078**0**... diff --git a/addons/Clock/Clock.lua b/addons/Clock/Clock.lua index 9a66f68374..b3ae51540a 100644 --- a/addons/Clock/Clock.lua +++ b/addons/Clock/Clock.lua @@ -62,7 +62,15 @@ config.register(settings, redraw) clock:show() -utc_diff = os.difftime(os.time(), os.time(os.date('!*t', os.time()))) +local function get_timezone_offset(ts) + ts = ts or os.time() + local utcdate = os.date("!*t", ts) + local localdate = os.date("*t", ts) + localdate.isdst = false -- this is the trick + return os.difftime(os.time(localdate), os.time(utcdate)) +end + +utc_diff = get_timezone_offset() windower.register_event('prerender', function() local utc_now = os.time() - utc_diff diff --git a/addons/ConsoleBG/ConsoleBG.lua b/addons/ConsoleBG/ConsoleBG.lua index 3c7b886061..db6ed5c5a9 100644 --- a/addons/ConsoleBG/ConsoleBG.lua +++ b/addons/ConsoleBG/ConsoleBG.lua @@ -8,16 +8,16 @@ require('logger') defaults = {} defaults.bg = {} -defaults.bg.alpha = 255 +defaults.bg.alpha = 192 defaults.bg.red = 0 defaults.bg.green = 0 defaults.bg.blue = 0 defaults.pos = {} -defaults.pos.x = 1 -defaults.pos.y = 25 +defaults.pos.x = 0 +defaults.pos.y = 0 defaults.extents = {} -defaults.extents.x = 600 -defaults.extents.y = 314 +defaults.extents.x = 7680 +defaults.extents.y = 360 settings = config.load(defaults) @@ -76,11 +76,11 @@ windower.register_event('addon command', function(command1, ...) end elseif (command1 == 'Position' or command1 == 'Size') then if ((2 > argcount) or (argcount > 2)) then - error('Invalid syntax. Check the "help" command.') + error('Invalid syntax. Check the "help" command.') else consolesettings(command1, ...) end - + end elseif command1 == 'help' then @@ -94,7 +94,7 @@ windower.register_event('addon command', function(command1, ...) else error('Unknown command! Use the "help" command for a list of commands.') - + end end) diff --git a/addons/Debuffed/Debuffed.lua b/addons/Debuffed/Debuffed.lua new file mode 100644 index 0000000000..d3c177e599 --- /dev/null +++ b/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 \\cr - Allows you to change the refresh interval (default: 0.1)') + print(' \\cs(255,255,255)blacklist|whitelist add|remove \\cr - Adds or removes the spell to the specified list') + end +end) diff --git a/addons/Debuffed/README.md b/addons/Debuffed/README.md new file mode 100644 index 0000000000..ae986b15dc --- /dev/null +++ b/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 ` + +This allows you to adjust the refresh interval for the textbox. It will be updated every \ number of seconds. + +`//debuffed hide` + +This toggles the automatic removal of effects when their timer reaches zero. + +`//debuffed blacklist|whitelist add|remove ` + +This adds or removes the spell \ 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 `-` diff --git a/addons/Dimmer/Dimmer.lua b/addons/Dimmer/Dimmer.lua new file mode 100644 index 0000000000..7b9f814604 --- /dev/null +++ b/addons/Dimmer/Dimmer.lua @@ -0,0 +1,115 @@ +--[[ +Copyright © 2018, Chiaia +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 Dimmer 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.]] + +--Complete addon is almost a direct copy of MyHome from "from20020516" but for warping to a different area. + +_addon.name = 'Dimmer' +_addon.author = 'Chiaia' +_addon.version = '1.1.1' +_addon.commands = {'dim','dimmer'} + +require('logger') +extdata = require('extdata') +res_bags = require('resources').bags + +log_flag = true + +lang = string.lower(windower.ffxi.get_info().language) +item_info = { + [1]={id=26176,japanese='D.ホラリング',english='"Dim. Ring (Holla)"',slot=13}, + [2]={id=26177,japanese='D.デムリング',english='"Dim. Ring (Dem)"',slot=13}, + [3]={id=26178,japanese='D.メアリング',english='"Dim. Ring (Mea)"',slot=13}, + [4]={id=10385,japanese="キュムラスマスク+1",english="Cumulus Masque +1",slot=4}, +} + +function search_item() + if windower.ffxi.get_player().status > 1 then + log('You cannot use items at this time.') + return + end + + local item_array = {} + local get_items = windower.ffxi.get_items + local set_equip = windower.ffxi.set_equip + + for bag_id in pairs(res_bags:equippable(true)) do + local bag = get_items(bag_id) + for _,item in ipairs(bag) do + if item.id > 0 then + item_array[item.id] = item + item_array[item.id].bag = bag_id + item_array[item.id].bag_enabled = bag.enabled + end + end + end + for index,stats in pairs(item_info) do + local item = item_array[stats.id] + if item and item.bag_enabled then + local ext = extdata.decode(item) + local enchant = ext.type == 'Enchanted Equipment' + local recast = enchant and ext.charges_remaining > 0 and math.max(ext.next_use_time+18000-os.time(),0) + local usable = recast and recast == 0 + log(stats[lang],usable and '' or recast and recast..' sec recast.') + if usable or ext.type == 'General' then + if enchant and item.status ~= 5 then --not equipped + set_equip(item.slot,stats.slot,item.bag) + repeat --waiting cast delay + coroutine.sleep(1) + local ext = extdata.decode(get_items(item.bag,item.slot)) + local delay = ext.activation_time+18000-os.time() + if delay > 0 then + log(stats[lang],delay) + elseif log_flag then + log_flag = false + log('Item use within 3 seconds..') + end + until ext.usable or delay > 30 + end + windower.chat.input('/item '..windower.to_shift_jis(stats[lang])..' ') + break; + end + elseif item and not item.bag_enabled then + log('You cannot access '..stats[lang]..' from ' .. res_bags[item.bag].name ..' at this time.') + else + log('You don\'t have '..stats[lang]..'.') + end + end +end + +windower.register_event('addon command',function(...) + local args = T{...} + local cmd = args[1] + if cmd == 'all' then + windower.chat.input('//dimmer') + windower.send_ipc_message('dimmer') + else + search_item() + end +end) + +windower.register_event('ipc message',function (msg) + if msg == 'dimmer' then + windower.chat.input('//dimmer') + end +end) diff --git a/addons/Dimmer/README.md b/addons/Dimmer/README.md new file mode 100644 index 0000000000..ea808e7adc --- /dev/null +++ b/addons/Dimmer/README.md @@ -0,0 +1,14 @@ +# Dimmer +## English +- Automatically choose and uses the first Dimensional Ring on cool down to warp to Reisenjima for you. + +### Command +- `//dim` OR `//dimmer` +- `//dim all` OR `//dimmer all` will use ring on all characters. +- Priorities are: + 1. Dim. Ring (Holla) + 2. Dim. Ring (Dem) + 3. Dim. Ring (Mea) + +## 日本語 +- Should support the Japanesse client too. \ No newline at end of file diff --git a/addons/DressUp/DressUp.lua b/addons/DressUp/DressUp.lua index 5bc08530ae..adb3c06abf 100644 --- a/addons/DressUp/DressUp.lua +++ b/addons/DressUp/DressUp.lua @@ -1,4 +1,4 @@ --- Copyright © 2013-2015, Cairthenn +-- Copyright © 2013-2017, Cairthenn -- All rights reserved. -- Redistribution and use in source and binary forms, with or without @@ -25,21 +25,20 @@ -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'DressUp' -_addon.author = 'Cairthenn' -_addon.version = '1.1' +_addon.author = 'Cair' +_addon.version = '1.30' _addon.commands = {'DressUp','du'} ---Libs -require('luau') -packets = require('packets') - ---DressUp files - +packets = require('packets') +require('luau') require('helper_functions') require('static_variables') + models = {} +require('main') +require('sub') require('head') require('body') require('hands') @@ -47,12 +46,22 @@ require('legs') require('feet') settings = config.load(defaults) +info = T{ + names = T{}, + self = T{}, + party = S{} +} + +model_names = S{"Face","Race","Head","Body","Hands","Legs","Feet","Main","Sub","Ranged"} local initialize = function() local player = windower.ffxi.get_player() - _char = player.name:lower() - if not settings[_char] then - settings[_char] = {} + info.self.name = player.name:lower() + info.self.id = player.id + info.self.index = player.index + + if not settings[info.self.name] then + settings[info.self.name] = {} end print_blink_settings("global") @@ -60,7 +69,7 @@ local initialize = function() notice('Loaded profile: ' .. player.main_job) end - update_model(player.index) + update_model(info.self.index) end windower.register_event('load', function() @@ -72,23 +81,22 @@ end) windower.register_event('login', initialize) windower.register_event('logout', function() - _char = nil + info.self:clear() end) windower.register_event('job change',function(job) if load_profile(res.jobs[job].name) then - update_model(windower.ffxi.get_player().index) - notice('Loaded profile: ' .. job) + update_model(info.self.index) + notice('Loaded profile: ' .. res.jobs[job].name) end end) -model_names = S{"Face","Race","Head","Body","Hands","Legs","Feet","Main","Sub","Ranged"} local modify_gear = function(packet, name, freeze, models) local modified = false for k, v in pairs(packet) do - if model_names:contains(k) and v ~= 0 then + if model_names[k] then if rawget(settings, name) and settings[name][k:lower()] then -- Settings for individuals packet[k] = settings[name][k:lower()] @@ -109,65 +117,79 @@ local modify_gear = function(packet, name, freeze, models) end windower.register_event('incoming chunk',function (id, _, data) + if id ~= 0x00A and id ~= 0x00D and id ~= 0x051 then return end local packet = packets.parse('incoming', data) - local player = windower.ffxi.get_player() local modified -- Processing based on packet type if id == 0x00A then - if not _char then - return - end - modified,packet = modify_gear(packet, _char) + info.self.id = packet['Player'] + info.self.index = packet['Player Index'] + info.self.name = packet['Player Name']:lower() + modified,packet = modify_gear(packet, info.self.name) return modified and packets.build(packet) end - - -- Check whether the character is loaded into memory yet. - local character = windower.ffxi.get_mob_by_index(packet.Index or player and player.index or -1) -- Target of 0x00D or yourself for 0x051 - local blink_type, models, name = 'others' + + if id == 0x0D and not packet['Update Model'] then + return + end + + local char_id = packet.Player or info.self.id + local char_index = packet.Index or info.self.index + local character = windower.ffxi.get_mob_by_index(char_index or -1) + local blink_type, name = 'others' + local models + if character and character.models and table.length(character.models) == 9 and (id == 0x051 or (id == 0x00D and character.id == packet.Player) ) then - models = {Race=character.race, - Face = character.models[1], - Head=character.models[2]+0x1000, - Body=character.models[3]+0x2000, - Hands=character.models[4]+0x3000, - Legs=character.models[5]+0x4000, - Feet=character.models[6]+0x5000, - Main=character.models[7]+0x6000, - Sub=character.models[8]+0x7000, - Ranged=character.models[9]+0x8000} - else - return + models = T{ + Race = character.race, + Face = character.models[1], + Head = character.models[2]+0x1000, + Body = character.models[3]+0x2000, + Hands = character.models[4]+0x3000, + Legs = character.models[5]+0x4000, + Feet = character.models[6]+0x5000, + Main = character.models[7]+0x6000, + Sub = character.models[8]+0x7000, + Ranged = character.models[9]+0x8000} end - - if character then - if player.follow_index == character.index then - blink_type = "follow" - elseif character.in_alliance then - blink_type = "party" - else - blink_type = "others" - end - if character.name == player.name then - name = _char - blink_type = "self" - elseif settings[character.name:lower()] then - name = character.name:lower() + if not info.names[char_id] then + if packet['Update Name'] then + info.names[char_id] = packet['Character Name']:lower() + elseif character then + info.names[char_id] = character.name:lower() else - name = "others" + return end + end + + local player = windower.ffxi.get_player() + + if player.follow_index == char_index then + blink_type = "follow" + elseif character and character.in_alliance then + blink_type = "party" + else + blink_type = "others" + end + + if info.names[char_id] == info.self.name then + name = info.self.name + blink_type = "self" + elseif settings[info.names[char_id]] then + name = info.names[char_id] else name = "others" end -- Model ID 0xFFFF in ranged slot signifies a monster. This prevents undesired results. - modified,packet = modify_gear(packet, name or _char, blink_logic(blink_type, character, player), models) + modified,packet = modify_gear(packet, name, blink_logic(blink_type, char_index, player), models) return packet['Ranged'] ~= 0xFFFF and modified and packets.build(packet) end) @@ -224,7 +246,7 @@ windower.register_event('addon command', function (command,...) if command == "player" then command = args:remove(1) elseif command == "self" then - command = _char + command = info.self.name end if not settings[command] then @@ -344,7 +366,7 @@ windower.register_event('addon command', function (command,...) if _clear == "player" then _clear = args:remove(1) elseif _clear == "self" then - _clear = _char + _clear = info.self.name end local _selection = S{"head","body","hands","legs","feet","main","sub","ranged","race","face"}:contains(args[1]) and args:remove(1) @@ -453,7 +475,7 @@ windower.register_event('addon command', function (command,...) return end end - if settings.autoupdate and ((command == _char) or (_clear == _char)) then + if settings.autoupdate and ((command == info.self.name) or (_clear == info.self.name)) then update_model(windower.ffxi.get_player().index) end diff --git a/addons/DressUp/body.lua b/addons/DressUp/body.lua index d91a3c7c02..d0c414c774 100644 --- a/addons/DressUp/body.lua +++ b/addons/DressUp/body.lua @@ -1013,6 +1013,8 @@ models.body[27924] = { name = "Thurandaut Tabard" , enl = "thurandaut tabard", m models.body[27925] = { name = "Karieyh Haubert" , enl = "karieyh haubert", model = 8534} models.body[27926] = { name = "Geomancy Tunic" , enl = "geomancy tunic", model = 8500} --8508 Taru M models.body[27927] = { name = "Runeist Coat" , enl = "runeist coat", model = 8530} +models.body[27854] = { name = "Mandra. Suit" , enl = "mandragora suit", model = 8568} + models.body[50000] = { name = "Volunteer Solider Body" , model = 8365 } models.body[50001] = { name = "Chasuble (Male Only)", model = 8369 } diff --git a/addons/DressUp/head.lua b/addons/DressUp/head.lua index 385e86f846..255bfa9edc 100644 --- a/addons/DressUp/head.lua +++ b/addons/DressUp/head.lua @@ -962,6 +962,7 @@ models.head[27784] = { name = "Thurandaut Chapeau" , enl = "thurandaut chapeau", models.head[27785] = { name = "Karieyh Morion" , enl = "karieyh morion", model = 4438} models.head[27786] = { name = "Geomancy Galero" , enl = "geomancy galero", model = 4404} models.head[27787] = { name = "Runeist Bandeau" , enl = "runeist bandeau", model = 4434} +models.head[26705] = { name = "Mandra. Masque" , enl = "mandra masque", model = 4472} models.head[40001] = { name = "??? Chapeau" , model = 4257 } models.head[40002] = { name = "Haudrale's Chapeau" , model = 4338 } diff --git a/addons/DressUp/helper_functions.lua b/addons/DressUp/helper_functions.lua index 866283454b..7d84543285 100644 --- a/addons/DressUp/helper_functions.lua +++ b/addons/DressUp/helper_functions.lua @@ -71,7 +71,7 @@ function save_profile(name) notice('Saved your current settings to the profile: ' .. name) end -function blink_logic(blink_type,character,player) +function blink_logic(blink_type,character_index,player) if settings.blinking["all"]["always"] then return true elseif settings.blinking[blink_type]["always"] then @@ -83,10 +83,10 @@ function blink_logic(blink_type,character,player) elseif settings.blinking[blink_type]["combat"] and player.in_combat then return true end - - if settings.blinking["all"]["target"] and player.target_index == character.index then + + if settings.blinking["all"]["target"] and player.target_index == character_index then return true - elseif settings.blinking[blink_type]["target"] and player.target_index == character.index then + elseif settings.blinking[blink_type]["target"] and player.target_index == character_index then return true end diff --git a/addons/DressUp/main.lua b/addons/DressUp/main.lua new file mode 100644 index 0000000000..bce4aaf016 --- /dev/null +++ b/addons/DressUp/main.lua @@ -0,0 +1,3630 @@ +-- Copyright © 2013-2022, Cairthenn +-- 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 DressUp 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 Cairthenn 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. + + +models.main = {} + +models.main["None"] = { name = "empty" , model = 24576 } + +models.main[16385] = { name = "Cesti" , model = 24702} +models.main[16386] = { name = "Lizard Cesti" , model = 24703} +models.main[16387] = { name = "Poison Cesti" , model = 24704} +models.main[16388] = { name = "Himantes" , model = 24703} +models.main[16389] = { name = "Coeurl Cesti" , model = 24702} +models.main[16390] = { name = "Bronze Knuckles" , model = 24706} +models.main[16391] = { name = "Brass Knuckles" , model = 24707} +models.main[16392] = { name = "Metal Knuckles" , model = 24708} +models.main[16393] = { name = "Mythril Knuckles" , model = 24709} +models.main[16394] = { name = "Dst. Knuckles" , model = 24705} +models.main[16395] = { name = "Diamond Knuckles" , model = 24711} +models.main[16396] = { name = "Koenigs Knuckles" , model = 24710} +models.main[16397] = { name = "Behemoth Cesti" , model = 24704} +models.main[16398] = { name = "Burning Cesti" , model = 24703} +models.main[16399] = { name = "Katars" , model = 24695} +models.main[16400] = { name = "Darksteel Katars" , model = 24694} +models.main[16401] = { name = "Jamadhars" , model = 24696} +models.main[16403] = { name = "Poison Katars" , model = 24695} +models.main[16404] = { name = "Venom Katars" , model = 24694} +models.main[16405] = { name = "Cat Baghnakhs" , model = 24716} +models.main[16406] = { name = "Baghnakhs" , model = 24718} +models.main[16407] = { name = "Brass Baghnakhs" , model = 24717} +models.main[16408] = { name = "Rune Baghnakhs" , model = 24719} +models.main[16409] = { name = "Lynx Baghnakhs" , model = 24716} +models.main[16410] = { name = "Psn. Baghnakhs" , model = 24718} +models.main[16411] = { name = "Claws" , model = 24699} +models.main[16412] = { name = "Mythril Claws" , model = 24700} +models.main[16413] = { name = "Darksteel Claws" , model = 24698} +models.main[16414] = { name = "Cermet Claws" , model = 24701} +models.main[16416] = { name = "Dragon Claws" , model = 24701} +models.main[16417] = { name = "Poison Claws" , model = 24699} +models.main[16418] = { name = "Venom Claws" , model = 24698} +models.main[16419] = { name = "Patas" , model = 24714} +models.main[16420] = { name = "Bone Patas" , model = 24715} +models.main[16421] = { name = "Gold Patas" , model = 24713} +models.main[16422] = { name = "Tigerfangs" , model = 24715} +models.main[16423] = { name = "Manoples" , model = 24712} +models.main[16425] = { name = "Venom Claws +1" , model = 24698} +models.main[16426] = { name = "Avengers" , model = 24693} +models.main[16427] = { name = "Lunaris Claws" , model = 24693} +models.main[16428] = { name = "Afflictors" , model = 25075} +models.main[16429] = { name = "Slc. Baghnakhs" , model = 24717} +models.main[16430] = { name = "Acid Claws" , model = 24700} +models.main[16431] = { name = "Stun Claws" , model = 24701} +models.main[16432] = { name = "Stun Jamadhars" , model = 24696} +models.main[16433] = { name = "Lgn. Knuckles" , model = 24707} +models.main[16434] = { name = "Sonic Knuckles" , model = 24705} +models.main[16437] = { name = "Metal Knuckles +1" , model = 24708} +models.main[16438] = { name = "Slc. Baghnakhs +1" , model = 24717} +models.main[16439] = { name = "Poison Claws +1" , model = 24699} +models.main[16440] = { name = "Brz. Knuckles +1" , model = 24706} +models.main[16441] = { name = "Brs. Baghnakhs +1" , model = 24717} +models.main[16442] = { name = "Fsd. Baghnakhs" , model = 24716} +models.main[16443] = { name = "Fruit Punches" , model = 24702} +models.main[16444] = { name = "Baghnakhs +1" , model = 24718} +models.main[16445] = { name = "Claws +1" , model = 24699} +models.main[16446] = { name = "Mtl. Knuckles +1" , model = 24709} +models.main[16447] = { name = "Rusty Dagger" , model = 24740} +models.main[16448] = { name = "Bronze Dagger" , model = 24740} +models.main[16449] = { name = "Brass Dagger" , model = 24741} +models.main[16450] = { name = "Dagger" , model = 24742} +models.main[16451] = { name = "Mythril Dagger" , model = 24743} +models.main[16452] = { name = "Misericorde" , model = 24739} +models.main[16453] = { name = "Orichalcum Dagger" , model = 24755} +models.main[16454] = { name = "Blind Dagger" , model = 24740} +models.main[16455] = { name = "Baselard" , model = 24745} +models.main[16456] = { name = "Mythril Baselard" , model = 24746} +models.main[16457] = { name = "Dst. Baselard" , model = 24744} +models.main[16458] = { name = "Poison Baselard" , model = 24745} +models.main[16459] = { name = "Acid Baselard" , model = 24746} +models.main[16460] = { name = "Kris" , model = 24754} +models.main[16461] = { name = "Adaman Kris" , model = 24753} +models.main[16463] = { name = "Cmb.Cst. Dagger" , model = 24753} +models.main[16465] = { name = "Bronze Knife" , model = 24735} +models.main[16466] = { name = "Knife" , model = 24736} +models.main[16467] = { name = "Mythril Knife" , model = 24737} +models.main[16468] = { name = "Darksteel Knife" , model = 24734} +models.main[16469] = { name = "Cermet Knife" , model = 24738} +models.main[16470] = { name = "Gully" , model = 24733} +models.main[16471] = { name = "Blind Knife" , model = 24735} +models.main[16472] = { name = "Poison Knife" , model = 24736} +models.main[16473] = { name = "Kukri" , model = 24748} +models.main[16475] = { name = "Mythril Kukri" , model = 24749} +models.main[16476] = { name = "Darksteel Kukri" , model = 24747} +models.main[16477] = { name = "Cermet Kukri" , model = 24750} +models.main[16478] = { name = "Poison Kukri" , model = 24748} +models.main[16479] = { name = "Acid Kukri" , model = 24749} +models.main[16480] = { name = "Thief's Knife" , model = 24752} +models.main[16481] = { name = "Yataghan +1" , model = 24974} +models.main[16482] = { name = "Onion Dagger" , model = 24740} +models.main[16483] = { name = "Onion Knife" , model = 24735} +models.main[16484] = { name = "Burglar's Dagger" , model = 24742} +models.main[16485] = { name = "Yataghan" , model = 24974} +models.main[16486] = { name = "Beestinger" , model = 24743} +models.main[16487] = { name = "Minstrel's Dagger" , model = 24740} +models.main[16488] = { name = "Nguul" , model = 24733} +models.main[16489] = { name = "Poison Kukri +1" , model = 24748} +models.main[16490] = { name = "Blind Knife +1" , model = 24735} +models.main[16491] = { name = "Bronze Knife +1" , model = 24735} +models.main[16492] = { name = "Bronze Dagger +1" , model = 24740} +models.main[16493] = { name = "Blind Dagger +1" , model = 24740} +models.main[16494] = { name = "Corrosive Kukri" , model = 24749} +models.main[16495] = { name = "Silence Dagger" , model = 24741} +models.main[16496] = { name = "Poison Dagger" , model = 24742} +models.main[16497] = { name = "Sleep Dagger" , model = 24743} +models.main[16498] = { name = "Carabineer Dagger" , model = 24755} +models.main[16499] = { name = "Venom Kris" , model = 24754} +models.main[16500] = { name = "Aluh Jambiya" , model = 24985} +models.main[16501] = { name = "Acid Knife" , model = 24737} +models.main[16502] = { name = "Venom Knife" , model = 24734} +models.main[16503] = { name = "Stun Knife" , model = 24738} +models.main[16504] = { name = "Oynos Knife" , model = 24738} +models.main[16505] = { name = "Venom Kukri" , model = 24747} +models.main[16506] = { name = "Stun Kukri" , model = 24750} +models.main[16507] = { name = "Venom Baselard" , model = 24744} +models.main[16508] = { name = "Silence Dagger +1" , model = 24741} +models.main[16509] = { name = "Aspir Knife" , model = 24735} +models.main[16510] = { name = "Vnm. Baselard +1" , model = 24744} +models.main[16511] = { name = "Burnite Shell" , model = 24756} +models.main[16512] = { name = "Bilbo" , model = 24759} +models.main[16513] = { name = "Tuck" , model = 24760} +models.main[16514] = { name = "Mailbreaker" , model = 24763} +models.main[16515] = { name = "Colichemarde" , model = 24757} +models.main[16516] = { name = "Jr.Msk. Tuck" , model = 24760} +models.main[16517] = { name = "Degen" , model = 24764} +models.main[16518] = { name = "Mythril Degen" , model = 24765} +models.main[16519] = { name = "Schlaeger" , model = 24762} +models.main[16520] = { name = "Verdun" , model = 24761} +models.main[16521] = { name = "Rapier" , model = 24763} +models.main[16522] = { name = "Flame Degen" , model = 24764} +models.main[16523] = { name = "Holy Degen" , model = 24765} +models.main[16524] = { name = "Fleuret" , model = 24767} +models.main[16525] = { name = "Hornet Fleuret" , model = 24769} +models.main[16526] = { name = "Schwert" , model = 24768} +models.main[16527] = { name = "Epee" , model = 24766} +models.main[16528] = { name = "Bloody Rapier" , model = 24764} +models.main[16529] = { name = "Musketeer's Sword" , model = 24764} +models.main[16530] = { name = "Xiphos" , model = 24840} +models.main[16531] = { name = "Brass Xiphos" , model = 24841} +models.main[16532] = { name = "Gladius" , model = 24842} +models.main[16533] = { name = "Ancient Sword" , model = 24859} +models.main[16534] = { name = "Onion Sword" , model = 24841} +models.main[16535] = { name = "Bronze Sword" , model = 24844} +models.main[16536] = { name = "Iron Sword" , model = 24846} +models.main[16537] = { name = "Mythril Sword" , model = 24847} +models.main[16538] = { name = "Darksteel Sword" , model = 24843} +models.main[16539] = { name = "Cermet Sword" , model = 24849} +models.main[16540] = { name = "Tyrfing" , model = 25094} +models.main[16541] = { name = "Jagdplaute" , model = 24845} +models.main[16542] = { name = "Wing Sword" , model = 24864} +models.main[16543] = { name = "Fire Sword" , model = 24844} +models.main[16544] = { name = "Ryl.Arc. Sword" , model = 24827} +models.main[16545] = { name = "Broadsword" , model = 24852} +models.main[16546] = { name = "Katzbalger" , model = 24851} +models.main[16547] = { name = "Anelace" , model = 24850} +models.main[16548] = { name = "Coral Sword" , model = 24853} +models.main[16549] = { name = "Divine Sword" , model = 24852} +models.main[16550] = { name = "Hallowed Sword" , model = 24852} +models.main[16551] = { name = "Sapara" , model = 24831} +models.main[16552] = { name = "Scimitar" , model = 24832} +models.main[16553] = { name = "Tulwar" , model = 24833} +models.main[16554] = { name = "Hanger" , model = 24834} +models.main[16555] = { name = "Ridill" , model = 24835} +models.main[16556] = { name = "Bloody Blade" , model = 24838} +models.main[16557] = { name = "Msk.Cmd. Falchion" , model = 24838} +models.main[16558] = { name = "Falchion" , model = 24838} +models.main[16559] = { name = "Darksteel Falchion" , model = 24836} +models.main[16560] = { name = "Cutlass" , model = 24839} +models.main[16562] = { name = "Platinum Cutlass" , model = 24837} +models.main[16563] = { name = "Rune Blade" , model = 24830} +models.main[16564] = { name = "Flame Blade" , model = 24838} +models.main[16565] = { name = "Spatha" , model = 24825} +models.main[16566] = { name = "Longsword" , model = 24827} +models.main[16567] = { name = "Knight's Sword" , model = 24828} +models.main[16568] = { name = "Saber" , model = 24829} +models.main[16569] = { name = "Gold Sword" , model = 24826} +models.main[16571] = { name = "T.K. Army Sword" , model = 24827} +models.main[16572] = { name = "Bee Spatha" , model = 24825} +models.main[16575] = { name = "Curtana" , model = 24845} +models.main[16576] = { name = "Hunting Sword" , model = 24856} +models.main[16577] = { name = "Bastard Sword" , model = 24855} +models.main[16578] = { name = "Espadon" , model = 24857} +models.main[16579] = { name = "Kaskara" , model = 24854} +models.main[16580] = { name = "Bloodsword" , model = 24863} +models.main[16581] = { name = "Holy Sword" , model = 24862} +models.main[16582] = { name = "Vetala Sword" , model = 24864} +models.main[16583] = { name = "Claymore" , model = 24642} +models.main[16584] = { name = "Mythril Claymore" , model = 24643} +models.main[16585] = { name = "Dst. Claymore" , model = 24641} +models.main[16586] = { name = "Adaman Claymore" , model = 24640} +models.main[16587] = { name = "Gold Algol" , model = 24962} +models.main[16588] = { name = "Flame Claymore" , model = 24642} +models.main[16589] = { name = "Two-Hand. Sword" , model = 24647} +models.main[16590] = { name = "Greatsword" , model = 24648} +models.main[16591] = { name = "Zweihander" , model = 24646} +models.main[16592] = { name = "Gigant Sword" , model = 24645} +models.main[16593] = { name = "Plain Sword" , model = 24647} +models.main[16594] = { name = "Inferno Sword" , model = 24647} +models.main[16595] = { name = "Ram-Dao" , model = 24651} +models.main[16596] = { name = "Flamberge" , model = 24650} +models.main[16597] = { name = "Nagan" , model = 24649} +models.main[16598] = { name = "Gold Algol +1" , model = 24962} +models.main[16599] = { name = "Ryl.Grd. Sword" , model = 24649} +models.main[16600] = { name = "Wax Sword" , model = 24844} +models.main[16601] = { name = "Ryl.Swd. Blade" , model = 24648} +models.main[16602] = { name = "Perdu Sword" , model = 24646} +models.main[16603] = { name = "Halo Claymore" , model = 24642} +models.main[16604] = { name = "Save the Queen" , model = 24828} +models.main[16605] = { name = "Enhancing Sword" , model = 24826} +models.main[16606] = { name = "Rusty Greatsword" , model = 24648} +models.main[16607] = { name = "Chaosbringer" , model = 24641} +models.main[16608] = { name = "Gladiator" , model = 24842} +models.main[16609] = { name = "Bloody Sword" , model = 24843} +models.main[16610] = { name = "Wax Sword +1" , model = 24844} +models.main[16611] = { name = "Bee Spatha +1" , model = 24825} +models.main[16612] = { name = "Saber +1" , model = 24829} +models.main[16613] = { name = "Spirit Sword" , model = 24862} +models.main[16614] = { name = "Knife +1" , model = 24736} +models.main[16615] = { name = "Falchion +1" , model = 24838} +models.main[16616] = { name = "Zweihander +1" , model = 24646} +models.main[16617] = { name = "Tuck +1" , model = 24760} +models.main[16618] = { name = "Mailbreaker +1" , model = 24763} +models.main[16619] = { name = "Epee +1" , model = 24766} +models.main[16620] = { name = "Merman's Sword" , model = 24853} +models.main[16621] = { name = "Flame Sword" , model = 24844} +models.main[16622] = { name = "Judge's Sword" , model = 24884} +models.main[16623] = { name = "Bronze Sword +1" , model = 24844} +models.main[16624] = { name = "Xiphos +1" , model = 24840} +models.main[16625] = { name = "Scimitar +1" , model = 24832} +models.main[16626] = { name = "Iron Sword +1" , model = 24846} +models.main[16627] = { name = "Spatha +1" , model = 24825} +models.main[16628] = { name = "Longsword +1" , model = 24827} +models.main[16629] = { name = "Small Sword" , model = 24758} +models.main[16630] = { name = "Striker Sword" , model = 24859} +models.main[16631] = { name = "Kaiser Sword" , model = 24860} +models.main[16632] = { name = "Bilbo +1" , model = 24759} +models.main[16633] = { name = "Degen +1" , model = 24764} +models.main[16634] = { name = "Broadsword +1" , model = 24852} +models.main[16635] = { name = "Mythril Sword +1" , model = 24847} +models.main[16636] = { name = "Tulwar +1" , model = 24833} +models.main[16637] = { name = "Deathbringer" , model = 24641} +models.main[16638] = { name = "Claymore +1" , model = 24642} +models.main[16639] = { name = "Fine Claymore" , model = 24643} +models.main[16640] = { name = "Bronze Axe" , model = 24652} +models.main[16641] = { name = "Brass Axe" , model = 24653} +models.main[16642] = { name = "Bone Axe" , model = 24656} +models.main[16643] = { name = "Battleaxe" , model = 24654} +models.main[16644] = { name = "Mythril Axe" , model = 24655} +models.main[16645] = { name = "Darksteel Axe" , model = 24660} +models.main[16646] = { name = "Bronze Axe +1" , model = 24652} +models.main[16647] = { name = "Rune Axe" , model = 24661} +models.main[16648] = { name = "Legionnaire's Axe" , model = 24654} +models.main[16649] = { name = "Bone Pick" , model = 24666} +models.main[16650] = { name = "War Pick" , model = 24664} +models.main[16651] = { name = "Mythril Pick" , model = 24665} +models.main[16652] = { name = "Darksteel Pick" , model = 24663} +models.main[16653] = { name = "Nadziak" , model = 24662} +models.main[16654] = { name = "Glyph Axe" , model = 25095} +models.main[16655] = { name = "Rusty Pick" , model = 24664} +models.main[16656] = { name = "Orcish Axe" , model = 24667} +models.main[16657] = { name = "Tabar" , model = 24659} +models.main[16658] = { name = "Darksteel Tabar" , model = 24658} +models.main[16659] = { name = "Tabarzin" , model = 24657} +models.main[16660] = { name = "Doom Tabar" , model = 24657} +models.main[16661] = { name = "Brass Axe +1" , model = 24653} +models.main[16662] = { name = "Doom Tabar +1" , model = 24657} +models.main[16663] = { name = "Battleaxe +1" , model = 24654} +models.main[16664] = { name = "War Pick +1" , model = 24664} +models.main[16665] = { name = "Mythril Axe +1" , model = 24655} +models.main[16666] = { name = "Bone Axe +1" , model = 24656} +models.main[16667] = { name = "Light Axe" , model = 24654} +models.main[16668] = { name = "Bone Pick +1" , model = 24666} +models.main[16669] = { name = "Cmb.Cst. Axe" , model = 24659} +models.main[16670] = { name = "Mythril Pick +1" , model = 24665} +models.main[16671] = { name = "Tabar +1" , model = 24659} +models.main[16672] = { name = "Tigerhunter" , model = 24656} +models.main[16673] = { name = "Warrior's Axe" , model = 24654} +models.main[16674] = { name = "Emeth Pick" , model = 24665} +models.main[16675] = { name = "Storm Axe" , model = 24655} +models.main[16676] = { name = "Viking Axe" , model = 24660} +models.main[16677] = { name = "Darksteel Axe +1" , model = 24660} +models.main[16678] = { name = "Razor Axe" , model = 24654} +models.main[16679] = { name = "Wrath Tabar" , model = 24658} +models.main[16680] = { name = "Barbaroi Axe" , model = 24667} +models.main[16681] = { name = "Gerwitz's Axe" , model = 24659} +models.main[16682] = { name = "Darksteel Pick +1" , model = 24663} +models.main[16683] = { name = "Dst. Tabar +1" , model = 24658} +models.main[16684] = { name = "Kabrakan's Axe" , model = 24667} +models.main[16685] = { name = "Nadziak +1" , model = 24662} +models.main[16686] = { name = "Arcanabane" , model = 24666} +models.main[16687] = { name = "Platoon Axe" , model = 24653} +models.main[16688] = { name = "Mythril Claws +1" , model = 24700} +models.main[16689] = { name = "Brass Knuckles +1" , model = 24707} +models.main[16690] = { name = "Cesti +1" , model = 24702} +models.main[16691] = { name = "Ryl.Arc. Cesti" , model = 24702} +models.main[16692] = { name = "Psn. Baghnakhs +1" , model = 24718} +models.main[16693] = { name = "Poison Katars +1" , model = 24695} +models.main[16694] = { name = "Tct.Mag. Hooks" , model = 24715} +models.main[16695] = { name = "Katars +1" , model = 24695} +models.main[16696] = { name = "Patas +1" , model = 24714} +models.main[16697] = { name = "Dst. Claws +1" , model = 24698} +models.main[16698] = { name = "Dst. Knuckles +1" , model = 24705} +models.main[16699] = { name = "Himantes +1" , model = 24703} +models.main[16700] = { name = "Poison Cesti +1" , model = 24704} +models.main[16701] = { name = "Strike Baghnakhs" , model = 24716} +models.main[16702] = { name = "Cougar Baghnakhs" , model = 24717} +models.main[16703] = { name = "Impact Knuckles" , model = 24706} +models.main[16704] = { name = "Butterfly Axe" , model = 24670} +models.main[16705] = { name = "Greataxe" , model = 24671} +models.main[16706] = { name = "Heavy Axe" , model = 24669} +models.main[16707] = { name = "Bhuj" , model = 24672} +models.main[16708] = { name = "Horror Voulge" , model = 24941} +models.main[16709] = { name = "Inferno Axe" , model = 24670} +models.main[16710] = { name = "Gigant Axe" , model = 24674} +models.main[16711] = { name = "Demon's Axe" , model = 24673} +models.main[16712] = { name = "Centurion's Axe" , model = 24668} +models.main[16713] = { name = "Hellfire Axe" , model = 24669} +models.main[16714] = { name = "Neckchopper" , model = 24671} +models.main[16716] = { name = "Butterfly Axe +1" , model = 24670} +models.main[16717] = { name = "Greataxe +1" , model = 24671} +models.main[16718] = { name = "Heavy Axe +1" , model = 24669} +models.main[16719] = { name = "Moth Axe" , model = 24670} +models.main[16720] = { name = "Plantbane" , model = 24669} +models.main[16721] = { name = "Huge Moth Axe" , model = 24671} +models.main[16722] = { name = "Heavy Moth Axe" , model = 24670} +models.main[16723] = { name = "Executioner" , model = 24669} +models.main[16724] = { name = "Heavy Dst. Axe" , model = 24669} +models.main[16725] = { name = "Massive Dst. Axe" , model = 24668} +models.main[16726] = { name = "Forseti's Axe" , model = 24673} +models.main[16727] = { name = "Eisentaenzer" , model = 24673} +models.main[16728] = { name = "Schwarz Axt" , model = 24669} +models.main[16729] = { name = "Berserker's Axe" , model = 24669} +models.main[16730] = { name = "Colossal Axe" , model = 24674} +models.main[16731] = { name = "Colossal Axe +1" , model = 24674} +models.main[16732] = { name = "Bas. Greataxe" , model = 24668} +models.main[16733] = { name = "Republic Greataxe" , model = 24668} +models.main[16734] = { name = "Pendragon Axe" , model = 24672} +models.main[16735] = { name = "Axe of Trials" , model = 24670} +models.main[16736] = { name = "Dagger +1" , model = 24742} +models.main[16737] = { name = "Baselard +1" , model = 24745} +models.main[16738] = { name = "Mythril Dagger +1" , model = 24743} +models.main[16739] = { name = "Mythril Knife +1" , model = 24737} +models.main[16740] = { name = "Brass Dagger +1" , model = 24741} +models.main[16741] = { name = "Poison Dagger +1" , model = 24742} +models.main[16742] = { name = "Poison Knife +1" , model = 24736} +models.main[16743] = { name = "Python Baselard" , model = 24745} +models.main[16744] = { name = "Ryl.Sqr. Dagger" , model = 24746} +models.main[16745] = { name = "Decurion's Dagger" , model = 24743} +models.main[16746] = { name = "Mercenary's Knife" , model = 24736} +models.main[16747] = { name = "Mrc.Cpt. Kukri" , model = 24748} +models.main[16748] = { name = "Kukri +1" , model = 24748} +models.main[16749] = { name = "Kris +1" , model = 24754} +models.main[16750] = { name = "Mythril Kukri +1" , model = 24749} +models.main[16751] = { name = "Dst. Knife +1" , model = 24734} +models.main[16752] = { name = "Fine Baselard" , model = 24743} +models.main[16753] = { name = "Ceremonial Dagger" , model = 24740} +models.main[16754] = { name = "Parrying Knife" , model = 24752} +models.main[16755] = { name = "Archer's Knife" , model = 24737} +models.main[16756] = { name = "Leste Jambiya" , model = 24955} +models.main[16757] = { name = "Corsair's Knife" , model = 24747} +models.main[16758] = { name = "Dst. Baselard +1" , model = 24744} +models.main[16759] = { name = "Darksteel Kris" , model = 24754} +models.main[16760] = { name = "Darksteel Kris +1" , model = 24754} +models.main[16761] = { name = "Venom Kris +1" , model = 24754} +models.main[16762] = { name = "Venom Knife +1" , model = 24734} +models.main[16763] = { name = "Darksteel Kukri +1" , model = 24747} +models.main[16764] = { name = "Marauder's Knife" , model = 24736} +models.main[16765] = { name = "Lust Dagger" , model = 24741} +models.main[16766] = { name = "Paper Knife" , model = 24735} +models.main[16767] = { name = "Triple Dagger" , model = 24755} +models.main[16768] = { name = "Bronze Zaghnal" , model = 24773} +models.main[16769] = { name = "Brass Zaghnal" , model = 24774} +models.main[16770] = { name = "Zaghnal" , model = 24775} +models.main[16771] = { name = "Falcastra" , model = 24776} +models.main[16772] = { name = "Brass Zaghnal +1" , model = 24774} +models.main[16773] = { name = "Cruel Scythe" , model = 24771} +models.main[16774] = { name = "Scythe" , model = 24771} +models.main[16775] = { name = "Mythril Scythe" , model = 24772} +models.main[16776] = { name = "Mrc.Cpt. Scythe" , model = 24770} +models.main[16777] = { name = "Death Scythe" , model = 24777} +models.main[16778] = { name = "Brz. Zaghnal +1" , model = 24773} +models.main[16779] = { name = "Zaghnal +1" , model = 24775} +models.main[16780] = { name = "Lgn. Scythe" , model = 24774} +models.main[16781] = { name = "Scythe +1" , model = 24771} +models.main[16782] = { name = "Mythril Scythe +1" , model = 24772} +models.main[16783] = { name = "Plantreaper" , model = 24773} +models.main[16784] = { name = "Frostreaper" , model = 24774} +models.main[16785] = { name = "Harvester" , model = 24775} +models.main[16786] = { name = "Brb. Scythe" , model = 24772} +models.main[16787] = { name = "Demonslicer" , model = 24777} +models.main[16788] = { name = "Vassago's Scythe" , model = 24777} +models.main[16789] = { name = "Darksteel Scythe" , model = 24770} +models.main[16790] = { name = "Dst. Scythe +1" , model = 24770} +models.main[16791] = { name = "Death Scythe +1" , model = 24777} +models.main[16792] = { name = "Goshisho's Scythe" , model = 24773} +models.main[16793] = { name = "Scythe of Trials" , model = 24771} +models.main[16794] = { name = "Bone Scythe" , model = 24898} +models.main[16795] = { name = "Bone Scythe +1" , model = 24898} +models.main[16796] = { name = "Mythril Zaghnal" , model = 24776} +models.main[16797] = { name = "Mythril Zaghnal +1" , model = 24776} +models.main[16798] = { name = "Raven Scythe" , model = 24770} +models.main[16799] = { name = "Snr.Msk. Scythe" , model = 24921} +models.main[16800] = { name = "Knight's Sword +1" , model = 24828} +models.main[16801] = { name = "Sapara +1" , model = 24831} +models.main[16802] = { name = "Brass Xiphos +1" , model = 24841} +models.main[16803] = { name = "Fleuret +1" , model = 24767} +models.main[16804] = { name = "Flame Blade +1" , model = 24838} +models.main[16805] = { name = "Ryl.Grd. Fleuret" , model = 24769} +models.main[16806] = { name = "Centurion's Sword" , model = 24847} +models.main[16807] = { name = "Cmb.Cst. Scimitar" , model = 24833} +models.main[16808] = { name = "Wis.Wiz. Bilbo" , model = 24758} +models.main[16809] = { name = "Wis.Wiz. Anelace" , model = 24850} +models.main[16810] = { name = "Tct.Mag. Espadon" , model = 24856} +models.main[16811] = { name = "Dst. Sword +1" , model = 24843} +models.main[16812] = { name = "War Sword" , model = 24856} +models.main[16813] = { name = "Schlaeger +1" , model = 24762} +models.main[16814] = { name = "Crescent Sword" , model = 24836} +models.main[16815] = { name = "Mythril Degen +1" , model = 24765} +models.main[16816] = { name = "Holy Sword +1" , model = 24862} +models.main[16817] = { name = "Holy Degen +1" , model = 24765} +models.main[16818] = { name = "San d'Orian Sword" , model = 24827} +models.main[16819] = { name = "Mithran Scimitar" , model = 24832} +models.main[16820] = { name = "Strider Sword" , model = 24846} +models.main[16821] = { name = "Duel Rapier" , model = 24763} +models.main[16822] = { name = "Crimson Blade" , model = 24844} +models.main[16823] = { name = "Flame Degen +1" , model = 24764} +models.main[16824] = { name = "Carnage Rapier" , model = 24764} +models.main[16825] = { name = "Cermet Sword +1" , model = 24849} +models.main[16826] = { name = "Divine Sword +1" , model = 24852} +models.main[16827] = { name = "Carnage Blade" , model = 24838} +models.main[16828] = { name = "Bastard Sword +1" , model = 24855} +models.main[16829] = { name = "Fencing Degen" , model = 24764} +models.main[16830] = { name = "Gluttony Sword" , model = 24863} +models.main[16831] = { name = "Greed Scimitar" , model = 24858} +models.main[16832] = { name = "Harpoon" , model = 24784} +models.main[16833] = { name = "Bronze Spear" , model = 24781} +models.main[16834] = { name = "Brass Spear" , model = 24782} +models.main[16835] = { name = "Spear" , model = 24783} +models.main[16836] = { name = "Halberd" , model = 24778} +models.main[16837] = { name = "Trident" , model = 24792} +models.main[16838] = { name = "Tonbo-Giri" , model = 24790} +models.main[16839] = { name = "Partisan" , model = 24780} +models.main[16840] = { name = "Ox Tongue" , model = 24779} +models.main[16841] = { name = "Wyvern Spear" , model = 24791} +models.main[16842] = { name = "Golden Spear" , model = 24782} +models.main[16843] = { name = "Draconis Lance" , model = 24788} +models.main[16844] = { name = "Ryl.Sqr. Halberd" , model = 24778} +models.main[16845] = { name = "Lance" , model = 24786} +models.main[16846] = { name = "Bloody Lance" , model = 24785} +models.main[16847] = { name = "Mythril Lance" , model = 24787} +models.main[16848] = { name = "Darksteel Lance" , model = 24785} +models.main[16849] = { name = "Cermet Lance" , model = 24789} +models.main[16850] = { name = "Mercurial Spear" , model = 24783} +models.main[16851] = { name = "R.K. Army Lance" , model = 24786} +models.main[16852] = { name = "Ryl.Spr. Spear" , model = 24782} +models.main[16853] = { name = "Lizard Piercer" , model = 24783} +models.main[16854] = { name = "Vougier's Contus" , model = 25012} +models.main[16855] = { name = "Colossal Lance" , model = 24786} +models.main[16856] = { name = "Obelisk" , model = 24781} +models.main[16857] = { name = "Wind Spear" , model = 24783} +models.main[16858] = { name = "Sacred Lance" , model = 24786} +models.main[16859] = { name = "Bronze Spear +1" , model = 24781} +models.main[16860] = { name = "Holy Lance" , model = 24786} +models.main[16861] = { name = "Ice Lance" , model = 24789} +models.main[16862] = { name = "Harpoon +1" , model = 24784} +models.main[16863] = { name = "Cruel Spear" , model = 24783} +models.main[16864] = { name = "Brass Spear +1" , model = 24782} +models.main[16865] = { name = "Spear +1" , model = 24783} +models.main[16866] = { name = "Halberd +1" , model = 24778} +models.main[16867] = { name = "Orc Piercer" , model = 24784} +models.main[16868] = { name = "Heavy Halberd" , model = 24778} +models.main[16869] = { name = "Thundercloud" , model = 24782} +models.main[16870] = { name = "Envy Spear" , model = 24781} +models.main[16871] = { name = "Kamayari" , model = 24790} +models.main[16872] = { name = "Kamayari +1" , model = 24790} +models.main[16873] = { name = "Wyvern Spear +1" , model = 24791} +models.main[16874] = { name = "Partisan +1" , model = 24780} +models.main[16875] = { name = "Golden Spear +1" , model = 24782} +models.main[16876] = { name = "Lance +1" , model = 24786} +models.main[16877] = { name = "Mythril Lance +1" , model = 24787} +models.main[16878] = { name = "Dst. Lance +1" , model = 24785} +models.main[16879] = { name = "Cermet Lance +1" , model = 24789} +models.main[16880] = { name = "Holy Lance +1" , model = 24786} +models.main[16881] = { name = "Carnage Lance" , model = 24785} +models.main[16882] = { name = "Calamar" , model = 24792} +models.main[16883] = { name = "Monsoon Spear" , model = 24790} +models.main[16884] = { name = "Narval" , model = 24789} +models.main[16885] = { name = "Gae Bolg" , model = 24786} +models.main[16886] = { name = "Gnd.Kgt. Lance" , model = 24787} +models.main[16887] = { name = "Peregrine" , model = 24786} +models.main[16888] = { name = "Battle Fork" , model = 24792} +models.main[16889] = { name = "Battle Fork +1" , model = 24792} +models.main[16890] = { name = "Obelisk Lance" , model = 24946} +models.main[16891] = { name = "Obelisk Lance +1" , model = 24946} +models.main[16892] = { name = "Spear of Trials" , model = 24781} +models.main[16893] = { name = "Rsv.Cpt. Lance" , model = 24788} +models.main[16894] = { name = "Ox Tongue +1" , model = 24779} +models.main[16895] = { name = "Ice Lance +1" , model = 24789} +models.main[16896] = { name = "Kunai" , model = 24891} +models.main[16897] = { name = "Kageboshi" , model = 24890} +models.main[16898] = { name = "Cmb.Cst. Kusabi" , model = 24890} +models.main[16899] = { name = "Hototogisu" , model = 24891} +models.main[16900] = { name = "Wakizashi" , model = 24886} +models.main[16901] = { name = "Kodachi" , model = 24887} +models.main[16902] = { name = "Sakurafubuki" , model = 24888} +models.main[16903] = { name = "Kabutowari" , model = 24889} +models.main[16904] = { name = "Fudo" , model = 24885} +models.main[16905] = { name = "Bokuto" , model = 24886} +models.main[16906] = { name = "Mokuto" , model = 24886} +models.main[16907] = { name = "Busuto" , model = 24886} +models.main[16908] = { name = "Yoto" , model = 24886} +models.main[16909] = { name = "Kororito" , model = 24886} +models.main[16910] = { name = "Mamushito" , model = 24886} +models.main[16911] = { name = "Amanojaku" , model = 24886} +models.main[16912] = { name = "Kitsutsuki" , model = 24891} +models.main[16913] = { name = "Shinogi" , model = 24887} +models.main[16914] = { name = "Kunai +1" , model = 24891} +models.main[16915] = { name = "Hien" , model = 24891} +models.main[16916] = { name = "Hien +1" , model = 24891} +models.main[16917] = { name = "Suzume" , model = 24891} +models.main[16918] = { name = "Wakizashi +1" , model = 24886} +models.main[16919] = { name = "Shinobi-Gatana" , model = 24886} +models.main[16920] = { name = "Shinobi-Gatana +1" , model = 24886} +models.main[16921] = { name = "Kodachi +1" , model = 24887} +models.main[16922] = { name = "Sakurafubuki +1" , model = 24888} +models.main[16923] = { name = "Kabutowari +1" , model = 24889} +models.main[16924] = { name = "Hocho" , model = 24888} +models.main[16925] = { name = "Mokuto +1" , model = 24886} +models.main[16926] = { name = "Bokuto +1" , model = 24886} +models.main[16927] = { name = "Busuto +1" , model = 24886} +models.main[16928] = { name = "Hellfire Sword" , model = 24647} +models.main[16929] = { name = "Burning Claymore" , model = 24642} +models.main[16930] = { name = "Mrc. Greatsword" , model = 24642} +models.main[16931] = { name = "2-Hand. Sword +1" , model = 24647} +models.main[16932] = { name = "Greatsword +1" , model = 24648} +models.main[16933] = { name = "Dst. Claymore +1" , model = 24641} +models.main[16934] = { name = "Braveheart" , model = 24642} +models.main[16935] = { name = "Barbarian's Sword" , model = 24642} +models.main[16936] = { name = "Demonic Sword" , model = 24647} +models.main[16937] = { name = "Ice Brand" , model = 24648} +models.main[16938] = { name = "Glorious Sword" , model = 24644} +models.main[16939] = { name = "Ram-Dao +1" , model = 24651} +models.main[16940] = { name = "Gerwitz's Sword" , model = 24642} +models.main[16941] = { name = "Flamberge +1" , model = 24650} +models.main[16942] = { name = "Balmung" , model = 24897} +models.main[16943] = { name = "Ascalon" , model = 24649} +models.main[16944] = { name = "Lockheart" , model = 24643} +models.main[16945] = { name = "Arondight" , model = 24645} +models.main[16946] = { name = "Windurstian Sword" , model = 24642} +models.main[16947] = { name = "Federation Sword" , model = 24642} +models.main[16948] = { name = "Ryl.Swd. Blade +1" , model = 24648} +models.main[16949] = { name = "Ryl.Swd. Blade +2" , model = 24648} +models.main[16950] = { name = "Mythril Heart" , model = 24643} +models.main[16951] = { name = "Mythril Heart +1" , model = 24643} +models.main[16952] = { name = "Sword of Trials" , model = 24642} +models.main[16953] = { name = "Rsv.Cpt.Grt. sword" , model = 24640} +models.main[16954] = { name = "Pealing Nagan" , model = 24649} +models.main[16955] = { name = "Nagan +1" , model = 24649} +models.main[16956] = { name = "Skofnung" , model = 24645} +models.main[16957] = { name = "Faussar" , model = 24651} +models.main[16958] = { name = "Faussar +1" , model = 24651} +models.main[16959] = { name = "Platoon Sword" , model = 24647} +models.main[16960] = { name = "Uchigatana" , model = 24730} +models.main[16961] = { name = "Murasame" , model = 24731} +models.main[16962] = { name = "Ashura" , model = 24732} +models.main[16963] = { name = "Taimakuniyuki" , model = 24968} +models.main[16964] = { name = "Zanbato" , model = 24727} +models.main[16965] = { name = "Koryukagemitsu" , model = 24723} +models.main[16966] = { name = "Tachi" , model = 24721} +models.main[16967] = { name = "Mikazuki" , model = 24722} +models.main[16968] = { name = "Kamewari" , model = 24722} +models.main[16969] = { name = "Onikiri" , model = 24724} +models.main[16970] = { name = "Hosodachi" , model = 24723} +models.main[16971] = { name = "Yukitsugu" , model = 24899} +models.main[16972] = { name = "Kazaridachi" , model = 24899} +models.main[16973] = { name = "Homura" , model = 24721} +models.main[16974] = { name = "Dotanuki" , model = 24730} +models.main[16975] = { name = "Kanesada" , model = 24731} +models.main[16976] = { name = "Onimaru" , model = 24720} +models.main[16977] = { name = "Yukitsugu +1" , model = 24899} +models.main[16978] = { name = "Uchigatana +1" , model = 24730} +models.main[16979] = { name = "Ashura +1" , model = 24732} +models.main[16980] = { name = "Sukesada" , model = 24732} +models.main[16981] = { name = "Tachi +1" , model = 24721} +models.main[16982] = { name = "Nodachi" , model = 24721} +models.main[16983] = { name = "Nodachi +1" , model = 24721} +models.main[16984] = { name = "Jindachi" , model = 24721} +models.main[16985] = { name = "Jindachi +1" , model = 24721} +models.main[16986] = { name = "Homura +1" , model = 24721} +models.main[16987] = { name = "Okanehira" , model = 24721} +models.main[16988] = { name = "Kotetsu" , model = 24721} +models.main[16989] = { name = "Mikazuki +1" , model = 24722} +models.main[16990] = { name = "Daihannya" , model = 24722} +models.main[16991] = { name = "Odenta" , model = 24722} +models.main[17024] = { name = "Ash Club" , model = 24684} +models.main[17025] = { name = "Chestnut Club" , model = 24685} +models.main[17026] = { name = "Bone Cudgel" , model = 24677} +models.main[17027] = { name = "Oak Cudgel" , model = 24676} +models.main[17028] = { name = "Freesword's Club" , model = 24684} +models.main[17029] = { name = "Bouncer Club" , model = 24685} +models.main[17030] = { name = "Great Club" , model = 24687} +models.main[17031] = { name = "Shell Scepter" , model = 25168} +models.main[17032] = { name = "Gobbie Gavel" , model = 25169} +models.main[17033] = { name = "Bone Cudgel +1" , model = 24677} +models.main[17034] = { name = "Bronze Mace" , model = 24680} +models.main[17035] = { name = "Mace" , model = 24682} +models.main[17036] = { name = "Mythril Mace" , model = 24683} +models.main[17037] = { name = "Darksteel Mace" , model = 24679} +models.main[17038] = { name = "Buzdygan" , model = 24678} +models.main[17039] = { name = "Platinum Mace" , model = 24681} +models.main[17040] = { name = "Warp Cudgel" , model = 24676} +models.main[17041] = { name = "Holy Mace" , model = 24683} +models.main[17042] = { name = "Bronze Hammer" , model = 24689} +models.main[17043] = { name = "Brass Hammer" , model = 24690} +models.main[17044] = { name = "Warhammer" , model = 24691} +models.main[17045] = { name = "Maul" , model = 24692} +models.main[17046] = { name = "Darksteel Maul" , model = 24688} +models.main[17047] = { name = "Magnus Hammer" , model = 24692} +models.main[17048] = { name = "Decurion's Hammer" , model = 24691} +models.main[17049] = { name = "Maple Wand" , model = 24803} +models.main[17050] = { name = "Willow Wand" , model = 24808} +models.main[17051] = { name = "Yew Wand" , model = 24802} +models.main[17052] = { name = "Chestnut Wand" , model = 24807} +models.main[17053] = { name = "Rose Wand" , model = 24806} +models.main[17054] = { name = "Ebony Wand" , model = 24801} +models.main[17056] = { name = "Mythic Wand" , model = 24804} +models.main[17057] = { name = "Tefnut Wand" , model = 25108} +models.main[17058] = { name = "Caduceus" , model = 24809} +models.main[17059] = { name = "Bronze Rod" , model = 24796} +models.main[17060] = { name = "Rod" , model = 24798} +models.main[17061] = { name = "Mythril Rod" , model = 24799} +models.main[17062] = { name = "Bone Rod" , model = 24800} +models.main[17063] = { name = "Darksteel Rod" , model = 24795} +models.main[17064] = { name = "Scepter" , model = 24794} +models.main[17065] = { name = "Platinum Rod" , model = 24797} +models.main[17066] = { name = "Molva Maul" , model = 24690} +models.main[17067] = { name = "Ryl. Guard's Rod" , model = 24797} +models.main[17068] = { name = "Onion Rod" , model = 24796} +models.main[17069] = { name = "Moepapa Mace" , model = 24683} +models.main[17070] = { name = "Living Rod" , model = 24797} +models.main[17071] = { name = "Heat Rod" , model = 24796} +models.main[17072] = { name = "Lilith's Rod" , model = 24796} +models.main[17073] = { name = "Mistilteinn" , model = 24805} +models.main[17074] = { name = "Chocobo Wand" , model = 24812} +models.main[17075] = { name = "Star Rod" , model = 24816} +models.main[17076] = { name = "Earth Wand" , model = 24820} +models.main[17077] = { name = "Beneficus" , model = 24794} +models.main[17078] = { name = "Siriti" , model = 24809} +models.main[17079] = { name = "Winged Wand" , model = 24804} +models.main[17080] = { name = "Holy Maul" , model = 24692} +models.main[17081] = { name = "Brass Rod" , model = 24797} +models.main[17082] = { name = "Tct.Mag. Wand" , model = 24807} +models.main[17083] = { name = "Time Hammer" , model = 24691} +models.main[17085] = { name = "Holy Wand" , model = 24804} +models.main[17086] = { name = "Bronze Mace +1" , model = 24680} +models.main[17087] = { name = "Maple Wand +1" , model = 24803} +models.main[17088] = { name = "Ash Staff" , model = 24868} +models.main[17089] = { name = "Holly Staff" , model = 24866} +models.main[17090] = { name = "Elm Staff" , model = 24865} +models.main[17091] = { name = "Oak Staff" , model = 24867} +models.main[17092] = { name = "Mahogany Staff" , model = 24869} +models.main[17093] = { name = "Rune Staff" , model = 24881} +models.main[17094] = { name = "Wis.Wiz. Staff" , model = 24871} +models.main[17095] = { name = "Ash Pole" , model = 24878} +models.main[17096] = { name = "Holly Pole" , model = 24876} +models.main[17097] = { name = "Elm Pole" , model = 24875} +models.main[17098] = { name = "Oak Pole" , model = 24877} +models.main[17099] = { name = "Mahogany Pole" , model = 24880} +models.main[17100] = { name = "Ebony Pole" , model = 24874} +models.main[17101] = { name = "Mythic Pole" , model = 24879} +models.main[17102] = { name = "Eight-Sided Pole" , model = 24872} +models.main[17103] = { name = "Mercenary's Pole" , model = 24878} +models.main[17104] = { name = "Onion Staff" , model = 24867} +models.main[17105] = { name = "Soulscourge" , model = 24881} +models.main[17106] = { name = "Rockmasher" , model = 24873} +models.main[17108] = { name = "Healing Staff" , model = 24867} +models.main[17110] = { name = "Celeritas Pole" , model = 24873} +models.main[17111] = { name = "Bronze Rod +1" , model = 24796} +models.main[17112] = { name = "Fulcrum Pole" , model = 24937} +models.main[17113] = { name = "Owleyes" , model = 25100} +models.main[17114] = { name = "Holy Maul +1" , model = 24692} +models.main[17115] = { name = "Warhammer +1" , model = 24691} +models.main[17116] = { name = "Misery Staff" , model = 24870} +models.main[17117] = { name = "Hypno Staff" , model = 24866} +models.main[17118] = { name = "Lituus +1" , model = 24879} +models.main[17119] = { name = "Elm Pole +1" , model = 24875} +models.main[17120] = { name = "Oak Pole +1" , model = 24877} +models.main[17121] = { name = "Maul +1" , model = 24692} +models.main[17122] = { name = "Ash Pole +1" , model = 24878} +models.main[17123] = { name = "Ash Staff +1" , model = 24868} +models.main[17124] = { name = "Holly Pole +1" , model = 24876} +models.main[17125] = { name = "Holly Staff +1" , model = 24866} +models.main[17126] = { name = "Elm Staff +1" , model = 24865} +models.main[17127] = { name = "Oak Staff +1" , model = 24867} +models.main[17128] = { name = "Lgn. Staff" , model = 24870} +models.main[17129] = { name = "Musketeer's Pole" , model = 24880} +models.main[17130] = { name = "Freesword's Staff" , model = 24866} +models.main[17131] = { name = "Lituus" , model = 24879} +models.main[17132] = { name = "Monster Signa" , model = 24882} +models.main[17133] = { name = "Chanter's Staff" , model = 24869} +models.main[17134] = { name = "Dolphin Staff" , model = 24868} +models.main[17135] = { name = "Walrus Staff" , model = 24866} +models.main[17136] = { name = "Sloth Wand" , model = 24806} +models.main[17137] = { name = "Ash Club +1" , model = 24684} +models.main[17138] = { name = "Willow Wand +1" , model = 24808} +models.main[17139] = { name = "Solid Club" , model = 24685} +models.main[17140] = { name = "Yew Wand +1" , model = 24802} +models.main[17141] = { name = "Solid Wand" , model = 24807} +models.main[17142] = { name = "Oak Cudgel +1" , model = 24676} +models.main[17143] = { name = "Rose Wand +1" , model = 24806} +models.main[17144] = { name = "Bronze Hammer +1" , model = 24689} +models.main[17145] = { name = "Mace +1" , model = 24682} +models.main[17146] = { name = "Rod +1" , model = 24798} +models.main[17147] = { name = "Mythril Mace +1" , model = 24683} +models.main[17148] = { name = "Brass Rod +1" , model = 24797} +models.main[17149] = { name = "Brass Hammer +1" , model = 24690} +models.main[17150] = { name = "Ryl.Sqr. Mace" , model = 24682} +models.main[17151] = { name = "Msk.Cmd. Rod" , model = 24795} +models.main[17408] = { name = "Great Club +1" , model = 24687} +models.main[17409] = { name = "Mythril Rod +1" , model = 24799} +models.main[17410] = { name = "Bone Rod +1" , model = 24800} +models.main[17411] = { name = "Holy Mace +1" , model = 24683} +models.main[17412] = { name = "Wild Cudgel" , model = 24677} +models.main[17413] = { name = "Hermit's Wand" , model = 24808} +models.main[17414] = { name = "Pixie Mace" , model = 24683} +models.main[17415] = { name = "Shellbuster" , model = 24686} +models.main[17416] = { name = "Arcana Breaker" , model = 24689} +models.main[17417] = { name = "Rabbit Stick" , model = 24804} +models.main[17418] = { name = "Moonlight Wand" , model = 24804} +models.main[17419] = { name = "Artemis's Wand" , model = 24804} +models.main[17420] = { name = "Selene's Wand" , model = 24804} +models.main[17421] = { name = "Moonwatch Wand" , model = 24804} +models.main[17422] = { name = "Blessed Hammer" , model = 24691} +models.main[17423] = { name = "Casting Wand" , model = 24802} +models.main[17424] = { name = "Spiked Club" , model = 24872} +models.main[17425] = { name = "Spiked Club +1" , model = 24872} +models.main[17426] = { name = "Replica Maul" , model = 24692} +models.main[17427] = { name = "Ebony Wand +1" , model = 24801} +models.main[17428] = { name = "Darksteel Mace +1" , model = 24679} +models.main[17429] = { name = "Dominion Mace" , model = 24681} +models.main[17430] = { name = "Fey Wand" , model = 24824} +models.main[17431] = { name = "Platinum Mace +1" , model = 24681} +models.main[17432] = { name = "Darksteel Maul +1" , model = 24688} +models.main[17433] = { name = "Mythic Wand +1" , model = 24804} +models.main[17434] = { name = "Holy Wand +1" , model = 24804} +models.main[17435] = { name = "Darksteel Rod +1" , model = 24795} +models.main[17436] = { name = "Platinum Rod +1" , model = 24797} +models.main[17437] = { name = "Curse Wand" , model = 24818} +models.main[17438] = { name = "Titan's Cudgel" , model = 24676} +models.main[17439] = { name = "Leviathan's Rod" , model = 24797} +models.main[17440] = { name = "Kraken Club" , model = 24686} +models.main[17441] = { name = "Eremite's Wand" , model = 24808} +models.main[17442] = { name = "Eremite's Wand +1" , model = 24808} +models.main[17443] = { name = "Thoth's Wand" , model = 24804} +models.main[17444] = { name = "Windurstian Club" , model = 24684} +models.main[17445] = { name = "Federation Club" , model = 24684} +models.main[17446] = { name = "T.M. Wand +1" , model = 24807} +models.main[17447] = { name = "T.M. Wand +2" , model = 24807} +models.main[17448] = { name = "San d'Orian Mace" , model = 24682} +models.main[17449] = { name = "Kingdom Mace" , model = 24682} +models.main[17450] = { name = "Healing Mace" , model = 24680} +models.main[17451] = { name = "Morgenstern" , model = 24936} +models.main[17452] = { name = "Bastokan Hammer" , model = 24691} +models.main[17453] = { name = "Republic Hammer" , model = 24691} +models.main[17454] = { name = "Asklepios" , model = 24817} +models.main[17455] = { name = "Skirnir's Wand" , model = 24819} +models.main[17456] = { name = "Club of Trials" , model = 24684} +models.main[17457] = { name = "Snr.Msk. Rod" , model = 24794} +models.main[17458] = { name = "Rsv.Cpt. Mace" , model = 24681} +models.main[17459] = { name = "Scepter +1" , model = 24794} +models.main[17460] = { name = "Buzdygan +1" , model = 24678} +models.main[17461] = { name = "Rune Rod" , model = 24912} +models.main[17462] = { name = "Platoon Mace" , model = 24680} +models.main[17463] = { name = "Sealed Mace" , model = 24682} +models.main[17464] = { name = "Purgatory Mace" , model = 24679} +models.main[17465] = { name = "Mighty Cudgel" , model = 24676} +models.main[17466] = { name = "Dia Wand" , model = 24803} +models.main[17467] = { name = "Martial Wand" , model = 24818} +models.main[17468] = { name = "Raise Rod" , model = 24799} +models.main[17469] = { name = "Raise II Rod" , model = 24799} +models.main[17470] = { name = "Pealing Buzdygan" , model = 24678} +models.main[17471] = { name = "Horrent Mace" , model = 24679} +models.main[17472] = { name = "Cross-Counters" , model = 24705} +models.main[17473] = { name = "Torama Cesti" , model = 24702} +models.main[17474] = { name = "Grapnel" , model = 24576} +models.main[17475] = { name = "Dst. Katars +1" , model = 24694} +models.main[17476] = { name = "Cat Baghnakhs +1" , model = 24716} +models.main[17477] = { name = "Bone Patas +1" , model = 24715} +models.main[17478] = { name = "Beat Cesti" , model = 24703} +models.main[17479] = { name = "Behem. Cesti +1" , model = 24704} +models.main[17480] = { name = "Dmd. Knuckles +1" , model = 24711} +models.main[17481] = { name = "Kaiser Knuckles" , model = 24710} +models.main[17482] = { name = "Jamadhars +1" , model = 24696} +models.main[17483] = { name = "Venom Katars +1" , model = 24694} +models.main[17484] = { name = "Stun Jamadhars +1" , model = 24696} +models.main[17485] = { name = "Dragon Claws +1" , model = 24701} +models.main[17486] = { name = "Stun Claws +1" , model = 24701} +models.main[17487] = { name = "Corrosive Claws" , model = 24700} +models.main[17488] = { name = "Cermet Claws +1" , model = 24701} +models.main[17489] = { name = "Gold Patas +1" , model = 24713} +models.main[17490] = { name = "Feral Fangs" , model = 24715} +models.main[17491] = { name = "Spartan Cesti" , model = 24704} +models.main[17492] = { name = "Shiva's Claws" , model = 24701} +models.main[17493] = { name = "Tropical Punches" , model = 24702} +models.main[17494] = { name = "Trp. Punches +1" , model = 24702} +models.main[17495] = { name = "San d'Orian Cesti" , model = 24702} +models.main[17496] = { name = "Kingdom Cesti" , model = 24702} +models.main[17497] = { name = "Win. Baghnakhs" , model = 24716} +models.main[17498] = { name = "Fed. Baghnakhs" , model = 24716} +models.main[17499] = { name = "Bas. Knuckles" , model = 24707} +models.main[17500] = { name = "Republic Knuckles" , model = 24707} +models.main[17501] = { name = "T.M. Hooks +1" , model = 24715} +models.main[17502] = { name = "T.M. Hooks +2" , model = 24715} +models.main[17503] = { name = "Exocets" , model = 24697} +models.main[17504] = { name = "Pagures" , model = 24709} +models.main[17505] = { name = "Narasimha's Cesti" , model = 24702} +models.main[17506] = { name = "Vishnu's Cesti" , model = 24702} +models.main[17507] = { name = "Knuckles of Trials" , model = 24706} +models.main[17508] = { name = "Mst.Cst.Baghnakhs" , model = 24718} +models.main[17509] = { name = "Destroyers" , model = 24703} +models.main[17510] = { name = "Vampiric Claws" , model = 24698} +models.main[17511] = { name = "Indra Katars" , model = 24696} +models.main[17512] = { name = "Hydro Baghnakhs" , model = 24717} +models.main[17513] = { name = "Hyd.Baghnakhs +1" , model = 24717} +models.main[17514] = { name = "Hydro Claws" , model = 24699} +models.main[17515] = { name = "Hydro Claws +1" , model = 24699} +models.main[17516] = { name = "Hydro Patas" , model = 24715} +models.main[17517] = { name = "Hydro Patas +1" , model = 24715} +models.main[17518] = { name = "Manoples +1" , model = 24712} +models.main[17519] = { name = "Platoon Cesti" , model = 24703} +models.main[17520] = { name = "Heavy Staff" , model = 24869} +models.main[17521] = { name = "Mahogany Pole +1" , model = 24880} +models.main[17522] = { name = "Pride Staff" , model = 24870} +models.main[17523] = { name = "Quarterstaff" , model = 24872} +models.main[17524] = { name = "Footman's Staff" , model = 24872} +models.main[17525] = { name = "Ebony Pole +1" , model = 24874} +models.main[17526] = { name = "Mythic Pole +1" , model = 24879} +models.main[17527] = { name = "Pole of Trials" , model = 24878} +models.main[17528] = { name = "Astral Signa" , model = 24882} +models.main[17529] = { name = "Sunlight Pole" , model = 24875} +models.main[17530] = { name = "Mst.Cst. Pole" , model = 24877} +models.main[17531] = { name = "Ramuh's Staff" , model = 24865} +models.main[17532] = { name = "Kukulcan's Staff" , model = 24869} +models.main[17533] = { name = "Whale Staff" , model = 24868} +models.main[17534] = { name = "Whale Staff +1" , model = 24868} +models.main[17535] = { name = "Windurstian Pole" , model = 24878} +models.main[17536] = { name = "Federation Pole" , model = 24878} +models.main[17537] = { name = "Windurstian Staff" , model = 24866} +models.main[17538] = { name = "Federation Staff" , model = 24866} +models.main[17539] = { name = "Msk. Pole +1" , model = 24880} +models.main[17540] = { name = "Msk. Pole +2" , model = 24880} +models.main[17541] = { name = "Bastokan Staff" , model = 24870} +models.main[17542] = { name = "Republic Staff" , model = 24870} +models.main[17543] = { name = "Battle Staff" , model = 24872} +models.main[17544] = { name = "Battle Staff +1" , model = 24872} +models.main[17545] = { name = "Fire Staff" , model = 24905} +models.main[17546] = { name = "Vulcan's Staff" , model = 24905} +models.main[17547] = { name = "Ice Staff" , model = 24903} +models.main[17548] = { name = "Aquilo's Staff" , model = 24903} +models.main[17549] = { name = "Wind Staff" , model = 24902} +models.main[17550] = { name = "Auster's Staff" , model = 24902} +models.main[17551] = { name = "Earth Staff" , model = 24907} +models.main[17552] = { name = "Terra's Staff" , model = 24907} +models.main[17553] = { name = "Thunder Staff" , model = 24904} +models.main[17554] = { name = "Jupiter's Staff" , model = 24904} +models.main[17555] = { name = "Water Staff" , model = 24901} +models.main[17556] = { name = "Neptune's Staff" , model = 24901} +models.main[17557] = { name = "Light Staff" , model = 24906} +models.main[17558] = { name = "Apollo's Staff" , model = 24906} +models.main[17559] = { name = "Dark Staff" , model = 24900} +models.main[17560] = { name = "Pluto's Staff" , model = 24900} +models.main[17561] = { name = "Revenging Staff" , model = 24867} +models.main[17562] = { name = "Rvg. Staff +1" , model = 24867} +models.main[17563] = { name = "Power Staff" , model = 24871} +models.main[17564] = { name = "Cocytus Pole" , model = 24874} +models.main[17565] = { name = "Trick Staff" , model = 24908} +models.main[17566] = { name = "Treat Staff" , model = 24908} +models.main[17567] = { name = "Kirin's Pole" , model = 24876} +models.main[17568] = { name = "Eight-Sd. Pole +1" , model = 24872} +models.main[17569] = { name = "Iron-splitter" , model = 24917} +models.main[17570] = { name = "Iron-splitter +1" , model = 24917} +models.main[17571] = { name = "Platoon Pole" , model = 24875} +models.main[17572] = { name = "Dusky Staff" , model = 24868} +models.main[17573] = { name = "Himmel Stock" , model = 24866} +models.main[17574] = { name = "Archalaus's Pole" , model = 24880} +models.main[17575] = { name = "Somnus Signa" , model = 24882} +models.main[17576] = { name = "Grim Staff" , model = 24869} +models.main[17577] = { name = "Capricorn Staff" , model = 24867} +models.main[17578] = { name = "Zen Pole" , model = 24879} +models.main[17579] = { name = "Wyvern Perch" , model = 24874} +models.main[17580] = { name = "Military Pole" , model = 24875} +models.main[17581] = { name = "Mighty Pole" , model = 24876} +models.main[17582] = { name = "Prelatic Pole" , model = 24879} +models.main[17583] = { name = "Kgd. Signet Staff" , model = 24931} +models.main[17584] = { name = "Rep. Signet Staff" , model = 24933} +models.main[17585] = { name = "Fed. Signet Staff" , model = 24932} +models.main[17586] = { name = "Mercurial Pole" , model = 24879} +models.main[17587] = { name = "Trick Staff II" , model = 24908} +models.main[17588] = { name = "Treat Staff II" , model = 24908} +models.main[17589] = { name = "Thyrsusstab" , model = 24865} +models.main[17590] = { name = "Primate Staff" , model = 24937} +models.main[17591] = { name = "Primate Staff +1" , model = 24937} +models.main[17592] = { name = "Kinkobo" , model = 24937} +models.main[17593] = { name = "Martial Staff" , model = 24865} +models.main[17594] = { name = "Gelong Staff" , model = 24867} +models.main[17595] = { name = "Hope Staff" , model = 24881} +models.main[17596] = { name = "Steel-splitter" , model = 24917} +models.main[17597] = { name = "Dragon Staff" , model = 24869} +models.main[17598] = { name = "Bahamut's Staff" , model = 24869} +models.main[17599] = { name = "Diabolos's Pole" , model = 24874} +models.main[17600] = { name = "Stun Knife +1" , model = 24738} +models.main[17601] = { name = "Demon's Knife" , model = 24756} +models.main[17602] = { name = "Demon's Knife +1" , model = 24756} +models.main[17603] = { name = "Cermet Kukri +1" , model = 24750} +models.main[17604] = { name = "Venom Kukri +1" , model = 24747} +models.main[17605] = { name = "Acid Dagger" , model = 24743} +models.main[17606] = { name = "Corrosive Dagger" , model = 24743} +models.main[17607] = { name = "Corrosive Baselard" , model = 24746} +models.main[17608] = { name = "Corrosive Knife" , model = 24737} +models.main[17609] = { name = "Cermet Knife +1" , model = 24738} +models.main[17610] = { name = "Bone Knife" , model = 24756} +models.main[17611] = { name = "Bone Knife +1" , model = 24756} +models.main[17612] = { name = "Beetle Knife" , model = 24756} +models.main[17613] = { name = "Beetle Knife +1" , model = 24756} +models.main[17614] = { name = "Stun Kukri +1" , model = 24750} +models.main[17615] = { name = "Chicken Knife" , model = 24735} +models.main[17616] = { name = "Dagger of Trials" , model = 24740} +models.main[17617] = { name = "Mst.Cst. Knife" , model = 24756} +models.main[17618] = { name = "Kidney Dagger" , model = 24745} +models.main[17619] = { name = "Daylight Dagger" , model = 24746} +models.main[17620] = { name = "Misericorde +1" , model = 24739} +models.main[17621] = { name = "Gully +1" , model = 24733} +models.main[17622] = { name = "Buccaneer's Knife" , model = 24749} +models.main[17623] = { name = "Btm. Knife" , model = 24749} +models.main[17624] = { name = "Anubis's Knife" , model = 24733} +models.main[17625] = { name = "Ponderous Gully" , model = 24733} +models.main[17626] = { name = "Auric Dagger" , model = 25093} +models.main[17627] = { name = "Garuda's Dagger" , model = 24742} +models.main[17628] = { name = "Behemoth Knife" , model = 24756} +models.main[17629] = { name = "Behem. Knife +1" , model = 24756} +models.main[17630] = { name = "Hawker's Knife" , model = 24737} +models.main[17631] = { name = "Hawker's Knife +1" , model = 24737} +models.main[17632] = { name = "Colichemarde +1" , model = 24757} +models.main[17633] = { name = "Rapier +1" , model = 24763} +models.main[17634] = { name = "Wasp Fleuret" , model = 24769} +models.main[17635] = { name = "Schwert +1" , model = 24768} +models.main[17636] = { name = "Jagdplaute +1" , model = 24845} +models.main[17637] = { name = "Wing Sword +1" , model = 24864} +models.main[17638] = { name = "Katzbalger +1" , model = 24851} +models.main[17639] = { name = "Cutlass +1" , model = 24839} +models.main[17640] = { name = "Ptm. Cutlass +1" , model = 24837} +models.main[17641] = { name = "Gold Sword +1" , model = 24826} +models.main[17642] = { name = "Hanger +1" , model = 24834} +models.main[17643] = { name = "Honor Sword" , model = 24828} +models.main[17644] = { name = "Judge's Sword" , model = 24966} +models.main[17645] = { name = "Espadon +1" , model = 24857} +models.main[17646] = { name = "Carnage Sword" , model = 24843} +models.main[17647] = { name = "Aramis's Rapier" , model = 24763} +models.main[17648] = { name = "Dragvandil" , model = 24856} +models.main[17649] = { name = "Nightmare Sword" , model = 24843} +models.main[17650] = { name = "Nadrs" , model = 24858} +models.main[17651] = { name = "Dainslaif" , model = 24848} +models.main[17652] = { name = "Joyeuse" , model = 24761} +models.main[17653] = { name = "Hrotti" , model = 24854} +models.main[17654] = { name = "Sapara of Trials" , model = 24831} +models.main[17655] = { name = "Snr.Msk. Scimitar" , model = 24837} +models.main[17656] = { name = "Verdun +1" , model = 24761} +models.main[17657] = { name = "Anelace +1" , model = 24850} +models.main[17658] = { name = "Tutelary" , model = 24760} +models.main[17659] = { name = "Seiryu's Sword" , model = 24835} +models.main[17660] = { name = "Kilij" , model = 24951} +models.main[17661] = { name = "Storm Scimitar" , model = 24858} +models.main[17662] = { name = "Company Sword" , model = 24857} +models.main[17663] = { name = "Kilij +1" , model = 24951} +models.main[17664] = { name = "Firmament" , model = 24853} +models.main[17665] = { name = "Ifrit's Blade" , model = 24831} +models.main[17666] = { name = "Jr.Msk. Tuck +1" , model = 24760} +models.main[17667] = { name = "Jr.Msk. Tuck +2" , model = 24760} +models.main[17668] = { name = "Firmament +1" , model = 24853} +models.main[17669] = { name = "Sagasinger" , model = 25104} +models.main[17670] = { name = "T.K. Sword +1" , model = 24827} +models.main[17671] = { name = "T.K. Sword +2" , model = 24827} +models.main[17672] = { name = "Bastokan Sword" , model = 24847} +models.main[17673] = { name = "Republic Sword" , model = 24847} +models.main[17674] = { name = "Cmb.Cst.Scmtr. +1" , model = 24833} +models.main[17675] = { name = "Cmb.Cst.Scmtr. +2" , model = 24833} +models.main[17676] = { name = "T.M. Espadon +1" , model = 24856} +models.main[17677] = { name = "T.M. Espadon +2" , model = 24856} +models.main[17678] = { name = "San d'Orian Sword" , model = 24841} +models.main[17679] = { name = "Kingdom Sword" , model = 24841} +models.main[17680] = { name = "Msk. Sword +1" , model = 24764} +models.main[17681] = { name = "Msk. Sword +2" , model = 24764} +models.main[17682] = { name = "Sacred Sword" , model = 24862} +models.main[17683] = { name = "Sacred Degen" , model = 24765} +models.main[17684] = { name = "Griffinclaw" , model = 24826} +models.main[17685] = { name = "Lex Talionis" , model = 24760} +models.main[17686] = { name = "Spark Bilbo" , model = 24760} +models.main[17687] = { name = "Spark Bilbo +1" , model = 24760} +models.main[17688] = { name = "Spark Degen" , model = 24765} +models.main[17689] = { name = "Spark Degen +1" , model = 24765} +models.main[17690] = { name = "Spark Rapier" , model = 24763} +models.main[17691] = { name = "Spark Rapier +1" , model = 24763} +models.main[17692] = { name = "Platoon Spatha" , model = 24825} +models.main[17693] = { name = "Grudge Sword" , model = 24828} +models.main[17694] = { name = "Guespiere" , model = 24762} +models.main[17695] = { name = "Bayard's Sword" , model = 24849} +models.main[17696] = { name = "Buzzard Tuck" , model = 24760} +models.main[17697] = { name = "Mighty Talwar" , model = 24833} +models.main[17698] = { name = "Princely Sword" , model = 24854} +models.main[17699] = { name = "Dissector" , model = 24861} +models.main[17700] = { name = "Durandal" , model = 24853} +models.main[17701] = { name = "Shotel" , model = 24934} +models.main[17702] = { name = "Shotel +1" , model = 24934} +models.main[17703] = { name = "Pealing Anelace" , model = 24850} +models.main[17704] = { name = "Vulcan Sword" , model = 24844} +models.main[17705] = { name = "Vulcan Degen" , model = 24764} +models.main[17706] = { name = "Vulcan Blade" , model = 24839} +models.main[17707] = { name = "Martial Anelace" , model = 24850} +models.main[17708] = { name = "Auriga Xiphos" , model = 24840} +models.main[17709] = { name = "Swan Bilbo" , model = 24757} +models.main[17710] = { name = "Justice Sword" , model = 24830} +models.main[17711] = { name = "Shiva's Shotel" , model = 24934} +models.main[17712] = { name = "Kaskara +1" , model = 24854} +models.main[17713] = { name = "Macuahuitl" , model = 24957} +models.main[17714] = { name = "Macuahuitl +1" , model = 24957} +models.main[17715] = { name = "Storm Tulwar" , model = 24833} +models.main[17716] = { name = "Macuahuitl -1" , model = 24957} +models.main[17717] = { name = "Immortal's Scimitar" , model = 24858} +models.main[17718] = { name = "Leech Scimitar" , model = 24832} +models.main[17719] = { name = "Mensur Epee" , model = 24769} +models.main[17720] = { name = "Company Fleuret" , model = 24767} +models.main[17721] = { name = "Sanguine Sword" , model = 24966} +models.main[17722] = { name = "Phantom Fleuret" , model = 24767} +models.main[17723] = { name = "Singh Kilij" , model = 24951} +models.main[17724] = { name = "Darksteel Kilij" , model = 24958} +models.main[17725] = { name = "Darksteel Kilij +1" , model = 24958} +models.main[17726] = { name = "Immortal's Shotel" , model = 24934} +models.main[17727] = { name = "Adaman Kilij" , model = 24960} +models.main[17728] = { name = "Adaman Kilij +1" , model = 24960} +models.main[17729] = { name = "Vermin Slayer" , model = 24958} +models.main[17730] = { name = "Insect Slayer" , model = 24958} +models.main[17731] = { name = "Aquan Slayer" , model = 24958} +models.main[17732] = { name = "Marine Slayer" , model = 24958} +models.main[17733] = { name = "Dragon Slayer" , model = 24960} +models.main[17734] = { name = "Wyrm Slayer" , model = 24960} +models.main[17735] = { name = "Demon Slayer" , model = 24960} +models.main[17736] = { name = "Devil Slayer" , model = 24960} +models.main[17737] = { name = "Corsair's Scimitar" , model = 24832} +models.main[17738] = { name = "Hauteclaire" , model = 24975} +models.main[17739] = { name = "Steel Kilij" , model = 24978} +models.main[17740] = { name = "Steel Kilij +1" , model = 24978} +models.main[17741] = { name = "Perdu Hanger" , model = 24834} +models.main[17742] = { name = "Vorpal Sword" , model = 24767} +models.main[17743] = { name = "Wightslayer" , model = 24951} +models.main[17744] = { name = "Brave Blade" , model = 24857} +models.main[17745] = { name = "Hofud" , model = 24980} +models.main[17746] = { name = "Cermet Kilij" , model = 24978} +models.main[17747] = { name = "Cermet Kilij +1" , model = 24978} +models.main[17748] = { name = "Ibushi Shinai" , model = 24988} +models.main[17749] = { name = "Ibushi Shinai +1" , model = 24988} +models.main[17750] = { name = "Anthos Xiphos" , model = 24840} +models.main[17751] = { name = "Fragarach" , model = 25007} +models.main[17753] = { name = "Organics" , model = 25021} +models.main[17754] = { name = "Sylphid Epee" , model = 24766} +models.main[17755] = { name = "Beast Slayer" , model = 24978} +models.main[17756] = { name = "Sinfender" , model = 24832} +models.main[17757] = { name = "Merveilleuse" , model = 24826} +models.main[17758] = { name = "Ruler" , model = 24829} +models.main[17759] = { name = "Koggelmander" , model = 24842} +models.main[17760] = { name = "Buc. Scimitar" , model = 24834} +models.main[17761] = { name = "Oberon's Rapier" , model = 24763} +models.main[17762] = { name = "Erlking's Sword" , model = 24851} +models.main[17763] = { name = "Erlking's Blade" , model = 24836} +models.main[17764] = { name = "Trainee Sword" , model = 24829} +models.main[17765] = { name = "Concordia" , model = 25036} +models.main[17766] = { name = "Lyft Scimitar" , model = 24831} +models.main[17767] = { name = "Chipped Scimitar" , model = 24832} +models.main[17768] = { name = "Yoto +1" , model = 24886} +models.main[17769] = { name = "Kororito +1" , model = 24886} +models.main[17770] = { name = "Mamushito +1" , model = 24886} +models.main[17771] = { name = "Anju" , model = 24891} +models.main[17772] = { name = "Zushio" , model = 24887} +models.main[17773] = { name = "Kodachi of Trials" , model = 24887} +models.main[17774] = { name = "Shiranui" , model = 24889} +models.main[17775] = { name = "Fukuro" , model = 24890} +models.main[17776] = { name = "Hibari" , model = 24891} +models.main[17777] = { name = "Hibari +1" , model = 24891} +models.main[17778] = { name = "Muketsu" , model = 24888} +models.main[17779] = { name = "Muketsu +1" , model = 24888} +models.main[17780] = { name = "Kyofu" , model = 24886} +models.main[17781] = { name = "Kyofu +1" , model = 24886} +models.main[17782] = { name = "Reppu" , model = 24887} +models.main[17783] = { name = "Reppu +1" , model = 24887} +models.main[17784] = { name = "Keppu" , model = 24888} +models.main[17785] = { name = "Keppu +1" , model = 24888} +models.main[17786] = { name = "Ganko" , model = 24890} +models.main[17787] = { name = "Ohaguro" , model = 24890} +models.main[17788] = { name = "Sairen" , model = 24888} +models.main[17789] = { name = "Unsho" , model = 24888} +models.main[17790] = { name = "Unji" , model = 24888} +models.main[17791] = { name = "Rai Kunimitsu" , model = 24887} +models.main[17792] = { name = "Nikkariaoe" , model = 24888} +models.main[17793] = { name = "Senjuinrikio" , model = 24889} +models.main[17794] = { name = "Niokiyotsuna" , model = 24887} +models.main[17795] = { name = "Sai" , model = 24943} +models.main[17796] = { name = "Sai +1" , model = 24943} +models.main[17797] = { name = "Seito" , model = 24886} +models.main[17798] = { name = "Shamo" , model = 24889} +models.main[17799] = { name = "Imanotsurugi" , model = 24947} +models.main[17800] = { name = "Hosodachi +1" , model = 24723} +models.main[17801] = { name = "Kikugosaku" , model = 25016} +models.main[17802] = { name = "Kiku-Ichimonji" , model = 24723} +models.main[17803] = { name = "Zanbato +1" , model = 24727} +models.main[17804] = { name = "Ushikirimaru" , model = 24727} +models.main[17805] = { name = "Kazaridachi +1" , model = 24899} +models.main[17806] = { name = "Asa-arashi" , model = 24899} +models.main[17807] = { name = "Gld.Msk. Uchigat." , model = 24731} +models.main[17808] = { name = "Scathacha" , model = 25099} +models.main[17809] = { name = "Mumeito" , model = 24730} +models.main[17810] = { name = "Futsuno Mitama" , model = 24916} +models.main[17811] = { name = "Katayama" , model = 24722} +models.main[17812] = { name = "Magoroku" , model = 24722} +models.main[17813] = { name = "Soboro Sukehiro" , model = 24731} +models.main[17814] = { name = "Raikiri" , model = 24720} +models.main[17815] = { name = "Tachi of Trials" , model = 24721} +models.main[17816] = { name = "Kotetsu +1" , model = 24721} +models.main[17817] = { name = "Shinkotetsu" , model = 24721} +models.main[17818] = { name = "Kanesada +1" , model = 24731} +models.main[17819] = { name = "Shinkanesada" , model = 24731} +models.main[17820] = { name = "Gunromaru" , model = 24730} +models.main[17821] = { name = "Kagehide" , model = 24723} +models.main[17822] = { name = "Omokage" , model = 24722} +models.main[17823] = { name = "Shinsoku" , model = 24899} +models.main[17824] = { name = "Nukemaru" , model = 24720} +models.main[17825] = { name = "Honebami" , model = 24732} +models.main[17826] = { name = "Messhikimaru" , model = 24899} +models.main[17827] = { name = "Michishiba" , model = 24732} +models.main[17828] = { name = "Koen" , model = 24721} +models.main[17829] = { name = "Hagun" , model = 24727} +models.main[17830] = { name = "Wooden Katana" , model = 24944} +models.main[17831] = { name = "Hardwood Katana" , model = 24944} +models.main[17924] = { name = "Tungi" , model = 24667} +models.main[17925] = { name = "Fransisca" , model = 24667} +models.main[17926] = { name = "Acha d'Armas" , model = 24657} +models.main[17927] = { name = "Lohar" , model = 24662} +models.main[17928] = { name = "Juggernaut" , model = 24667} +models.main[17929] = { name = "Bastokan Axe" , model = 24654} +models.main[17930] = { name = "Republic Axe" , model = 24654} +models.main[17931] = { name = "Cmb.Cst. Axe +1" , model = 24659} +models.main[17932] = { name = "Cmb.Cst. Axe +2" , model = 24659} +models.main[17933] = { name = "Pick of Trials" , model = 24666} +models.main[17934] = { name = "Rsv.Cpt. Pick" , model = 24662} +models.main[17935] = { name = "Tabarzin +1" , model = 24657} +models.main[17936] = { name = "De Saintre's Axe" , model = 24652} +models.main[17937] = { name = "Leopard Axe" , model = 24653} +models.main[17938] = { name = "Woodville's Axe" , model = 24659} +models.main[17939] = { name = "Kriegsbeil" , model = 24667} +models.main[17940] = { name = "Military Pick" , model = 24664} +models.main[17941] = { name = "Mighty Pick" , model = 24663} +models.main[17942] = { name = "Tomahawk" , model = 24929} +models.main[17943] = { name = "Tomahawk +1" , model = 24929} +models.main[17944] = { name = "Retributor" , model = 24929} +models.main[17945] = { name = "Martial Axe" , model = 24652} +models.main[17946] = { name = "Maneater" , model = 24658} +models.main[17947] = { name = "Garde Pick" , model = 24665} +models.main[17948] = { name = "Temperance Axe" , model = 24661} +models.main[17949] = { name = "Furnace Tabarzin" , model = 24657} +models.main[17950] = { name = "Marid Ancus" , model = 24662} +models.main[17951] = { name = "Storm Tabar" , model = 24658} +models.main[17952] = { name = "Sirius Axe" , model = 24963} +models.main[17953] = { name = "Zoraal Ja's Axe" , model = 24929} +models.main[17954] = { name = "Jolt Axe" , model = 24652} +models.main[17955] = { name = "Plain Pick" , model = 24664} +models.main[17956] = { name = "Double Axe" , model = 24660} +models.main[17957] = { name = "Navy Axe" , model = 24655} +models.main[17958] = { name = "Iron Ram Pick" , model = 24664} +models.main[17959] = { name = "Viperine Pick" , model = 24664} +models.main[17960] = { name = "Labrys" , model = 25009} +models.main[17961] = { name = "Lion Tamer" , model = 24664} +models.main[17962] = { name = "Fleetwing" , model = 24660} +models.main[17963] = { name = "Rainmaker" , model = 24929} +models.main[17964] = { name = "Barkborer" , model = 24666} +models.main[17965] = { name = "Sirocco Axe" , model = 24655} +models.main[17966] = { name = "Erlking's Tabar" , model = 24658} +models.main[17967] = { name = "Felling Axe" , model = 24653} +models.main[17968] = { name = "Veldt Axe" , model = 24653} +models.main[17969] = { name = "Fendoir" , model = 24652} +models.main[17970] = { name = "Lyft Tabar" , model = 24657} +models.main[17971] = { name = "Tartaglia" , model = 24655} +models.main[17972] = { name = "San. Dagger" , model = 24743} +models.main[17973] = { name = "Kingdom Dagger" , model = 24743} +models.main[17974] = { name = "Bastokan Dagger" , model = 24743} +models.main[17975] = { name = "Republic Dagger" , model = 24743} +models.main[17976] = { name = "Windurstian Knife" , model = 24736} +models.main[17977] = { name = "Federation Knife" , model = 24736} +models.main[17978] = { name = "Windurstian Kukri" , model = 24748} +models.main[17979] = { name = "Federation Kukri" , model = 24748} +models.main[17980] = { name = "Hornetneedle" , model = 24739} +models.main[17981] = { name = "Bano del Sol" , model = 24753} +models.main[17982] = { name = "Kard" , model = 24893} +models.main[17983] = { name = "Valiant Knife" , model = 24733} +models.main[17984] = { name = "Spark Dagger" , model = 24742} +models.main[17985] = { name = "Spark Dagger +1" , model = 24742} +models.main[17986] = { name = "Spark Baselard" , model = 24746} +models.main[17987] = { name = "Spark Baselard +1" , model = 24746} +models.main[17988] = { name = "Spark Kris" , model = 24754} +models.main[17989] = { name = "Spark Kris +1" , model = 24754} +models.main[17990] = { name = "Cmb.Cst.Dagger +1" , model = 24753} +models.main[17991] = { name = "Cmb.Cst.Dagger +2" , model = 24753} +models.main[17992] = { name = "Triton's Dagger" , model = 24755} +models.main[17993] = { name = "Platoon Dagger" , model = 24741} +models.main[17994] = { name = "Calveley's Dagger" , model = 24971} +models.main[17995] = { name = "Jongleur's Dagger" , model = 24740} +models.main[17996] = { name = "Stylet" , model = 24745} +models.main[17997] = { name = "Argent Dagger" , model = 24922} +models.main[17998] = { name = "Thanatos Baselard" , model = 24744} +models.main[17999] = { name = "Taillefer's Dagger" , model = 24755} +models.main[18000] = { name = "Mighty Knife" , model = 24734} +models.main[18001] = { name = "Harpe" , model = 24930} +models.main[18002] = { name = "Perseus's Harpe" , model = 24930} +models.main[18003] = { name = "Swordbreaker" , model = 24751} +models.main[18004] = { name = "Trailer's Kukri" , model = 24750} +models.main[18005] = { name = "Heart Snatcher" , model = 24751} +models.main[18006] = { name = "Hoplites Harpe" , model = 24930} +models.main[18007] = { name = "Chiroptera Dagger" , model = 24922} +models.main[18008] = { name = "Hushed Dagger" , model = 24741} +models.main[18009] = { name = "Martial Knife" , model = 24734} +models.main[18010] = { name = "Melt Dagger" , model = 24743} +models.main[18011] = { name = "Melt Knife" , model = 24737} +models.main[18012] = { name = "Melt Baselard" , model = 24746} +models.main[18013] = { name = "Melt Kukri" , model = 24749} +models.main[18014] = { name = "Odorous Knife" , model = 24893} +models.main[18015] = { name = "Blau Dolch" , model = 24739} +models.main[18016] = { name = "Odorous Knife +1" , model = 24893} +models.main[18017] = { name = "Asn. Jambiya" , model = 24955} +models.main[18018] = { name = "Sirocco Kukri" , model = 24747} +models.main[18019] = { name = "X's Knife" , model = 24756} +models.main[18020] = { name = "Mercurial Kris" , model = 24754} +models.main[18021] = { name = "Titan's Baselarde" , model = 24745} +models.main[18022] = { name = "Adaman Kris +1" , model = 24753} +models.main[18023] = { name = "Jambiya" , model = 24955} +models.main[18024] = { name = "Jambiya +1" , model = 24955} +models.main[18025] = { name = "Khanjar" , model = 24753} +models.main[18026] = { name = "Magnet Knife" , model = 24734} +models.main[18027] = { name = "Palladium Dagger" , model = 24971} +models.main[18028] = { name = "Matron's Knife" , model = 24972} +models.main[18029] = { name = "Piercing Dagger" , model = 24741} +models.main[18030] = { name = "Khimaira Jambiya" , model = 24974} +models.main[18031] = { name = "Amir Jambiya" , model = 24974} +models.main[18032] = { name = "Adder Jambiya" , model = 24974} +models.main[18033] = { name = "Adder Jambiya +1" , model = 24974} +models.main[18034] = { name = "Dancing Dagger" , model = 24922} +models.main[18035] = { name = "Deathbone Knife" , model = 24756} +models.main[18036] = { name = "Win. Scythe" , model = 24770} +models.main[18037] = { name = "Federation Scythe" , model = 24770} +models.main[18038] = { name = "Bastokan Scythe" , model = 24774} +models.main[18039] = { name = "Republic Scythe" , model = 24774} +models.main[18040] = { name = "Webcutter" , model = 24771} +models.main[18041] = { name = "A l'Outrance" , model = 24777} +models.main[18042] = { name = "Ascention" , model = 24898} +models.main[18043] = { name = "Suzaku's Scythe" , model = 24773} +models.main[18044] = { name = "Scarecrow Scythe" , model = 24772} +models.main[18045] = { name = "Platoon Zaghnal" , model = 24773} +models.main[18046] = { name = "Mutilator" , model = 24772} +models.main[18047] = { name = "Havoc Scythe" , model = 24777} +models.main[18048] = { name = "King Maker" , model = 24921} +models.main[18049] = { name = "Mighty Zaghnal" , model = 24921} +models.main[18050] = { name = "Mandibular Sickle" , model = 24926} +models.main[18051] = { name = "Antlion Sickle" , model = 24926} +models.main[18052] = { name = "Tredecim Scythe" , model = 24777} +models.main[18053] = { name = "Gravedigger" , model = 24926} +models.main[18054] = { name = "Ivory Sickle" , model = 24942} +models.main[18055] = { name = "Ivory Sickle +1" , model = 24942} +models.main[18056] = { name = "Martial Scythe" , model = 24770} +models.main[18057] = { name = "Y's Scythe" , model = 24777} +models.main[18058] = { name = "Orichalcum Scythe" , model = 24948} +models.main[18059] = { name = "Triton's Scythe" , model = 24948} +models.main[18060] = { name = "Blizzard Scythe" , model = 24948} +models.main[18061] = { name = "Bahamut Zaghnal" , model = 24776} +models.main[18062] = { name = "Lucent Scythe" , model = 24770} +models.main[18063] = { name = "Garuda's Sickle" , model = 24942} +models.main[18064] = { name = "Volunt. Scythe" , model = 24772} +models.main[18065] = { name = "Storm Zaghnal" , model = 24921} +models.main[18066] = { name = "Blackjack" , model = 24926} +models.main[18067] = { name = "Keen Zaghnal" , model = 24774} +models.main[18068] = { name = "San d'Orian Spear" , model = 24781} +models.main[18069] = { name = "Kingdom Spear" , model = 24781} +models.main[18070] = { name = "San. Halberd" , model = 24778} +models.main[18071] = { name = "Kingdom Halberd" , model = 24778} +models.main[18072] = { name = "R.K. Lance +1" , model = 24786} +models.main[18073] = { name = "R.K. Lance +2" , model = 24786} +models.main[18074] = { name = "Iron Ram Lance" , model = 24788} +models.main[18075] = { name = "Rossignol" , model = 24783} +models.main[18076] = { name = "Spark Spear" , model = 24782} +models.main[18077] = { name = "Spark Spear +1" , model = 24782} +models.main[18078] = { name = "Spark Lance" , model = 24946} +models.main[18079] = { name = "Spark Lance +1" , model = 24946} +models.main[18080] = { name = "Spark Fork" , model = 24792} +models.main[18081] = { name = "Spark Fork +1" , model = 24792} +models.main[18082] = { name = "Barchha" , model = 24788} +models.main[18083] = { name = "Barchha +1" , model = 24788} +models.main[18084] = { name = "Rune Halberd" , model = 24913} +models.main[18085] = { name = "Platoon Lance" , model = 24787} +models.main[18086] = { name = "Behourd Lance" , model = 24787} +models.main[18087] = { name = "Schwarz Lance" , model = 24786} +models.main[18088] = { name = "Dreizack" , model = 24792} +models.main[18089] = { name = "Schiltron Spear" , model = 24780} +models.main[18090] = { name = "Military Spear" , model = 24783} +models.main[18091] = { name = "Mighty Lance" , model = 24789} +models.main[18092] = { name = "Bourdonasse" , model = 24786} +models.main[18093] = { name = "Couse" , model = 24925} +models.main[18094] = { name = "Couse +1" , model = 24925} +models.main[18095] = { name = "Dispel Couse" , model = 24925} +models.main[18096] = { name = "Heavy Lance" , model = 24786} +models.main[18097] = { name = "Gondo-Shizunori" , model = 24925} +models.main[18098] = { name = "Martial Lance" , model = 24788} +models.main[18099] = { name = "Stone-splitter" , model = 24925} +models.main[18100] = { name = "Love Halberd" , model = 24913} +models.main[18101] = { name = "Z's Trident" , model = 24792} +models.main[18102] = { name = "Pitchfork" , model = 24945} +models.main[18103] = { name = "Pitchfork +1" , model = 24945} +models.main[18104] = { name = "Fuscina" , model = 24792} +models.main[18105] = { name = "Orichalcum Lance" , model = 24946} +models.main[18106] = { name = "Triton's Lance" , model = 24946} +models.main[18107] = { name = "Ponderous Lance" , model = 24946} +models.main[18108] = { name = "Lucent Lance" , model = 24786} +models.main[18109] = { name = "Leviathan's Couse" , model = 24925} +models.main[18110] = { name = "Mezraq" , model = 24954} +models.main[18111] = { name = "Mezraq +1" , model = 24954} +models.main[18112] = { name = "Puk Lance" , model = 24787} +models.main[18113] = { name = "Imperial Neza" , model = 24788} +models.main[18114] = { name = "Tournament Lance" , model = 24786} +models.main[18115] = { name = "Engetsuto" , model = 24967} +models.main[18116] = { name = "Engetsuto +1" , model = 24967} +models.main[18117] = { name = "Gimlet Spear" , model = 24782} +models.main[18118] = { name = "Dark Mezraq" , model = 24964} +models.main[18119] = { name = "Dark Mezraq +1" , model = 24964} +models.main[18120] = { name = "Radiant Lance" , model = 24946} +models.main[18121] = { name = "Valkyrie's Fork" , model = 24981} +models.main[18122] = { name = "Broach Lance" , model = 24786} +models.main[18123] = { name = "Thalassocrat" , model = 24984} +models.main[18124] = { name = "Thalassocrat +1" , model = 24984} +models.main[18125] = { name = "Cletine" , model = 25012} +models.main[18126] = { name = "Tomoe" , model = 25020} +models.main[18127] = { name = "Achilles' Spear" , model = 24789} +models.main[18128] = { name = "Skystrider" , model = 24787} +models.main[18129] = { name = "Dabo" , model = 25029} +models.main[18130] = { name = "Dabo +1" , model = 25029} +models.main[18131] = { name = "Zaide" , model = 25028} +models.main[18196] = { name = "Snr.Msk. Axe" , model = 24668} +models.main[18197] = { name = "Bhuj +1" , model = 24672} +models.main[18198] = { name = "Byakko's Axe" , model = 24674} +models.main[18199] = { name = "Ulfhedinn Axe" , model = 24671} +models.main[18200] = { name = "Hydro Axe" , model = 24671} +models.main[18201] = { name = "Hydro Axe +1" , model = 24671} +models.main[18202] = { name = "Hydro Cutter" , model = 24670} +models.main[18203] = { name = "Hydro Cutter +1" , model = 24670} +models.main[18204] = { name = "Hydro Chopper" , model = 24669} +models.main[18205] = { name = "Hydro Chopper +1" , model = 24669} +models.main[18206] = { name = "Rune Chopper" , model = 24911} +models.main[18207] = { name = "Kheten" , model = 24673} +models.main[18208] = { name = "Kheten +1" , model = 24673} +models.main[18209] = { name = "Platoon Cutter" , model = 24670} +models.main[18210] = { name = "Raifu" , model = 24673} +models.main[18211] = { name = "Gawain's Axe" , model = 24674} +models.main[18212] = { name = "Military Axe" , model = 24671} +models.main[18213] = { name = "Mighty Axe" , model = 24670} +models.main[18214] = { name = "Voulge" , model = 24924} +models.main[18215] = { name = "Voulge +1" , model = 24924} +models.main[18216] = { name = "Twicer" , model = 24924} +models.main[18217] = { name = "Rampager" , model = 24924} +models.main[18218] = { name = "Leucous Voulge" , model = 24941} +models.main[18219] = { name = "Lcs. Voulge +1" , model = 24941} +models.main[18220] = { name = "Prominence Axe" , model = 24670} +models.main[18221] = { name = "Martial Bhuj" , model = 24672} +models.main[18222] = { name = "Fortitude Axe" , model = 24911} +models.main[18223] = { name = "Toporok" , model = 24668} +models.main[18224] = { name = "Toporok +1" , model = 24668} +models.main[18225] = { name = "Blizzard Toporok" , model = 24668} +models.main[18226] = { name = "Darksteel Voulge" , model = 24939} +models.main[18227] = { name = "Dst. Voulge +1" , model = 24939} +models.main[18260] = { name = "Relic Knuckles" , model = 24711} +models.main[18261] = { name = "Militant Knuckles" , model = 24711} +models.main[18262] = { name = "Dynamis Knuckles" , model = 24711} +models.main[18263] = { name = "Caestus" , model = 24711} +models.main[18264] = { name = "Spharai" , model = 25087} +models.main[18265] = { name = "Spharai" , model = 25087} +models.main[18266] = { name = "Relic Dagger" , model = 24739} +models.main[18267] = { name = "Malefic Dagger" , model = 24739} +models.main[18268] = { name = "Dynamis Dagger" , model = 24739} +models.main[18269] = { name = "Batardeau" , model = 24739} +models.main[18270] = { name = "Mandau" , model = 24910} +models.main[18271] = { name = "Mandau" , model = 24910} +models.main[18272] = { name = "Relic Sword" , model = 24845} +models.main[18273] = { name = "Glyptic Sword" , model = 24845} +models.main[18274] = { name = "Dynamis Sword" , model = 24845} +models.main[18275] = { name = "Caliburn" , model = 24845} +models.main[18276] = { name = "Excalibur" , model = 24896} +models.main[18277] = { name = "Excalibur" , model = 24896} +models.main[18278] = { name = "Relic Blade" , model = 24648} +models.main[18279] = { name = "Gilded Blade" , model = 24648} +models.main[18280] = { name = "Dynamis Blade" , model = 24648} +models.main[18281] = { name = "Valhalla" , model = 24640} +models.main[18282] = { name = "Ragnarok" , model = 24895} +models.main[18283] = { name = "Ragnarok" , model = 24895} +models.main[18284] = { name = "Relic Axe" , model = 24667} +models.main[18285] = { name = "Leonine Axe" , model = 24667} +models.main[18286] = { name = "Dynamis Axe" , model = 24667} +models.main[18287] = { name = "Ogre Killer" , model = 24667} +models.main[18288] = { name = "Guttler" , model = 24923} +models.main[18289] = { name = "Guttler" , model = 24923} +models.main[18290] = { name = "Relic Bhuj" , model = 24672} +models.main[18291] = { name = "Agonal Bhuj" , model = 24672} +models.main[18292] = { name = "Dynamis Bhuj" , model = 24672} +models.main[18293] = { name = "Abaddon Killer" , model = 24672} +models.main[18294] = { name = "Bravura" , model = 24915} +models.main[18295] = { name = "Bravura" , model = 24915} +models.main[18296] = { name = "Relic Lance" , model = 24786} +models.main[18297] = { name = "Hotspur Lance" , model = 24786} +models.main[18298] = { name = "Dynamis Lance" , model = 24786} +models.main[18299] = { name = "Gae Assail" , model = 24786} +models.main[18300] = { name = "Gungnir" , model = 24793} +models.main[18301] = { name = "Gungnir" , model = 24793} +models.main[18302] = { name = "Relic Scythe" , model = 24898} +models.main[18303] = { name = "Memento Scythe" , model = 24898} +models.main[18304] = { name = "Dynamis Scythe" , model = 24898} +models.main[18305] = { name = "Bec de Faucon" , model = 24898} +models.main[18306] = { name = "Apocalypse" , model = 24914} +models.main[18307] = { name = "Apocalypse" , model = 24914} +models.main[18308] = { name = "Ihintanto" , model = 24885} +models.main[18309] = { name = "Mimizuku" , model = 24885} +models.main[18310] = { name = "Rogetsu" , model = 24885} +models.main[18311] = { name = "Yoshimitsu" , model = 24885} +models.main[18312] = { name = "Kikoku" , model = 24920} +models.main[18313] = { name = "Kikoku" , model = 24920} +models.main[18314] = { name = "Ito" , model = 24723} +models.main[18315] = { name = "Hayatemaru" , model = 24723} +models.main[18316] = { name = "Oboromaru" , model = 24723} +models.main[18317] = { name = "Totsukanotsurugi" , model = 24724} +models.main[18318] = { name = "Amanomurakumo" , model = 24916} +models.main[18319] = { name = "Amanomurakumo" , model = 24916} +models.main[18320] = { name = "Relic Maul" , model = 24690} +models.main[18321] = { name = "Battering Maul" , model = 24690} +models.main[18322] = { name = "Dynamis Maul" , model = 24690} +models.main[18323] = { name = "Gullintani" , model = 24690} +models.main[18324] = { name = "Mjollnir" , model = 24883} +models.main[18325] = { name = "Mjollnir" , model = 24883} +models.main[18326] = { name = "Relic Staff" , model = 24871} +models.main[18327] = { name = "Sage's Staff" , model = 24871} +models.main[18328] = { name = "Dynamis Staff" , model = 24871} +models.main[18329] = { name = "Thyrus" , model = 24871} +models.main[18330] = { name = "Claustrum" , model = 24918} +models.main[18331] = { name = "Claustrum" , model = 24918} +models.main[18350] = { name = "Tourney Patas" , model = 24713} +models.main[18351] = { name = "Meteor Cesti" , model = 24704} +models.main[18352] = { name = "Mighty Patas" , model = 24715} +models.main[18353] = { name = "Adargas" , model = 25086} +models.main[18354] = { name = "Adargas +1" , model = 25086} +models.main[18355] = { name = "Hushed Baghnakhs" , model = 24717} +models.main[18356] = { name = "Martial Knuckles" , model = 24708} +models.main[18357] = { name = "Melt Claws" , model = 24700} +models.main[18358] = { name = "Wagh Baghnakhs" , model = 24718} +models.main[18359] = { name = "Boreas Cesti" , model = 24704} +models.main[18360] = { name = "Faith Baghnakhs" , model = 24719} +models.main[18361] = { name = "Ponder. Manoples" , model = 24712} +models.main[18362] = { name = "Sainti" , model = 25085} +models.main[18363] = { name = "Sainti +1" , model = 25085} +models.main[18364] = { name = "Pahluwan Katars" , model = 24694} +models.main[18365] = { name = "Pahluwan Patas" , model = 24715} +models.main[18366] = { name = "Gust Claymore" , model = 24642} +models.main[18367] = { name = "Gust Claymore +1" , model = 24642} +models.main[18368] = { name = "Gust Sword" , model = 24648} +models.main[18369] = { name = "Gust Sword +1" , model = 24648} +models.main[18370] = { name = "Gust Tongue" , model = 24650} +models.main[18371] = { name = "Gust Tongue +1" , model = 24650} +models.main[18372] = { name = "Balan's Sword" , model = 24651} +models.main[18373] = { name = "Balin's Sword" , model = 24650} +models.main[18374] = { name = "Mighty Sword" , model = 24646} +models.main[18375] = { name = "Falx" , model = 24928} +models.main[18376] = { name = "Falx +1" , model = 24928} +models.main[18377] = { name = "Mercurial Sword" , model = 24646} +models.main[18378] = { name = "Subduer" , model = 24644} +models.main[18379] = { name = "Vulcan Claymore" , model = 24642} +models.main[18380] = { name = "Martial Sword" , model = 24646} +models.main[18381] = { name = "Prominence Sword" , model = 24647} +models.main[18382] = { name = "Darksteel Falx" , model = 24938} +models.main[18383] = { name = "Darksteel Falx +1" , model = 24938} +models.main[18384] = { name = "Lucent Sword" , model = 24647} +models.main[18385] = { name = "Algol" , model = 24953} +models.main[18386] = { name = "Gloom Claymore" , model = 24641} +models.main[18387] = { name = "Djinnbringer" , model = 24641} +models.main[18388] = { name = "Doombringer" , model = 24641} +models.main[18389] = { name = "Crude Sword" , model = 24647} +models.main[18390] = { name = "Templar Hammer" , model = 24689} +models.main[18391] = { name = "Sacred Mace" , model = 24683} +models.main[18392] = { name = "Sacred Maul" , model = 24692} +models.main[18393] = { name = "Sacred Wand" , model = 24804} +models.main[18394] = { name = "Pilgrim's Wand" , model = 24818} +models.main[18395] = { name = "Seawolf Cudgel" , model = 24676} +models.main[18396] = { name = "Sea Rob. Cudgel" , model = 24677} +models.main[18397] = { name = "Prudence Rod" , model = 24912} +models.main[18398] = { name = "Raphael's Rod" , model = 24816} +models.main[18399] = { name = "Charm Wand" , model = 24949} +models.main[18400] = { name = "Charm Wand +1" , model = 24949} +models.main[18401] = { name = "Moogle Rod" , model = 24950} +models.main[18402] = { name = "Mana Wand" , model = 24808} +models.main[18403] = { name = "High Mana Wand" , model = 24807} +models.main[18404] = { name = "Ramuh's Mace" , model = 24936} +models.main[18405] = { name = "Jadagna" , model = 24956} +models.main[18406] = { name = "Jadagna +1" , model = 24956} +models.main[18407] = { name = "Imperial Wand" , model = 24821} +models.main[18408] = { name = "Yigit Bulawa" , model = 24936} +models.main[18409] = { name = "Jadagna -1" , model = 24956} +models.main[18410] = { name = "Melt Katana" , model = 24886} +models.main[18411] = { name = "Buboso" , model = 24890} +models.main[18412] = { name = "Gassan" , model = 24888} +models.main[18413] = { name = "Hirenjaku" , model = 24947} +models.main[18414] = { name = "Hirenjaku +1" , model = 24947} +models.main[18415] = { name = "Tojaku" , model = 24947} +models.main[18416] = { name = "Karasuageha" , model = 24890} +models.main[18417] = { name = "Sayosamonji" , model = 24887} +models.main[18418] = { name = "Otori" , model = 24943} +models.main[18419] = { name = "Kugui" , model = 24943} +models.main[18420] = { name = "Hayabusa" , model = 24970} +models.main[18421] = { name = "Hayabusa +1" , model = 24970} +models.main[18422] = { name = "Ryumon" , model = 24965} +models.main[18423] = { name = "Izayoi" , model = 24976} +models.main[18424] = { name = "Izayoi +1" , model = 24976} +models.main[18425] = { name = "Perdu Blade" , model = 24970} +models.main[18426] = { name = "Sasuke Katana" , model = 24965} +models.main[18427] = { name = "Hanafubuki" , model = 24888} +models.main[18428] = { name = "Kogitsunemaru" , model = 24976} +models.main[18429] = { name = "Shusui" , model = 25015} +models.main[18430] = { name = "Oninohocho" , model = 25023} +models.main[18431] = { name = "Butachi" , model = 24720} +models.main[18432] = { name = "Butachi +1" , model = 24720} +models.main[18433] = { name = "Kagiroi" , model = 24720} +models.main[18434] = { name = "Kosetsusamonji" , model = 24723} +models.main[18435] = { name = "Hotarumaru" , model = 24722} +models.main[18436] = { name = "Lotus Katana" , model = 24944} +models.main[18437] = { name = "Namikirimaru" , model = 24732} +models.main[18438] = { name = "Kumokirimaru" , model = 24722} +models.main[18439] = { name = "Shirogatana" , model = 24968} +models.main[18440] = { name = "Shirogatana +1" , model = 24968} +models.main[18441] = { name = "Shinai" , model = 24979} +models.main[18442] = { name = "Taimakuniyuki +1" , model = 24968} +models.main[18443] = { name = "Windslicer" , model = 24732} +models.main[18444] = { name = "Tsurugitachi" , model = 24723} +models.main[18445] = { name = "Amakura" , model = 24724} +models.main[18446] = { name = "Pachipachio" , model = 25016} +models.main[18447] = { name = "Nanatsusaya" , model = 25019} +models.main[18448] = { name = "Hacchonenbutsu" , model = 24723} +models.main[18449] = { name = "Namioyogi" , model = 24722} +models.main[18450] = { name = "Mukademaru" , model = 24729} +models.main[18451] = { name = "Mokusa" , model = 24968} +models.main[18452] = { name = "Rindomaru" , model = 24727} +models.main[18453] = { name = "Unshomaru" , model = 24722} +models.main[18454] = { name = "Ishikirimaru" , model = 24723} +models.main[18455] = { name = "Ame-no-ohabari" , model = 24724} +models.main[18456] = { name = "Yoshihiro" , model = 24720} +models.main[18457] = { name = "Murasamemaru" , model = 25113} +models.main[18458] = { name = "Bizen-osafune" , model = 24731} +models.main[18459] = { name = "Heshikiri-hasebe" , model = 24727} +models.main[18460] = { name = "Kagotsurube" , model = 24720} +models.main[18461] = { name = "Nikko-ichimonji" , model = 24722} +models.main[18462] = { name = "Sasanuki" , model = 24731} +models.main[18463] = { name = "Sasanuki +1" , model = 24731} +models.main[18464] = { name = "Ark Tachi" , model = 25164} +models.main[18465] = { name = "Genjito" , model = 24724} +models.main[18466] = { name = "Tenkomaru" , model = 25178} +models.main[18481] = { name = "Lucent Axe" , model = 24670} +models.main[18482] = { name = "Amood" , model = 24952} +models.main[18483] = { name = "Amood +1" , model = 24952} +models.main[18484] = { name = "Wamoura Axe" , model = 24671} +models.main[18485] = { name = "Imperial Bhuj" , model = 24672} +models.main[18486] = { name = "Wardancer" , model = 24939} +models.main[18487] = { name = "Erik's Axe" , model = 24911} +models.main[18488] = { name = "Assailant's Axe" , model = 24670} +models.main[18489] = { name = "Dark Amood" , model = 24961} +models.main[18490] = { name = "Dark Amood +1" , model = 24961} +models.main[18491] = { name = "Perdu Voulge" , model = 24941} +models.main[18492] = { name = "Sturdy Axe" , model = 24939} +models.main[18493] = { name = "Regiment Kheten" , model = 24673} +models.main[18494] = { name = "Fourth Toporok" , model = 24668} +models.main[18495] = { name = "Wootz Amood" , model = 24982} +models.main[18496] = { name = "Wootz Amood +1" , model = 24982} +models.main[18497] = { name = "Foolkiller" , model = 25010} +models.main[18498] = { name = "Balestarius" , model = 25024} +models.main[18499] = { name = "Alastor" , model = 24940} +models.main[18500] = { name = "Sparth" , model = 25024} +models.main[18501] = { name = "Seismic Axe" , model = 24674} +models.main[18502] = { name = "Trainee Axe" , model = 24924} +models.main[18503] = { name = "Mammut" , model = 24674} +models.main[18504] = { name = "Eventreuse" , model = 25027} +models.main[18505] = { name = "Erlking's Kheten" , model = 24673} +models.main[18506] = { name = "Tewhatewha" , model = 24924} +models.main[18507] = { name = "Kinship Axe" , model = 24670} +models.main[18508] = { name = "Lyft Voulge" , model = 24940} +models.main[18509] = { name = "Tewhatewha+1" , model = 24924} +models.main[18510] = { name = "Vermeil Bhuj" , model = 25096} +models.main[18511] = { name = "Dolor Bhuj" , model = 24672} +models.main[18512] = { name = "Dolor Bhuj +1" , model = 24672} +models.main[18513] = { name = "Barbarus Bhuj" , model = 24672} +models.main[18514] = { name = "Magnus Toporok" , model = 24668} +models.main[18515] = { name = "Widowmaker" , model = 25027} +models.main[18516] = { name = "Warlord's Axe" , model = 24674} +models.main[18517] = { name = "Elephas Axe" , model = 24669} +models.main[18518] = { name = "Elephas Axe +1" , model = 24669} +models.main[18519] = { name = "Oneiros Axe" , model = 24669} +models.main[18520] = { name = "Laceratrice" , model = 24672} +models.main[18521] = { name = "Dies Irae" , model = 24924} +models.main[18522] = { name = "Firnaxe" , model = 24669} +models.main[18523] = { name = "Firnaxe +1" , model = 24669} +models.main[18524] = { name = "Huskarl Axe" , model = 25179} +models.main[18525] = { name = "Himthige" , model = 25179} +models.main[18531] = { name = "Veldt Axe +1" , model = 24653} +models.main[18532] = { name = "Cleofun Axe" , model = 24667} +models.main[18533] = { name = "Magnus Axe" , model = 24657} +models.main[18534] = { name = "Charmer's Merlin" , model = 24657} +models.main[18535] = { name = "Carabinier's Axe" , model = 24654} +models.main[18536] = { name = "Artio's Axe" , model = 24654} +models.main[18537] = { name = "Maiden Tabar" , model = 24658} +models.main[18538] = { name = "Maiden Tabar +1" , model = 24658} +models.main[18539] = { name = "Tonatiuh Axe" , model = 25167} +models.main[18540] = { name = "Barbican Axe" , model = 24665} +models.main[18541] = { name = "Tjukurrpa Axe" , model = 24658} +models.main[18542] = { name = "Aytanri" , model = 25167} +models.main[18543] = { name = "Breidox" , model = 24658} +models.main[18544] = { name = "Breidox +1" , model = 24658} +models.main[18545] = { name = "Ark Tabar" , model = 25163} +models.main[18546] = { name = "Gibbous Axe" , model = 25107} +models.main[18547] = { name = "Ravana's Axe" , model = 25176} +models.main[18551] = { name = "Twilight Scythe" , model = 25102} +models.main[18552] = { name = "Maleficus" , model = 24926} +models.main[18553] = { name = "Woeborn" , model = 24898} +models.main[18554] = { name = "Darklinn Scythe" , model = 24770} +models.main[18555] = { name = "Sectum Sickle" , model = 24969} +models.main[18556] = { name = "Sectum Sickle+1" , model = 24969} +models.main[18557] = { name = "Sortilege Scythe" , model = 24772} +models.main[18558] = { name = "Wroth Scythe" , model = 25172} +models.main[18559] = { name = "Void Scythe" , model = 24770} +models.main[18560] = { name = "Nirastamo" , model = 24942} +models.main[18561] = { name = "Yhatdhara" , model = 24775} +models.main[18562] = { name = "Yhatdhara +1" , model = 24775} +models.main[18563] = { name = "Ark Scythe" , model = 25162} +models.main[18564] = { name = "Devilish Scythe" , model = 24777} +models.main[18565] = { name = "Adflictio" , model = 25172} +models.main[18581] = { name = "Carbuncle's Pole" , model = 24875} +models.main[18582] = { name = "Yigit Staff" , model = 24871} +models.main[18583] = { name = "Imperial Pole" , model = 24879} +models.main[18584] = { name = "Astral Staff" , model = 24867} +models.main[18585] = { name = "Kinnara Pole" , model = 24937} +models.main[18586] = { name = "Flexible Pole" , model = 24876} +models.main[18587] = { name = "Dryad Staff" , model = 24868} +models.main[18588] = { name = "Perdu Staff" , model = 24917} +models.main[18589] = { name = "Mage's Staff" , model = 24865} +models.main[18590] = { name = "Scepter Staff" , model = 24877} +models.main[18591] = { name = "Pastoral Staff" , model = 24872} +models.main[18592] = { name = "Elder Staff" , model = 24870} +models.main[18593] = { name = "Alkalurops" , model = 25014} +models.main[18594] = { name = "Dorje" , model = 25018} +models.main[18595] = { name = "Mekki Shakki" , model = 25017} +models.main[18596] = { name = "Kebbie" , model = 24867} +models.main[18597] = { name = "Catalyst" , model = 24882} +models.main[18598] = { name = "Prester" , model = 25014} +models.main[18599] = { name = "Pestle" , model = 24872} +models.main[18600] = { name = "Caver's Shovel" , model = 25031} +models.main[18601] = { name = "Fay Crozier" , model = 24900} +models.main[18602] = { name = "Fay Staff" , model = 24870} +models.main[18603] = { name = "Majestas" , model = 25038} +models.main[18604] = { name = "Astaroth Cane" , model = 24866} +models.main[18605] = { name = "Melampus Staff" , model = 24865} +models.main[18606] = { name = "Passaddhi Staff" , model = 24868} +models.main[18607] = { name = "Ceres' Spica" , model = 24869} +models.main[18608] = { name = "Atesh Pole" , model = 24872} +models.main[18609] = { name = "Lyft Pole" , model = 24879} +models.main[18610] = { name = "Spiro Staff" , model = 24870} +models.main[18611] = { name = "Qi Staff" , model = 24869} +models.main[18612] = { name = "Ram Staff" , model = 24931} +models.main[18613] = { name = "Fourth Staff" , model = 24933} +models.main[18614] = { name = "Cobra Staff" , model = 24932} +models.main[18615] = { name = "Passaddhi Staff +1" , model = 24868} +models.main[18616] = { name = "Qi Staff +1" , model = 24869} +models.main[18617] = { name = "Cracked Staff" , model = 24868} +models.main[18618] = { name = "Samudra" , model = 24871} +models.main[18619] = { name = "Chthonic Staff" , model = 24871} +models.main[18620] = { name = "Magnus Pole" , model = 24879} +models.main[18621] = { name = "Warmage's Pole" , model = 24872} +models.main[18622] = { name = "Warmage's Pole +1" , model = 24872} +models.main[18623] = { name = "Chtonic Staff" , model = 24869} +models.main[18624] = { name = "Numen Staff" , model = 24867} +models.main[18625] = { name = "Gerra's Staff" , model = 24905} +models.main[18626] = { name = "Plenitas Virga" , model = 25159} +models.main[18627] = { name = "Bryoja's Staff" , model = 24917} +models.main[18628] = { name = "Flete Pole" , model = 24872} +models.main[18629] = { name = "Flete Pole +1" , model = 24872} +models.main[18630] = { name = "Nathushne" , model = 24868} +models.main[18631] = { name = "Nathushne +1" , model = 24868} +models.main[18632] = { name = "Iridal Staff" , model = 25177} +models.main[18633] = { name = "Chatoyant Staff" , model = 25177} +models.main[18634] = { name = "Zamzummim Staff" , model = 25180} +models.main[18635] = { name = "Melisseus Staff" , model = 25180} +models.main[18637] = { name = "Spharai" , model = 25087} +models.main[18638] = { name = "Mandau" , model = 24910} +models.main[18639] = { name = "Excalibur" , model = 24896} +models.main[18640] = { name = "Ragnarok" , model = 24895} +models.main[18641] = { name = "Guttler" , model = 24923} +models.main[18642] = { name = "Bravura" , model = 24915} +models.main[18643] = { name = "Gungnir" , model = 24793} +models.main[18644] = { name = "Apocalypse" , model = 24914} +models.main[18645] = { name = "Kikoku" , model = 24920} +models.main[18646] = { name = "Amanomurakumo" , model = 24916} +models.main[18647] = { name = "Mjollnir" , model = 24883} +models.main[18648] = { name = "Claustrum" , model = 24918} +models.main[18651] = { name = "Spharai" , model = 25087} +models.main[18652] = { name = "Mandau" , model = 24910} +models.main[18653] = { name = "Excalibur" , model = 24896} +models.main[18654] = { name = "Ragnarok" , model = 24895} +models.main[18655] = { name = "Guttler" , model = 24923} +models.main[18656] = { name = "Bravura" , model = 24915} +models.main[18657] = { name = "Gungnir" , model = 24793} +models.main[18658] = { name = "Apocalypse" , model = 24914} +models.main[18659] = { name = "Kikoku" , model = 24910} +models.main[18660] = { name = "Amanomurakumo" , model = 24916} +models.main[18661] = { name = "Mjollnir" , model = 24883} +models.main[18662] = { name = "Claustrum" , model = 24918} +models.main[18665] = { name = "Spharai" , model = 25087} +models.main[18666] = { name = "Mandau" , model = 24910} +models.main[18667] = { name = "Excalibur" , model = 24896} +models.main[18668] = { name = "Ragnarok" , model = 24895} +models.main[18669] = { name = "Guttler" , model = 24923} +models.main[18670] = { name = "Bravura" , model = 24915} +models.main[18671] = { name = "Gungnir" , model = 24793} +models.main[18672] = { name = "Apocalypse" , model = 24914} +models.main[18673] = { name = "Kikoku" , model = 24920} +models.main[18674] = { name = "Amanomurakumo" , model = 24916} +models.main[18675] = { name = "Mjollnir" , model = 24883} +models.main[18676] = { name = "Claustrum" , model = 24918} +models.main[18741] = { name = "Scogan's Knuckles" , model = 24709} +models.main[18742] = { name = "Puppet Claws" , model = 24700} +models.main[18743] = { name = "Darksteel Sainti" , model = 25084} +models.main[18744] = { name = "Dst. Sainti +1" , model = 25084} +models.main[18745] = { name = "Adaman Sainti" , model = 25082} +models.main[18746] = { name = "Gem Sainti" , model = 25082} +models.main[18747] = { name = "Smash Cesti" , model = 24703} +models.main[18748] = { name = "Hades Sainti" , model = 25083} +models.main[18749] = { name = "Hades Sainti +1" , model = 25083} +models.main[18750] = { name = "Black Adargas" , model = 25081} +models.main[18751] = { name = "Black Adargas +1" , model = 25081} +models.main[18752] = { name = "Retaliators" , model = 24705} +models.main[18753] = { name = "Burning Fists" , model = 24710} +models.main[18754] = { name = "Inferno Claws" , model = 25084} +models.main[18755] = { name = "Noble Himantes" , model = 24703} +models.main[18756] = { name = "Cobra Baghnakhs" , model = 24718} +models.main[18757] = { name = "Gnole Sainti" , model = 25080} +models.main[18758] = { name = "Gnole Sainti +1" , model = 25080} +models.main[18759] = { name = "Shlng. Baghnakhs" , model = 25077} +models.main[18760] = { name = "Useshi" , model = 24704} +models.main[18761] = { name = "Acantha Shavers" , model = 25085} +models.main[18762] = { name = "Custodes" , model = 25081} +models.main[18763] = { name = "Trainee Scissors" , model = 24695} +models.main[18764] = { name = "Oberon's Knuckles" , model = 24710} +models.main[18765] = { name = "Oberon's Sainti" , model = 25084} +models.main[18766] = { name = "Tyro Katars" , model = 24695} +models.main[18767] = { name = "Birdbanes" , model = 24695} +models.main[18768] = { name = "Poppet Katars" , model = 24695} +models.main[18769] = { name = "Severus Claws" , model = 24699} +models.main[18770] = { name = "Pygme Sainti" , model = 25082} +models.main[18771] = { name = "Lyft Sainti" , model = 25080} +models.main[18772] = { name = "Tyro Katars +1" , model = 24695} +models.main[18773] = { name = "Severus Claws +1" , model = 24699} +models.main[18774] = { name = "Savate Fists" , model = 25082} +models.main[18775] = { name = "Savate Fists +1" , model = 25082} +models.main[18776] = { name = "Heofon Knuckles" , model = 24711} +models.main[18777] = { name = "Magnus Sainti" , model = 25082} +models.main[18778] = { name = "Marotte Claws" , model = 24697} +models.main[18779] = { name = "Taurine Cesti" , model = 24702} +models.main[18780] = { name = "Burattinaios" , model = 25085} +models.main[18781] = { name = "Furor Cesti" , model = 24703} +models.main[18782] = { name = "Eyra Baghnakhs" , model = 24716} +models.main[18783] = { name = "Eyra Baghnakhs +1" , model = 24716} +models.main[18784] = { name = "Metasoma Katars" , model = 24694} +models.main[18785] = { name = "Grotesque Cesti" , model = 24704} +models.main[18786] = { name = "Girru" , model = 25074} +models.main[18787] = { name = "Shara's Fists" , model = 24710} +models.main[18788] = { name = "Brawny Adargas" , model = 25081} +models.main[18789] = { name = "Marath Baghnakhs" , model = 24718} +models.main[18790] = { name = "Shivaji Baghnakhs" , model = 24718} +models.main[18791] = { name = "Buzbaz Sainti" , model = 25085} +models.main[18792] = { name = "Buzbaz Sainti +1" , model = 25085} +models.main[18793] = { name = "Blutkrallen" , model = 25069} +models.main[18794] = { name = "Blutklauen" , model = 25069} +models.main[18827] = { name = "Oxossi Facon" , model = 25173} +models.main[18828] = { name = "Oxossi Facon +1" , model = 25173} +models.main[18829] = { name = "Blustery Dagger" , model = 24751} +models.main[18830] = { name = "Gusterion" , model = 24751} +models.main[18841] = { name = "Templar Mace" , model = 24681} +models.main[18842] = { name = "Nmd. Moogle Rod" , model = 24959} +models.main[18843] = { name = "Flan Smasher" , model = 24679} +models.main[18844] = { name = "Miracle Wand" , model = 24949} +models.main[18845] = { name = "Miracle Wand +1" , model = 24949} +models.main[18846] = { name = "Battledore" , model = 24973} +models.main[18847] = { name = "Seveneyes" , model = 24935} +models.main[18848] = { name = "Brass Jadagna" , model = 24977} +models.main[18849] = { name = "Brass Jadagna +1" , model = 24977} +models.main[18850] = { name = "Perdu Wand" , model = 24804} +models.main[18851] = { name = "Werebuster" , model = 24687} +models.main[18852] = { name = "Octave Club" , model = 24686} +models.main[18853] = { name = "Spirit Maul" , model = 24692} +models.main[18854] = { name = "Fourth Mace" , model = 24681} +models.main[18855] = { name = "Trainee Hammer" , model = 24691} +models.main[18856] = { name = "Deae Gratia" , model = 24678} +models.main[18857] = { name = "Antares" , model = 25013} +models.main[18858] = { name = "Flanged Mace" , model = 25022} +models.main[18859] = { name = "Kerykeion" , model = 24809} +models.main[18860] = { name = "Flanged Mace +1" , model = 25022} +models.main[18861] = { name = "Grandeur" , model = 24817} +models.main[18862] = { name = "Clearpath" , model = 24799} +models.main[18863] = { name = "Dream Bell" , model = 25025} +models.main[18864] = { name = "Dream Bell +1" , model = 25025} +models.main[18865] = { name = "Zonure" , model = 24936} +models.main[18866] = { name = "Club Hammer" , model = 25030} +models.main[18867] = { name = "Daedalus Hammer" , model = 24689} +models.main[18868] = { name = "Lady Bell" , model = 25032} +models.main[18869] = { name = "Lady Bell +1" , model = 25032} +models.main[18870] = { name = "Dweomer Maul" , model = 24688} +models.main[18871] = { name = "Kitty Rod" , model = 24816} +models.main[18872] = { name = "Lyft Ferule" , model = 24804} +models.main[18873] = { name = "Brise-os" , model = 24977} +models.main[18874] = { name = "Brise-os +1" , model = 24977} +models.main[18875] = { name = "Vodun Mace" , model = 24679} +models.main[18876] = { name = "Vodun Mace +1" , model = 24679} +models.main[18877] = { name = "Robur Mace" , model = 24679} +models.main[18878] = { name = "Robur Mace +1" , model = 24679} +models.main[18879] = { name = "Rounsey Wand" , model = 25111} +models.main[18880] = { name = "Maestro's Baton" , model = 25115} +models.main[18881] = { name = "Melomane Mallet" , model = 25116} +models.main[18882] = { name = "Beaivi's Scepter" , model = 24797} +models.main[18883] = { name = "Luckitoo" , model = 24936} +models.main[18884] = { name = "Vejovis Wand" , model = 24801} +models.main[18885] = { name = "Vejovis Wand +1" , model = 24801} +models.main[18886] = { name = "Dhyana Rod" , model = 25171} +models.main[18887] = { name = "Dukkha" , model = 25171} +models.main[18888] = { name = "Ankylosis Wand" , model = 25175} +models.main[18891] = { name = "Hannibal's Sword" , model = 24861} +models.main[18892] = { name = "Corbenic Sword" , model = 24845} +models.main[18893] = { name = "Magnus Sword" , model = 24849} +models.main[18894] = { name = "Accolade Sword" , model = 24857} +models.main[18895] = { name = "Chimeric Fleuret" , model = 24769} +models.main[18896] = { name = "Honorbound" , model = 24966} +models.main[18897] = { name = "Isador" , model = 24978} +models.main[18898] = { name = "Mageblade" , model = 24843} +models.main[18899] = { name = "Runic Anelace" , model = 24850} +models.main[18900] = { name = "Skeld Sword" , model = 24857} +models.main[18901] = { name = "Falcata" , model = 24845} +models.main[18902] = { name = "Falcata +1" , model = 24845} +models.main[18903] = { name = "Talekeeper" , model = 25104} +models.main[18904] = { name = "Ephemeron" , model = 25114} +models.main[18905] = { name = "Swiftwing" , model = 24864} +models.main[18906] = { name = "Galenus" , model = 24842} +models.main[18907] = { name = "Devourer" , model = 24863} +models.main[18908] = { name = "Dhampyr Sword" , model = 24851} +models.main[18909] = { name = "Sanus Ensis" , model = 25158} +models.main[18910] = { name = "Apaisante" , model = 24842} +models.main[18911] = { name = "Apaisante +1" , model = 24842} +models.main[18912] = { name = "Ark Saber" , model = 25160} +models.main[18913] = { name = "Ark Sword" , model = 25161} +models.main[18914] = { name = "Killer's Kilij" , model = 24960} +models.main[18915] = { name = "Eradicator's Kilij" , model = 24960} +models.main[18916] = { name = "Heimdall's Doom" , model = 24980} +models.main[18921] = { name = "Taiaha" , model = 24874} +models.main[18922] = { name = "Yantok" , model = 24872} +models.main[18923] = { name = "Shareeravadi" , model = 24871} +models.main[18924] = { name = "Agni's Staff" , model = 24881} +models.main[18925] = { name = "Varuna's Staff" , model = 24881} +models.main[18926] = { name = "Vayu's Staff" , model = 24881} +models.main[18927] = { name = "Kubera's Staff" , model = 24881} +models.main[18928] = { name = "Indra's Staff" , model = 24881} +models.main[18929] = { name = "Soma's Staff" , model = 24881} +models.main[18930] = { name = "Surya's Staff" , model = 24881} +models.main[18931] = { name = "Yama's Staff" , model = 24881} +models.main[18932] = { name = "Sedikutchi" , model = 24879} +models.main[18941] = { name = "Naigama" , model = 24969} +models.main[18942] = { name = "Naigama +1" , model = 24969} +models.main[18943] = { name = "Perdu Sickle" , model = 24969} +models.main[18944] = { name = "Death Sickle" , model = 24926} +models.main[18945] = { name = "Jet Sickle" , model = 24926} +models.main[18946] = { name = "Fourth Zaghnal" , model = 24921} +models.main[18947] = { name = "Moliones's Sickle" , model = 24942} +models.main[18948] = { name = "Enforcer" , model = 25011} +models.main[18949] = { name = "Zareehkl Scythe" , model = 24948} +models.main[18950] = { name = "White Joker" , model = 24942} +models.main[18951] = { name = "Vendetta" , model = 24770} +models.main[18952] = { name = "Faucheuse" , model = 24777} +models.main[18953] = { name = "Beluga" , model = 24942} +models.main[18954] = { name = "Ogre Sickle" , model = 24926} +models.main[18955] = { name = "Dweomer Scythe" , model = 24777} +models.main[18956] = { name = "Serpette" , model = 24898} +models.main[18957] = { name = "Smiting Scythe" , model = 24772} +models.main[18958] = { name = "Lyft Scythe" , model = 24771} +models.main[18959] = { name = "Serpette +1" , model = 24898} +models.main[18960] = { name = "Smiting Scythe +1" , model = 24772} +models.main[18961] = { name = "Plaga Scythe" , model = 25097} +models.main[18962] = { name = "Rusty Zaghnal" , model = 24773} +models.main[18963] = { name = "Gleaming Zaghnal" , model = 24775} +models.main[18964] = { name = "Dire Scythe" , model = 24770} +models.main[18965] = { name = "Dire Scythe +1" , model = 24770} +models.main[18966] = { name = "Crisis Scythe" , model = 24898} +models.main[18967] = { name = "Magnus Scythe" , model = 24948} +models.main[18968] = { name = "Bounty Sickle" , model = 24926} +models.main[18969] = { name = "Terpsichore" , model = 25004} +models.main[18970] = { name = "Tupsimati" , model = 25005} +models.main[18971] = { name = "Conqueror" , model = 24990} +models.main[18972] = { name = "Glanzfaust" , model = 25078} +models.main[18973] = { name = "Yagrush" , model = 24991} +models.main[18974] = { name = "Laevateinn" , model = 24992} +models.main[18975] = { name = "Murgleis" , model = 24996} +models.main[18976] = { name = "Vajra" , model = 24998} +models.main[18977] = { name = "Burtgang" , model = 25002} +models.main[18978] = { name = "Liberator" , model = 25001} +models.main[18979] = { name = "Aymur" , model = 24989} +models.main[18980] = { name = "Carnwenhan" , model = 25003} +models.main[18982] = { name = "Kogarasumaru" , model = 25000} +models.main[18983] = { name = "Nagi" , model = 24997} +models.main[18984] = { name = "Ryunohige" , model = 24999} +models.main[18985] = { name = "Nirvana" , model = 24993} +models.main[18986] = { name = "Tizona" , model = 24995} +models.main[18988] = { name = "Kenkonken" , model = 25079} +models.main[18989] = { name = "Terpsichore" , model = 25004} +models.main[18990] = { name = "Tupsimati" , model = 25005} +models.main[18991] = { name = "Conqueror" , model = 24990} +models.main[18992] = { name = "Glanzfaust" , model = 25078} +models.main[18993] = { name = "Yagrush" , model = 24991} +models.main[18994] = { name = "Laevateinn" , model = 24992} +models.main[18995] = { name = "Murgleis" , model = 24996} +models.main[18996] = { name = "Vajra" , model = 24998} +models.main[18997] = { name = "Burtgang" , model = 25002} +models.main[18998] = { name = "Liberator" , model = 25001} +models.main[18999] = { name = "Aymur" , model = 24989} +models.main[19000] = { name = "Carnwenhan" , model = 25003} +models.main[19002] = { name = "Kogarasumaru" , model = 25000} +models.main[19003] = { name = "Nagi" , model = 24997} +models.main[19004] = { name = "Ryunohige" , model = 24999} +models.main[19005] = { name = "Nirvana" , model = 24993} +models.main[19006] = { name = "Tizona" , model = 24995} +models.main[19008] = { name = "Kenkonken" , model = 25079} +models.main[19060] = { name = "Conqueror" , model = 24990} +models.main[19061] = { name = "Glanzfaust" , model = 25078} +models.main[19062] = { name = "Yagrush" , model = 24991} +models.main[19063] = { name = "Laevateinn" , model = 24992} +models.main[19064] = { name = "Murgleis" , model = 24996} +models.main[19065] = { name = "Vajra" , model = 24998} +models.main[19066] = { name = "Burtgang" , model = 25002} +models.main[19067] = { name = "Liberator" , model = 25001} +models.main[19068] = { name = "Aymur" , model = 24989} +models.main[19069] = { name = "Carnwenhan" , model = 25003} +models.main[19071] = { name = "Kogarasumaru" , model = 25000} +models.main[19072] = { name = "Nagi" , model = 24997} +models.main[19073] = { name = "Ryunohige" , model = 24999} +models.main[19074] = { name = "Nirvana" , model = 24993} +models.main[19075] = { name = "Tizona" , model = 24995} +models.main[19077] = { name = "Kenkonken" , model = 25079} +models.main[19078] = { name = "Terpsichore" , model = 25004} +models.main[19079] = { name = "Tupsimati" , model = 25005} +models.main[19080] = { name = "Conqueror" , model = 24990} +models.main[19081] = { name = "Glanzfaust" , model = 25078} +models.main[19082] = { name = "Yagrush" , model = 24991} +models.main[19083] = { name = "Laevateinn" , model = 24992} +models.main[19084] = { name = "Murgleis" , model = 24996} +models.main[19085] = { name = "Vajra" , model = 24998} +models.main[19086] = { name = "Burtgang" , model = 25002} +models.main[19087] = { name = "Liberator" , model = 25001} +models.main[19088] = { name = "Aymur" , model = 24989} +models.main[19089] = { name = "Carnwenhan" , model = 25003} +models.main[19091] = { name = "Kogarasumaru" , model = 25000} +models.main[19092] = { name = "Nagi" , model = 24997} +models.main[19093] = { name = "Ryunohige" , model = 24999} +models.main[19094] = { name = "Nirvana" , model = 24993} +models.main[19095] = { name = "Tizona" , model = 24995} +models.main[19097] = { name = "Kenkonken" , model = 25079} +models.main[19098] = { name = "Terpsichore" , model = 25004} +models.main[19099] = { name = "Tupsimati" , model = 25005} +models.main[19100] = { name = "Cobra Knife" , model = 24756} +models.main[19101] = { name = "Trainee Knife" , model = 24893} +models.main[19102] = { name = "Main Gauche" , model = 24752} +models.main[19103] = { name = "Darksteel Jambiya" , model = 24985} +models.main[19104] = { name = "Dst. Jambiya +1" , model = 24985} +models.main[19105] = { name = "Thug's Jambiya" , model = 24955} +models.main[19106] = { name = "Thug's Jambiya +1" , model = 24955} +models.main[19107] = { name = "Azoth" , model = 25006} +models.main[19108] = { name = "Zareehkl Jambiya" , model = 24985} +models.main[19109] = { name = "Trilling Dagger" , model = 24744} +models.main[19110] = { name = "Trainee's Needle" , model = 24745} +models.main[19111] = { name = "Silktone" , model = 24744} +models.main[19112] = { name = "Farseer" , model = 24744} +models.main[19113] = { name = "Ermine's Tail" , model = 25026} +models.main[19114] = { name = "Galkan Dagger" , model = 24744} +models.main[19115] = { name = "Fane Baselard" , model = 24744} +models.main[19116] = { name = "Dweomer Knife" , model = 24734} +models.main[19117] = { name = "Ogre Jambiya" , model = 24985} +models.main[19118] = { name = "Machismo" , model = 25035} +models.main[19119] = { name = "Ranging Knife" , model = 24756} +models.main[19120] = { name = "Avis" , model = 24986} +models.main[19121] = { name = "Sleight Kukri" , model = 24750} +models.main[19122] = { name = "Courser's Pugio" , model = 24738} +models.main[19123] = { name = "Cinquedea" , model = 24734} +models.main[19124] = { name = "Creve-coeur" , model = 24955} +models.main[19125] = { name = "Lyft Jambiya" , model = 24955} +models.main[19126] = { name = "Papilio Kirpan" , model = 24985} +models.main[19127] = { name = "Ranging Knife +1" , model = 24756} +models.main[19128] = { name = "Edgeless Knife" , model = 24736} +models.main[19129] = { name = "Rapidus Sax" , model = 24755} +models.main[19130] = { name = "Clement Skean" , model = 24739} +models.main[19131] = { name = "Magnus Dagger" , model = 24739} +models.main[19132] = { name = "Twilight Knife" , model = 25103} +models.main[19133] = { name = "Triplus Dagger" , model = 24753} +models.main[19134] = { name = "Felibre's Dague" , model = 24734} +models.main[19135] = { name = "Acinaces" , model = 24955} +models.main[19136] = { name = "Phurba" , model = 24738} +models.main[19137] = { name = "Angr Harpe" , model = 24930} +models.main[19138] = { name = "Verus Knife" , model = 24734} +models.main[19139] = { name = "Verus Knife +1" , model = 24734} +models.main[19140] = { name = "Mantodea Harpe" , model = 25109} +models.main[19141] = { name = "Oneiros Knife" , model = 24734} +models.main[19142] = { name = "Gnadgott" , model = 24744} +models.main[19143] = { name = "Lux Pugio" , model = 25110} +models.main[19144] = { name = "Coruscanti" , model = 25112} +models.main[19145] = { name = "Asteria" , model = 25117} +models.main[19146] = { name = "Supernal Knife" , model = 24971} +models.main[19147] = { name = "Janamaraka" , model = 24955} +models.main[19148] = { name = "Pugiunculus" , model = 24744} +models.main[19149] = { name = "Strategema Knife" , model = 24733} +models.main[19150] = { name = "Cobra Claymore" , model = 24642} +models.main[19151] = { name = "Bahadur" , model = 24983} +models.main[19152] = { name = "Bahadur +1" , model = 24983} +models.main[19153] = { name = "Naglering" , model = 25008} +models.main[19154] = { name = "Ferrara" , model = 24928} +models.main[19155] = { name = "Cruadin" , model = 24650} +models.main[19156] = { name = "Balisarde" , model = 24647} +models.main[19157] = { name = "Surviver" , model = 24643} +models.main[19158] = { name = "Scheherazade" , model = 24939} +models.main[19159] = { name = "Galatyn" , model = 25039} +models.main[19160] = { name = "Estramacon" , model = 24642} +models.main[19161] = { name = "Lyft Claymore" , model = 24640} +models.main[19162] = { name = "Dull Claymore" , model = 24643} +models.main[19163] = { name = "Nightfall" , model = 25040} +models.main[19164] = { name = "Ferus Algol" , model = 25101} +models.main[19165] = { name = "Cratus Sword" , model = 24649} +models.main[19166] = { name = "Cratus Sword +1" , model = 24649} +models.main[19167] = { name = "Khloros Blade" , model = 24640} +models.main[19168] = { name = "Magnus Claymore" , model = 24641} +models.main[19169] = { name = "Kriegsmesser" , model = 24640} +models.main[19170] = { name = "Kardia Faussar" , model = 24650} +models.main[19171] = { name = "Kardia Faussar +1" , model = 24650} +models.main[19172] = { name = "Jing. Greatsword" , model = 25105} +models.main[19173] = { name = "Gram" , model = 24897} +models.main[19174] = { name = "Borealis" , model = 25119} +models.main[19175] = { name = "Hoarfrost Blade" , model = 25118} +models.main[19176] = { name = "Irasya" , model = 24641} +models.main[19177] = { name = "Etourdissante" , model = 24646} +models.main[19178] = { name = "Etourdissante +1" , model = 24646} +models.main[19179] = { name = "Dervish Sword" , model = 25174} +models.main[19271] = { name = "Osoraku" , model = 24889} +models.main[19272] = { name = "Yagentoshiro" , model = 24888} +models.main[19273] = { name = "Onishibari" , model = 24970} +models.main[19274] = { name = "Trainee Burin" , model = 24891} +models.main[19275] = { name = "Tsukumo" , model = 24890} +models.main[19276] = { name = "Midare" , model = 24888} +models.main[19277] = { name = "Tsugumi" , model = 24891} +models.main[19278] = { name = "Fuchingiri" , model = 24885} +models.main[19279] = { name = "Musanto" , model = 24887} +models.main[19280] = { name = "Narigitsune" , model = 24885} +models.main[19281] = { name = "Midare +1" , model = 24888} +models.main[19282] = { name = "Hochomasamune" , model = 25098} +models.main[19283] = { name = "Rusty Kunai" , model = 24891} +models.main[19284] = { name = "Hiwa" , model = 24890} +models.main[19285] = { name = "Kakko" , model = 24976} +models.main[19286] = { name = "Kakko +1" , model = 24976} +models.main[19287] = { name = "Kamome" , model = 24890} +models.main[19288] = { name = "Sekirei" , model = 24888} +models.main[19289] = { name = "Toki" , model = 24886} +models.main[19290] = { name = "Aizenkunitoshi" , model = 24889} +models.main[19291] = { name = "Oirandori" , model = 24970} +models.main[19292] = { name = "Kogara" , model = 24890} +models.main[19293] = { name = "Ichi-an" , model = 24888} +models.main[19294] = { name = "Ichi-an +1" , model = 24888} +models.main[19295] = { name = "Mujin Tanto" , model = 24889} +models.main[19296] = { name = "Ban" , model = 24891} +models.main[19297] = { name = "Kakesu" , model = 24889} +models.main[19298] = { name = "Ikarigiri" , model = 25165} +models.main[19299] = { name = "Aisa" , model = 24889} +models.main[19300] = { name = "Aisa +1" , model = 24889} +models.main[19301] = { name = "Kawasemi" , model = 24976} +models.main[19302] = { name = "Uguisu" , model = 25181} +models.main[19303] = { name = "Fay Lance" , model = 24785} +models.main[19304] = { name = "Sarissa" , model = 25037} +models.main[19305] = { name = "Pike" , model = 24786} +models.main[19306] = { name = "Lyft Lance" , model = 24788} +models.main[19307] = { name = "Blunt Lance" , model = 24787} +models.main[19308] = { name = "Rusty Spear" , model = 24781} +models.main[19309] = { name = "Gleaming Spear" , model = 24780} +models.main[19310] = { name = "Guisarme" , model = 24946} +models.main[19311] = { name = "Guisarme +1" , model = 24946} +models.main[19312] = { name = "Skogul Lance" , model = 24786} +models.main[19313] = { name = "Magnus Lance" , model = 24786} +models.main[19314] = { name = "Quint Spear" , model = 24779} +models.main[19315] = { name = "Erebus's Lance" , model = 24925} +models.main[19316] = { name = "Fetter Lance" , model = 24785} +models.main[19317] = { name = "Borian Spear" , model = 24780} +models.main[19318] = { name = "Borian Spear +1" , model = 24780} +models.main[19327] = { name = "Pugilists" , model = 24706} +models.main[19328] = { name = "Simian Fists" , model = 24705} +models.main[19329] = { name = "Mantis" , model = 25085} +models.main[19330] = { name = "Wargfangs" , model = 24695} +models.main[19331] = { name = "Cat's Claws" , model = 24701} +models.main[19332] = { name = "Peeler" , model = 24735} +models.main[19333] = { name = "Renegade" , model = 24737} +models.main[19334] = { name = "Kartika" , model = 24986} +models.main[19335] = { name = "Athame" , model = 24752} +models.main[19336] = { name = "Dakini" , model = 24756} +models.main[19337] = { name = "Side-sword" , model = 24844} +models.main[19338] = { name = "Schiavona" , model = 24846} +models.main[19339] = { name = "Nobilis" , model = 24853} +models.main[19340] = { name = "Antea" , model = 24859} +models.main[19341] = { name = "Soulsaber" , model = 24829} +models.main[19342] = { name = "Break Blade" , model = 24647} +models.main[19343] = { name = "Sunblade" , model = 24648} +models.main[19344] = { name = "Albion" , model = 24646} +models.main[19345] = { name = "Salamand Sword" , model = 24650} +models.main[19346] = { name = "Brand d'Arcon" , model = 24641} +models.main[19347] = { name = "Chopper" , model = 24667} +models.main[19348] = { name = "Splinter" , model = 24659} +models.main[19349] = { name = "Bonebiter" , model = 24658} +models.main[19350] = { name = "Punisher" , model = 24664} +models.main[19351] = { name = "Skeggiold" , model = 24654} +models.main[19352] = { name = "Lumberjack" , model = 24669} +models.main[19353] = { name = "Sagaris" , model = 24671} +models.main[19354] = { name = "Bonesplitter" , model = 24669} +models.main[19355] = { name = "Luchtaine" , model = 24674} +models.main[19356] = { name = "Hephaestus" , model = 24924} +models.main[19357] = { name = "Farmhand" , model = 24771} +models.main[19358] = { name = "Stigma" , model = 24772} +models.main[19359] = { name = "Ultimatum" , model = 24770} +models.main[19360] = { name = "Vengeance" , model = 24926} +models.main[19361] = { name = "Severance" , model = 24898} +models.main[19362] = { name = "Ranseur" , model = 24786} +models.main[19363] = { name = "Copperhead" , model = 24787} +models.main[19364] = { name = "Oathkeeper" , model = 24785} +models.main[19365] = { name = "Bradamante" , model = 24925} +models.main[19366] = { name = "Stribog" , model = 24789} +models.main[19367] = { name = "Kibashiri" , model = 24886} +models.main[19368] = { name = "Koruri" , model = 24888} +models.main[19369] = { name = "Mozu" , model = 24889} +models.main[19370] = { name = "Isatu" , model = 24943} +models.main[19371] = { name = "Kuina" , model = 24888} +models.main[19372] = { name = "Donto" , model = 24722} +models.main[19373] = { name = "Shirodachi" , model = 24721} +models.main[19374] = { name = "Radennotachi" , model = 24899} +models.main[19375] = { name = "Kurodachi" , model = 24724} +models.main[19376] = { name = "Efunotachi" , model = 24723} +models.main[19377] = { name = "Stenz" , model = 24689} +models.main[19378] = { name = "Rageblow" , model = 24691} +models.main[19379] = { name = "Culacula" , model = 24692} +models.main[19380] = { name = "Goedendag" , model = 24679} +models.main[19381] = { name = "Ingrimm" , model = 24819} +models.main[19382] = { name = "Crook" , model = 24880} +models.main[19383] = { name = "Shillelagh" , model = 24875} +models.main[19384] = { name = "Slaine" , model = 24874} +models.main[19385] = { name = "Danda" , model = 24872} +models.main[19386] = { name = "Teiwaz" , model = 24866} +models.main[19397] = { name = "Verethragna" , model = 25076} +models.main[19398] = { name = "Twashtar" , model = 25041} +models.main[19399] = { name = "Almace" , model = 25042} +models.main[19400] = { name = "Caladbolg" , model = 25043} +models.main[19401] = { name = "Farsha" , model = 25044} +models.main[19402] = { name = "Ukonvasara" , model = 25045} +models.main[19403] = { name = "Redemption" , model = 25046} +models.main[19404] = { name = "Rhongomiant" , model = 25088} +models.main[19405] = { name = "Kannagi" , model = 25089} +models.main[19406] = { name = "Masamune" , model = 25090} +models.main[19407] = { name = "Gambanteinn" , model = 25091} +models.main[19408] = { name = "Hvergelmir" , model = 25092} +models.main[19412] = { name = "Revenant Fists" , model = 25085} +models.main[19413] = { name = "Ursine Claws" , model = 24695} +models.main[19414] = { name = "Taipan Fangs" , model = 24701} +models.main[19415] = { name = "Barracudas" , model = 24716} +models.main[19416] = { name = "Daka" , model = 24955} +models.main[19417] = { name = "Parazonium" , model = 24752} +models.main[19418] = { name = "Kila" , model = 24756} +models.main[19419] = { name = "Fusetto" , model = 24744} +models.main[19420] = { name = "Badelaire" , model = 24853} +models.main[19421] = { name = "Khanda" , model = 24859} +models.main[19422] = { name = "Shamshir" , model = 24829} +models.main[19423] = { name = "Machaera" , model = 24957} +models.main[19424] = { name = "Espafut" , model = 24646} +models.main[19425] = { name = "Prestelame" , model = 24650} +models.main[19426] = { name = "Sombrelame" , model = 24641} +models.main[19427] = { name = "Kalavejs" , model = 24644} +models.main[19428] = { name = "Alard's Axe" , model = 24658} +models.main[19429] = { name = "Richardet's Axe" , model = 24664} +models.main[19430] = { name = "Guichard's Axe" , model = 24654} +models.main[19431] = { name = "Renaud's Axe" , model = 24654} +models.main[19432] = { name = "Maschu" , model = 24669} +models.main[19433] = { name = "Kunlun" , model = 24674} +models.main[19434] = { name = "Atlas" , model = 24924} +models.main[19435] = { name = "Sumeru" , model = 24672} +models.main[19436] = { name = "Penitence" , model = 24770} +models.main[19437] = { name = "Maleficence" , model = 24926} +models.main[19438] = { name = "Absolution" , model = 24898} +models.main[19439] = { name = "Reckoning" , model = 24942} +models.main[19440] = { name = "Cerastes" , model = 24785} +models.main[19441] = { name = "Corsesca" , model = 24925} +models.main[19442] = { name = "Langdebeve" , model = 24789} +models.main[19443] = { name = "Stingray" , model = 24954} +models.main[19444] = { name = "Tobi" , model = 24889} +models.main[19445] = { name = "Enchu" , model = 24943} +models.main[19446] = { name = "Sekka" , model = 24888} +models.main[19447] = { name = "Uzura" , model = 24886} +models.main[19448] = { name = "Hiradennotachi" , model = 24899} +models.main[19449] = { name = "Kokushitsunotachi" , model = 24724} +models.main[19450] = { name = "Hyogugusarinotachi" , model = 24723} +models.main[19451] = { name = "Keitonotachi" , model = 24721} +models.main[19452] = { name = "Canne de Combat" , model = 24692} +models.main[19453] = { name = "Naboot" , model = 24679} +models.main[19454] = { name = "Hoeroa" , model = 24820} +models.main[19455] = { name = "Makhila" , model = 24687} +models.main[19456] = { name = "Verethragna" , model = 25076} +models.main[19457] = { name = "Twashtar" , model = 25041} +models.main[19458] = { name = "Almace" , model = 25042} +models.main[19459] = { name = "Caladbolg" , model = 25043} +models.main[19460] = { name = "Farsha" , model = 25044} +models.main[19461] = { name = "Ukonvasara" , model = 25045} +models.main[19462] = { name = "Redemption" , model = 25046} +models.main[19463] = { name = "Rhongomiant" , model = 25088} +models.main[19464] = { name = "Kannagi" , model = 25089} +models.main[19465] = { name = "Masamune" , model = 25090} +models.main[19466] = { name = "Gambanteinn" , model = 25091} +models.main[19467] = { name = "Hvergelmir" , model = 25092} +models.main[19470] = { name = "Revenant Fists +1" , model = 25085} +models.main[19471] = { name = "Ursine Claws +1" , model = 24695} +models.main[19472] = { name = "Taipan Fangs +1" , model = 24701} +models.main[19473] = { name = "Barracudas +1" , model = 24716} +models.main[19474] = { name = "Daka +1" , model = 24955} +models.main[19475] = { name = "Parazonium +1" , model = 24752} +models.main[19476] = { name = "Kila +1" , model = 24756} +models.main[19477] = { name = "Fusetto +1" , model = 24744} +models.main[19478] = { name = "Badelaire +1" , model = 24853} +models.main[19479] = { name = "Khanda +1" , model = 24859} +models.main[19480] = { name = "Shamshir +1" , model = 24829} +models.main[19481] = { name = "Machaera +1" , model = 24957} +models.main[19482] = { name = "Espafut +1" , model = 24646} +models.main[19483] = { name = "Prestelame +1" , model = 24650} +models.main[19484] = { name = "Sombrelame +1" , model = 24641} +models.main[19485] = { name = "Kalavejs +1" , model = 24644} +models.main[19486] = { name = "Alard's Axe +1" , model = 24658} +models.main[19487] = { name = "Richardet's Axe +1" , model = 24664} +models.main[19488] = { name = "Guichard's Axe +1" , model = 24654} +models.main[19489] = { name = "Renaud's Axe +1" , model = 24654} +models.main[19490] = { name = "Maschu +1" , model = 24669} +models.main[19491] = { name = "Kunlun +1" , model = 24674} +models.main[19492] = { name = "Atlas +1" , model = 24924} +models.main[19493] = { name = "Sumeru +1" , model = 24672} +models.main[19494] = { name = "Penitence +1" , model = 24770} +models.main[19495] = { name = "Maleficence +1" , model = 24926} +models.main[19496] = { name = "Absolution +1" , model = 24898} +models.main[19497] = { name = "Reckoning +1" , model = 24942} +models.main[19498] = { name = "Cerastes +1" , model = 24785} +models.main[19499] = { name = "Corsesca +1" , model = 24925} +models.main[19500] = { name = "Langdebeve +1" , model = 24789} +models.main[19501] = { name = "Stingray +1" , model = 24954} +models.main[19502] = { name = "Tobi +1" , model = 24889} +models.main[19503] = { name = "Enchu +1" , model = 24943} +models.main[19504] = { name = "Sekka +1" , model = 24888} +models.main[19505] = { name = "Uzura +1" , model = 24886} +models.main[19506] = { name = "Hiradennotachi +1" , model = 24899} +models.main[19507] = { name = "Kokushitsu +1" , model = 24724} +models.main[19508] = { name = "Hyogugusari +1" , model = 24723} +models.main[19509] = { name = "Keitonotachi +1" , model = 24721} +models.main[19510] = { name = "Canne de Cbt. +1" , model = 24692} +models.main[19511] = { name = "Naboot +1" , model = 24679} +models.main[19512] = { name = "Hoeroa +1" , model = 24820} +models.main[19513] = { name = "Makhila +1" , model = 24687} +models.main[19514] = { name = "Taiaha +1" , model = 24874} +models.main[19515] = { name = "Yantok +1" , model = 24872} +models.main[19516] = { name = "Shareeravadi +1" , model = 24871} +models.main[19517] = { name = "Agni's Staff +1" , model = 24881} +models.main[19518] = { name = "Varuna's Staff +1" , model = 24881} +models.main[19519] = { name = "Vayu's Staff +1" , model = 24881} +models.main[19520] = { name = "Kubera's Staff +1" , model = 24881} +models.main[19521] = { name = "Indra's Staff +1" , model = 24881} +models.main[19522] = { name = "Soma's Staff +1" , model = 24881} +models.main[19523] = { name = "Surya's Staff +1" , model = 24881} +models.main[19524] = { name = "Yama's Staff +1" , model = 24881} +models.main[19525] = { name = "Sedikutchi +1" , model = 24879} +models.main[19534] = { name = "Verethragna" , model = 25076} +models.main[19535] = { name = "Twashtar" , model = 25041} +models.main[19536] = { name = "Almace" , model = 25042} +models.main[19537] = { name = "Caladbolg" , model = 25043} +models.main[19538] = { name = "Farsha" , model = 25044} +models.main[19539] = { name = "Ukonvasara" , model = 25045} +models.main[19540] = { name = "Redemption" , model = 25046} +models.main[19541] = { name = "Rhongomiant" , model = 25088} +models.main[19542] = { name = "Kannagi" , model = 25089} +models.main[19543] = { name = "Masamune" , model = 25090} +models.main[19544] = { name = "Gambanteinn" , model = 25091} +models.main[19545] = { name = "Hvergelmir" , model = 25092} +models.main[19548] = { name = "Revenant Fists +2" , model = 25085} +models.main[19549] = { name = "Ursine Claws +2" , model = 24695} +models.main[19550] = { name = "Taipan Fangs +2" , model = 24701} +models.main[19551] = { name = "Barracudas +2" , model = 24716} +models.main[19552] = { name = "Daka +2" , model = 24955} +models.main[19553] = { name = "Parazonium +2" , model = 24752} +models.main[19554] = { name = "Kila +2" , model = 24756} +models.main[19555] = { name = "Fusetto +2" , model = 24744} +models.main[19556] = { name = "Badelaire +2" , model = 24853} +models.main[19557] = { name = "Khanda +2" , model = 24859} +models.main[19558] = { name = "Shamshir +2" , model = 24829} +models.main[19559] = { name = "Machaera +2" , model = 24957} +models.main[19560] = { name = "Espafut +2" , model = 24646} +models.main[19561] = { name = "Prestelame +2" , model = 24650} +models.main[19562] = { name = "Sombrelame +2" , model = 24641} +models.main[19563] = { name = "Kalavejs +2" , model = 24644} +models.main[19564] = { name = "Alard's Axe +2" , model = 24658} +models.main[19565] = { name = "Richard. Axe +2" , model = 24664} +models.main[19566] = { name = "Guichard's Axe +2" , model = 24654} +models.main[19567] = { name = "Renaud's Axe +2" , model = 24654} +models.main[19568] = { name = "Maschu +2" , model = 24669} +models.main[19569] = { name = "Kunlun +2" , model = 24674} +models.main[19570] = { name = "Atlas +2" , model = 24924} +models.main[19571] = { name = "Sumeru +2" , model = 24672} +models.main[19572] = { name = "Penitence +2" , model = 24770} +models.main[19573] = { name = "Maleficence +2" , model = 24926} +models.main[19574] = { name = "Absolution +2" , model = 24898} +models.main[19575] = { name = "Reckoning +2" , model = 24942} +models.main[19576] = { name = "Cerastes +2" , model = 24785} +models.main[19577] = { name = "Corsesca +2" , model = 24925} +models.main[19578] = { name = "Langdebeve +2" , model = 24789} +models.main[19579] = { name = "Stingray +2" , model = 24954} +models.main[19580] = { name = "Tobi +2" , model = 24889} +models.main[19581] = { name = "Enchu +2" , model = 24943} +models.main[19582] = { name = "Sekka +2" , model = 24888} +models.main[19583] = { name = "Uzura +2" , model = 24886} +models.main[19584] = { name = "Hiradennotachi +2" , model = 24899} +models.main[19585] = { name = "Kokushitsu +2" , model = 24724} +models.main[19586] = { name = "Hyogugusari +2" , model = 24723} +models.main[19587] = { name = "Keitonotachi +2" , model = 24721} +models.main[19588] = { name = "Canne de Cbt. +2" , model = 24692} +models.main[19589] = { name = "Naboot +2" , model = 24679} +models.main[19590] = { name = "Hoeroa +2" , model = 24820} +models.main[19591] = { name = "Makhila +2" , model = 24687} +models.main[19592] = { name = "Taiaha +2" , model = 24874} +models.main[19593] = { name = "Yantok +2" , model = 24872} +models.main[19594] = { name = "Shareeravadi +2" , model = 24871} +models.main[19595] = { name = "Agni's Staff +2" , model = 24881} +models.main[19596] = { name = "Varuna's Staff +2" , model = 24881} +models.main[19597] = { name = "Vayu's Staff +2" , model = 24881} +models.main[19598] = { name = "Kubera's Staff +2" , model = 24881} +models.main[19599] = { name = "Indra's Staff +2" , model = 24881} +models.main[19600] = { name = "Soma's Staff +2" , model = 24881} +models.main[19601] = { name = "Surya's Staff +2" , model = 24881} +models.main[19602] = { name = "Yama's Staff +2" , model = 24881} +models.main[19603] = { name = "Sedikutchi +2" , model = 24879} +models.main[19612] = { name = "Conqueror" , model = 24990} +models.main[19613] = { name = "Glanzfaust" , model = 25078} +models.main[19614] = { name = "Yagrush" , model = 24991} +models.main[19615] = { name = "Laevateinn" , model = 24992} +models.main[19616] = { name = "Murgleis" , model = 24996} +models.main[19617] = { name = "Vajra" , model = 24998} +models.main[19618] = { name = "Burtgang" , model = 25002} +models.main[19619] = { name = "Liberator" , model = 25001} +models.main[19620] = { name = "Aymur" , model = 24989} +models.main[19621] = { name = "Carnwenhan" , model = 25003} +models.main[19623] = { name = "Kogarasumaru" , model = 25000} +models.main[19624] = { name = "Nagi" , model = 24997} +models.main[19625] = { name = "Ryunohige" , model = 24999} +models.main[19626] = { name = "Nirvana" , model = 24993} +models.main[19627] = { name = "Tizona" , model = 24995} +models.main[19629] = { name = "Kenkonken" , model = 25079} +models.main[19630] = { name = "Terpsichore" , model = 25004} +models.main[19631] = { name = "Tupsimati" , model = 25005} +models.main[19632] = { name = "Verethragna" , model = 25076} +models.main[19633] = { name = "Twashtar" , model = 25041} +models.main[19634] = { name = "Almace" , model = 25042} +models.main[19635] = { name = "Caladbolg" , model = 25043} +models.main[19636] = { name = "Farsha" , model = 25044} +models.main[19637] = { name = "Ukonvasara" , model = 25045} +models.main[19638] = { name = "Redemption" , model = 25046} +models.main[19639] = { name = "Rhongomiant" , model = 25088} +models.main[19640] = { name = "Kannagi" , model = 25089} +models.main[19641] = { name = "Masamune" , model = 25090} +models.main[19642] = { name = "Gambanteinn" , model = 25091} +models.main[19643] = { name = "Hvergelmir" , model = 25092} +models.main[19646] = { name = "Revenant Fists +3" , model = 25085} +models.main[19647] = { name = "Ursine Claws +3" , model = 24695} +models.main[19648] = { name = "Taipan Fangs +3" , model = 24701} +models.main[19649] = { name = "Barracudas +3" , model = 24716} +models.main[19650] = { name = "Daka +3" , model = 24955} +models.main[19651] = { name = "Parazonium +3" , model = 24752} +models.main[19652] = { name = "Kila +3" , model = 24756} +models.main[19653] = { name = "Fusetto +3" , model = 24744} +models.main[19654] = { name = "Badelaire +3" , model = 24853} +models.main[19655] = { name = "Khanda +3" , model = 24859} +models.main[19656] = { name = "Shamshir +3" , model = 24829} +models.main[19657] = { name = "Machaera +3" , model = 24957} +models.main[19658] = { name = "Espafut +3" , model = 24646} +models.main[19659] = { name = "Prestelame +3" , model = 24650} +models.main[19660] = { name = "Sombrelame +3" , model = 24641} +models.main[19661] = { name = "Kalavejs +3" , model = 24644} +models.main[19662] = { name = "Alard's Axe +3" , model = 24658} +models.main[19663] = { name = "Richard. Axe +3" , model = 24664} +models.main[19664] = { name = "Guichard's Axe +3" , model = 24654} +models.main[19665] = { name = "Renaud's Axe +3" , model = 24654} +models.main[19666] = { name = "Maschu +3" , model = 24669} +models.main[19667] = { name = "Kunlun +3" , model = 24674} +models.main[19668] = { name = "Atlas +3" , model = 24924} +models.main[19669] = { name = "Sumeru +3" , model = 24672} +models.main[19670] = { name = "Penitence +3" , model = 24770} +models.main[19671] = { name = "Maleficence +3" , model = 24926} +models.main[19672] = { name = "Absolution +3" , model = 24898} +models.main[19673] = { name = "Reckoning +3" , model = 24942} +models.main[19674] = { name = "Cerastes +3" , model = 24785} +models.main[19675] = { name = "Corsesca +3" , model = 24925} +models.main[19676] = { name = "Langdebeve +3" , model = 24789} +models.main[19677] = { name = "Stingray +3" , model = 24954} +models.main[19678] = { name = "Tobi +3" , model = 24889} +models.main[19679] = { name = "Enchu +3" , model = 24943} +models.main[19680] = { name = "Sekka +3" , model = 24888} +models.main[19681] = { name = "Uzura +3" , model = 24886} +models.main[19682] = { name = "Hiradennotachi +3" , model = 24899} +models.main[19683] = { name = "Kokushitsu +3" , model = 24724} +models.main[19684] = { name = "Hyogugusari +3" , model = 24723} +models.main[19685] = { name = "Keitonotachi +3" , model = 24721} +models.main[19686] = { name = "Canne de Cbt. +3" , model = 24692} +models.main[19687] = { name = "Naboot +3" , model = 24679} +models.main[19688] = { name = "Hoeroa +3" , model = 24820} +models.main[19689] = { name = "Makhila +3" , model = 24687} +models.main[19690] = { name = "Taiaha +3" , model = 24874} +models.main[19691] = { name = "Yantok +3" , model = 24872} +models.main[19692] = { name = "Shareeravadi +3" , model = 24871} +models.main[19693] = { name = "Agni's Staff +3" , model = 24881} +models.main[19694] = { name = "Varuna's Staff +3" , model = 24881} +models.main[19695] = { name = "Vayu's Staff +3" , model = 24881} +models.main[19696] = { name = "Kubera's Staff +3" , model = 24881} +models.main[19697] = { name = "Indra's Staff +3" , model = 24881} +models.main[19698] = { name = "Soma's Staff +3" , model = 24881} +models.main[19699] = { name = "Surya's Staff +3" , model = 24881} +models.main[19700] = { name = "Yama's Staff +3" , model = 24881} +models.main[19701] = { name = "Sedikutchi +3" , model = 24879} +models.main[19710] = { name = "Conqueror" , model = 24990} +models.main[19711] = { name = "Glanzfaust" , model = 25078} +models.main[19712] = { name = "Yagrush" , model = 24991} +models.main[19713] = { name = "Laevateinn" , model = 24992} +models.main[19714] = { name = "Murgleis" , model = 24996} +models.main[19715] = { name = "Vajra" , model = 24998} +models.main[19716] = { name = "Burtgang" , model = 25002} +models.main[19717] = { name = "Liberator" , model = 25001} +models.main[19718] = { name = "Aymur" , model = 24989} +models.main[19719] = { name = "Carnwenhan" , model = 25003} +models.main[19721] = { name = "Kogarasumaru" , model = 25000} +models.main[19722] = { name = "Nagi" , model = 24997} +models.main[19723] = { name = "Ryunohige" , model = 24999} +models.main[19724] = { name = "Nirvana" , model = 24993} +models.main[19725] = { name = "Tizona" , model = 24995} +models.main[19727] = { name = "Kenkonken" , model = 25079} +models.main[19728] = { name = "Terpsichore" , model = 25004} +models.main[19729] = { name = "Tupsimati" , model = 25005} +models.main[19746] = { name = "Spharai" , model = 25087} +models.main[19747] = { name = "Mandau" , model = 24910} +models.main[19748] = { name = "Excalibur" , model = 24896} +models.main[19749] = { name = "Ragnarok" , model = 24895} +models.main[19750] = { name = "Guttler" , model = 24923} +models.main[19751] = { name = "Bravura" , model = 24915} +models.main[19752] = { name = "Gungnir" , model = 24793} +models.main[19753] = { name = "Apocalypse" , model = 24914} +models.main[19754] = { name = "Kikoku" , model = 24920} +models.main[19755] = { name = "Amanomurakumo" , model = 24916} +models.main[19756] = { name = "Mjollnir" , model = 24883} +models.main[19757] = { name = "Claustrum" , model = 24918} +models.main[19788] = { name = "Gorkhali Kukri" , model = 24748} +models.main[19789] = { name = "Mahakali's Kukri" , model = 24748} +models.main[19790] = { name = "Oneiros Lance" , model = 24785} +models.main[19791] = { name = "Draca Couse" , model = 24925} +models.main[19792] = { name = "Drachenstich" , model = 24786} +models.main[19793] = { name = "Patientia Lance" , model = 24789} +models.main[19794] = { name = "Delphinius" , model = 25166} +models.main[19795] = { name = "Ereptor Lance" , model = 25012} +models.main[19796] = { name = "Rosschinder" , model = 24781} +models.main[19797] = { name = "Rosschinder +1" , model = 24781} +models.main[19798] = { name = "Drakaina Lance" , model = 25029} +models.main[19799] = { name = "Herja's Fork" , model = 24981} +models.main[19805] = { name = "Verethragna" , model = 25076} +models.main[19806] = { name = "Twashtar" , model = 25041} +models.main[19807] = { name = "Almace" , model = 25042} +models.main[19808] = { name = "Caladbolg" , model = 25043} +models.main[19809] = { name = "Farsha" , model = 25044} +models.main[19810] = { name = "Ukonvasara" , model = 25045} +models.main[19811] = { name = "Redemption" , model = 25046} +models.main[19812] = { name = "Rhongomiant" , model = 25088} +models.main[19813] = { name = "Kannagi" , model = 25089} +models.main[19814] = { name = "Masamune" , model = 25090} +models.main[19815] = { name = "Gambanteinn" , model = 25091} +models.main[19816] = { name = "Hvergelmir" , model = 25092} +models.main[19819] = { name = "Conqueror" , model = 24990} +models.main[19820] = { name = "Glanzfaust" , model = 25078} +models.main[19821] = { name = "Yagrush" , model = 24991} +models.main[19822] = { name = "Laevateinn" , model = 24992} +models.main[19823] = { name = "Murgleis" , model = 24996} +models.main[19824] = { name = "Vajra" , model = 24998} +models.main[19825] = { name = "Burtgang" , model = 25002} +models.main[19826] = { name = "Liberator" , model = 25001} +models.main[19827] = { name = "Aymur" , model = 24989} +models.main[19828] = { name = "Carnwenhan" , model = 25003} +models.main[19830] = { name = "Kogarasumaru" , model = 25000} +models.main[19831] = { name = "Nagi" , model = 24997} +models.main[19832] = { name = "Ryunohige" , model = 24999} +models.main[19833] = { name = "Nirvana" , model = 24993} +models.main[19834] = { name = "Tizona" , model = 24995} +models.main[19836] = { name = "Kenkonken" , model = 25079} +models.main[19837] = { name = "Terpsichore" , model = 25004} +models.main[19838] = { name = "Tupsimati" , model = 25005} +models.main[19839] = { name = "Spharai" , model = 25073} +models.main[19840] = { name = "Mandau" , model = 25120} +models.main[19841] = { name = "Excalibur" , model = 25121} +models.main[19842] = { name = "Ragnarok" , model = 25122} +models.main[19843] = { name = "Guttler" , model = 25123} +models.main[19844] = { name = "Bravura" , model = 25124} +models.main[19845] = { name = "Gungnir" , model = 25125} +models.main[19846] = { name = "Apocalypse" , model = 25126} +models.main[19847] = { name = "Kikoku" , model = 25127} +models.main[19848] = { name = "Amanomurakumo" , model = 25128} +models.main[19849] = { name = "Mjollnir" , model = 25129} +models.main[19850] = { name = "Claustrum" , model = 25130} +models.main[19853] = { name = "Verethragna" , model = 25070} +models.main[19854] = { name = "Twashtar" , model = 25147} +models.main[19855] = { name = "Almace" , model = 25148} +models.main[19856] = { name = "Caladbolg" , model = 25149} +models.main[19857] = { name = "Farsha" , model = 25150} +models.main[19858] = { name = "Ukonvasara" , model = 25151} +models.main[19859] = { name = "Redemption" , model = 25152} +models.main[19860] = { name = "Rhongomiant" , model = 25153} +models.main[19861] = { name = "Kannagi" , model = 25154} +models.main[19862] = { name = "Masamune" , model = 25155} +models.main[19863] = { name = "Gambanteinn" , model = 25156} +models.main[19864] = { name = "Hvergelmir" , model = 25157} +models.main[19867] = { name = "Dumuzis" , model = 25084} +models.main[19868] = { name = "Ursa Majors" , model = 24694} +models.main[19869] = { name = "Oxyuranis" , model = 24698} +models.main[19870] = { name = "Sphyras" , model = 24717} +models.main[19871] = { name = "Khandroma" , model = 24974} +models.main[19872] = { name = "Praxidikai" , model = 24751} +models.main[19873] = { name = "Thokcha" , model = 24756} +models.main[19874] = { name = "Centovente" , model = 24744} +models.main[19875] = { name = "Brunello" , model = 24851} +models.main[19876] = { name = "Khadga" , model = 24859} +models.main[19877] = { name = "Shikargar" , model = 24826} +models.main[19878] = { name = "Thibron" , model = 24957} +models.main[19879] = { name = "Xiphias" , model = 24645} +models.main[19880] = { name = "Fulgurante" , model = 24649} +models.main[19881] = { name = "Tenebreuse" , model = 24640} +models.main[19882] = { name = "Kauriraris" , model = 24644} +models.main[19883] = { name = "Sacripante" , model = 24657} +models.main[19884] = { name = "Ganelon" , model = 24663} +models.main[19885] = { name = "Astolfo" , model = 24660} +models.main[19886] = { name = "Fernagu" , model = 24654} +models.main[19887] = { name = "Shamash" , model = 24668} +models.main[19888] = { name = "Liushi Shan" , model = 24673} +models.main[19889] = { name = "Telamon" , model = 24940} +models.main[19890] = { name = "Tavatimsa" , model = 24672} +models.main[19891] = { name = "Umiliati" , model = 24770} +models.main[19892] = { name = "Ogresse" , model = 24926} +models.main[19893] = { name = "Cloacina" , model = 24898} +models.main[19894] = { name = "Basanizo" , model = 24942} +models.main[19895] = { name = "Daboya" , model = 24785} +models.main[19896] = { name = "Chauve-Souris" , model = 24925} +models.main[19897] = { name = "Nahvalr" , model = 24788} +models.main[19898] = { name = "Sixgill" , model = 24964} +models.main[19899] = { name = "Kasasagi" , model = 24947} +models.main[19900] = { name = "Majimun" , model = 24943} +models.main[19901] = { name = "Arisui" , model = 24888} +models.main[19902] = { name = "Hitaki" , model = 24886} +models.main[19903] = { name = "Torigashira" , model = 24899} +models.main[19904] = { name = "Kawatsutsumi" , model = 24724} +models.main[19905] = { name = "Kabutsuchi" , model = 24720} +models.main[19906] = { name = "Kantonotachi" , model = 24927} +models.main[19907] = { name = "Rose Couverte" , model = 24690} +models.main[19908] = { name = "Tahtib" , model = 24678} +models.main[19909] = { name = "Tutunui" , model = 24824} +models.main[19910] = { name = "Ukaldi" , model = 24686} +models.main[19911] = { name = "Paikea" , model = 24878} +models.main[19912] = { name = "Urduja" , model = 24872} +models.main[19913] = { name = "Tuahjebat" , model = 24870} +models.main[19914] = { name = "Atar I" , model = 24881} +models.main[19915] = { name = "Atar II" , model = 24881} +models.main[19916] = { name = "Atar III" , model = 24881} +models.main[19917] = { name = "Vourukasha I" , model = 24881} +models.main[19918] = { name = "Vourukasha II" , model = 24881} +models.main[19919] = { name = "Vourukasha III" , model = 24881} +models.main[19920] = { name = "Vayuvata I" , model = 24881} +models.main[19921] = { name = "Vayuvata II" , model = 24881} +models.main[19922] = { name = "Vayuvata III" , model = 24881} +models.main[19923] = { name = "Vishrava I" , model = 24881} +models.main[19924] = { name = "Vishrava II" , model = 24881} +models.main[19925] = { name = "Vishrava III" , model = 24881} +models.main[19926] = { name = "Apamajas I" , model = 24881} +models.main[19927] = { name = "Apamajas II" , model = 24881} +models.main[19928] = { name = "Apamajas III" , model = 24881} +models.main[19929] = { name = "Haoma I" , model = 24881} +models.main[19930] = { name = "Haoma II" , model = 24881} +models.main[19931] = { name = "Haoma III" , model = 24881} +models.main[19932] = { name = "Arka I" , model = 24881} +models.main[19933] = { name = "Arka II" , model = 24881} +models.main[19934] = { name = "Arka III" , model = 24881} +models.main[19935] = { name = "Arka IV" , model = 24881} +models.main[19936] = { name = "Xsaeta I" , model = 24881} +models.main[19937] = { name = "Xsaeta II" , model = 24881} +models.main[19938] = { name = "Xsaeta III" , model = 24881} +models.main[19939] = { name = "Muruga" , model = 24879} +models.main[19948] = { name = "Conqueror" , model = 25131} +models.main[19949] = { name = "Glanzfaust" , model = 25072} +models.main[19950] = { name = "Yagrush" , model = 25132} +models.main[19951] = { name = "Laevateinn" , model = 25133} +models.main[19952] = { name = "Murgleis" , model = 25134} +models.main[19953] = { name = "Vajra" , model = 25135} +models.main[19954] = { name = "Burtgang" , model = 25136} +models.main[19955] = { name = "Liberator" , model = 25137} +models.main[19956] = { name = "Aymur" , model = 25138} +models.main[19957] = { name = "Carnwenhan" , model = 25139} +models.main[19959] = { name = "Kogarasumaru" , model = 25140} +models.main[19960] = { name = "Nagi" , model = 25141} +models.main[19961] = { name = "Ryunohige" , model = 25142} +models.main[19962] = { name = "Nirvana" , model = 25143} +models.main[19963] = { name = "Tizona" , model = 25144} +models.main[19965] = { name = "Kenkonken" , model = 25071} +models.main[19966] = { name = "Terpsichore" , model = 25145} +models.main[19967] = { name = "Tupsimati" , model = 25146} +models.main[20480] = { name = "Spharai" , model = 25087} +models.main[20481] = { name = "Spharai" , model = 25073} +models.main[20482] = { name = "Glanzfaust" , model = 25078} +models.main[20483] = { name = "Glanzfaust" , model = 25072} +models.main[20484] = { name = "Kenkonken" , model = 25079} +models.main[20485] = { name = "Kenkonken" , model = 25071} +models.main[20486] = { name = "Verethragna" , model = 25076} +models.main[20487] = { name = "Verethragna" , model = 25070} +models.main[20505] = { name = "Condemners" , model = 25086} +models.main[20506] = { name = "Suwaiyas" , model = 25075} +models.main[20507] = { name = "Comeuppances" , model = 25077} +models.main[20508] = { name = "Comeuppances +1" , model = 25077} +models.main[20509] = { name = "Spharai" , model = 25073} +models.main[20510] = { name = "Glanzfaust" , model = 25072} +models.main[20511] = { name = "Kenkonken" , model = 25071} +models.main[20512] = { name = "Verethragna" , model = 25070} +models.main[20514] = { name = "Aphelion Knuckles" , model = 25059} +models.main[20515] = { name = "Godhands" , model = 25060} +models.main[20516] = { name = "Denouements" , model = 25061} +models.main[20517] = { name = "Fleshcarvers" , model = 24716} +models.main[20518] = { name = "Eshus" , model = 25069} +models.main[20519] = { name = "Hammerfists" , model = 25077} +models.main[20520] = { name = "Midnights" , model = 25081} +models.main[20521] = { name = "Emeici" , model = 24693} +models.main[20522] = { name = "Emeici +1" , model = 24693} +models.main[20523] = { name = "Chastisers" , model = 25074} +models.main[20524] = { name = "Nibiru Sainti" , model = 25063} +models.main[20525] = { name = "Blurred Claws" , model = 25062} +models.main[20526] = { name = "Blurred Claws +1" , model = 25062} +models.main[20527] = { name = "Fists of Fury" , model = 24705} +models.main[20528] = { name = "Fists of Fury +1" , model = 24705} +models.main[20529] = { name = "Calved Claws" , model = 24701} +models.main[20530] = { name = "Ohrmazd" , model = 25082} +models.main[20531] = { name = "Homestead Cesti" , model = 25067} +models.main[20532] = { name = "Worm Feelers" , model = 25065} +models.main[20533] = { name = "Worm Feelers +1" , model = 25065} +models.main[20534] = { name = "Nyepel" , model = 25077} +models.main[20535] = { name = "Ohtas" , model = 25081} +models.main[20536] = { name = "Tinhaspa" , model = 24710} +models.main[20537] = { name = "Bhakazi Sainti" , model = 25080} +models.main[20538] = { name = "Bhakazi Sainti +1" , model = 25080} +models.main[20539] = { name = "Ninzas +2" , model = 25083} +models.main[20540] = { name = "Em. Baghnakhs" , model = 24718} +models.main[20541] = { name = "Pinion Cesti" , model = 24703} +models.main[20542] = { name = "Gnafron's Adargas" , model = 25086} +models.main[20543] = { name = "Maochinoli" , model = 25068} +models.main[20544] = { name = "Dumuzis -1" , model = 25084} +models.main[20545] = { name = "Cama. Knuckles" , model = 24705} +models.main[20546] = { name = "Ninzas +1" , model = 25083} +models.main[20547] = { name = "Forefront Cesti" , model = 25067} +models.main[20548] = { name = "Oatixur" , model = 25068} +models.main[20549] = { name = "Rigor Baghnakhs" , model = 24719} +models.main[20550] = { name = "Vineslash Cesti" , model = 24703} +models.main[20551] = { name = "Akua Sainti" , model = 25084} +models.main[20552] = { name = "Akua Sainti +1" , model = 25084} +models.main[20553] = { name = "Ninzas" , model = 25083} +models.main[20554] = { name = "Tlalpoloani" , model = 25068} +models.main[20555] = { name = "Mandau" , model = 24910} +models.main[20556] = { name = "Mandau" , model = 25120} +models.main[20557] = { name = "Terpsichore" , model = 25004} +models.main[20558] = { name = "Terpsichore" , model = 25145} +models.main[20559] = { name = "Vajra" , model = 24998} +models.main[20560] = { name = "Vajra" , model = 25135} +models.main[20561] = { name = "Carnwenhan" , model = 25003} +models.main[20562] = { name = "Carnwenhan" , model = 25139} +models.main[20563] = { name = "Twashtar" , model = 25041} +models.main[20564] = { name = "Twashtar" , model = 25147} +models.main[20573] = { name = "Aern Dagger" , model = 25402} +models.main[20576] = { name = "Qutrub Knife" , model = 25407} +models.main[20577] = { name = "Chicken Knife II" , model = 25360} +models.main[20579] = { name = "Skinflayer" , model = 25006} +models.main[20580] = { name = "Kustawi" , model = 24733} +models.main[20581] = { name = "Kustawi +1" , model = 24733} +models.main[20583] = { name = "Mandau" , model = 25120} +models.main[20584] = { name = "Terpsichore" , model = 25145} +models.main[20585] = { name = "Vajra" , model = 25135} +models.main[20586] = { name = "Carnwenhan" , model = 25139} +models.main[20587] = { name = "Twashtar" , model = 25147} +models.main[20592] = { name = "Sangoma" , model = 25334} +models.main[20594] = { name = "Aeneas" , model = 25336} +models.main[20595] = { name = "Malevolence" , model = 25117} +models.main[20596] = { name = "Taming Sari" , model = 25204} +models.main[20597] = { name = "Enchufla" , model = 25026} +models.main[20598] = { name = "Shijo" , model = 24972} +models.main[20599] = { name = "Kali" , model = 25093} +models.main[20600] = { name = "Nibiru Knife" , model = 25308} +models.main[20601] = { name = "Blurred Knife" , model = 25035} +models.main[20602] = { name = "Blurred Knife +1" , model = 25035} +models.main[20603] = { name = "Ternion Dagger" , model = 24744} +models.main[20604] = { name = "Ternion Dagger +1" , model = 24744} +models.main[20605] = { name = "Odium" , model = 25307} +models.main[20606] = { name = "Anathema Harpe" , model = 25109} +models.main[20607] = { name = "Anathema Harpe +1" , model = 25109} +models.main[20608] = { name = "Jugo Kukri" , model = 24747} +models.main[20609] = { name = "Jugo Kukri +1" , model = 24747} +models.main[20610] = { name = "Rhadamanthus" , model = 25300} +models.main[20611] = { name = "Sangarius" , model = 24863} +models.main[20612] = { name = "Sangarius +1" , model = 24863} +models.main[20613] = { name = "Pukulatmuj" , model = 24844} +models.main[20614] = { name = "Pukulatmuj +1" , model = 24844} +models.main[20615] = { name = "Levante Dagger" , model = 24742} +models.main[20616] = { name = "Ipetam" , model = 25286} +models.main[20617] = { name = "Homestead Dagger" , model = 24742} +models.main[20618] = { name = "Sandung" , model = 25173} +models.main[20619] = { name = "Polyhymnia" , model = 25026} +models.main[20620] = { name = "Sabebus" , model = 24752} +models.main[20621] = { name = "Nanti Knife" , model = 24756} +models.main[20622] = { name = "Nanti Knife +1" , model = 24756} +models.main[20623] = { name = "Leisilonu +2" , model = 24755} +models.main[20624] = { name = "Eminent Dagger" , model = 24739} +models.main[20625] = { name = "Secespita" , model = 24751} +models.main[20626] = { name = "Blitto Needle" , model = 24739} +models.main[20627] = { name = "Surcouf's Jambiya" , model = 24955} +models.main[20628] = { name = "Mindmeld Kris" , model = 24922} +models.main[20629] = { name = "Legato Dagger" , model = 25117} +models.main[20630] = { name = "Atoyac" , model = 25191} +models.main[20631] = { name = "Khandroma -1" , model = 24974} +models.main[20632] = { name = "Vanir Knife" , model = 24734} +models.main[20633] = { name = "Cama. Dagger" , model = 25204} +models.main[20634] = { name = "Leisilonu +1" , model = 24755} +models.main[20635] = { name = "Forefront Dagger" , model = 24742} +models.main[20636] = { name = "Izhiikoh" , model = 25191} +models.main[20637] = { name = "Aphotic Kukri" , model = 24747} +models.main[20638] = { name = "Coalition Dirk" , model = 25182} +models.main[20639] = { name = "Oxidant Baselard" , model = 24746} +models.main[20640] = { name = "Nitric Baselard" , model = 24746} +models.main[20641] = { name = "Leisilonu" , model = 24755} +models.main[20642] = { name = "Tzustes Knife +1" , model = 24736} +models.main[20643] = { name = "Macoquetza" , model = 25191} +models.main[20644] = { name = "Tzustes Knife" , model = 24736} +models.main[20645] = { name = "Excalibur" , model = 24896} +models.main[20646] = { name = "Excalibur" , model = 25121} +models.main[20647] = { name = "Murgleis" , model = 24996} +models.main[20648] = { name = "Murgleis" , model = 25134} +models.main[20649] = { name = "Burtgang" , model = 25002} +models.main[20650] = { name = "Burtgang" , model = 25136} +models.main[20651] = { name = "Tizona" , model = 24995} +models.main[20652] = { name = "Tizona" , model = 25144} +models.main[20653] = { name = "Almace" , model = 25042} +models.main[20654] = { name = "Almace" , model = 25148} +models.main[20665] = { name = "Kam'lanaut's Sword" , model = 25383} +models.main[20666] = { name = "Blizzard Brand" , model = 25358} +models.main[20667] = { name = "Blizzard Brand +1" , model = 25358} +models.main[20668] = { name = "Firetongue" , model = 25359} +models.main[20669] = { name = "Firetongue +1" , model = 25359} +models.main[20674] = { name = "Aern Sword" , model = 25401} +models.main[20677] = { name = "Colada" , model = 24966} +models.main[20678] = { name = "Firangi" , model = 25021} +models.main[20679] = { name = "Tanmogayi" , model = 24934} +models.main[20680] = { name = "Tanmogayi +1" , model = 24934} +models.main[20681] = { name = "Flyssa" , model = 24975} +models.main[20682] = { name = "Flyssa +1" , model = 24975} +models.main[20683] = { name = "Zantetsuken" , model = 24980} +models.main[20685] = { name = "Excalibur" , model = 25121} +models.main[20686] = { name = "Murgleis" , model = 25134} +models.main[20687] = { name = "Burtgang" , model = 25136} +models.main[20688] = { name = "Tizona" , model = 25144} +models.main[20689] = { name = "Almace" , model = 25148} +models.main[20690] = { name = "Reikiko" , model = 25347} +models.main[20694] = { name = "Fermion Sword" , model = 25332} +models.main[20695] = { name = "Sequence" , model = 25337} +models.main[20696] = { name = "Combuster" , model = 24854} +models.main[20697] = { name = "Combuster +1" , model = 24854} +models.main[20698] = { name = "Fettering Blade" , model = 25333} +models.main[20699] = { name = "Koboto" , model = 24835} +models.main[20700] = { name = "Nixxer" , model = 24975} +models.main[20701] = { name = "Iris" , model = 25007} +models.main[20702] = { name = "Emissary" , model = 24826} +models.main[20703] = { name = "Deacon Saber" , model = 25160} +models.main[20704] = { name = "Deacon Sword" , model = 25161} +models.main[20705] = { name = "Brilliance" , model = 25326} +models.main[20706] = { name = "Vampirism" , model = 25328} +models.main[20707] = { name = "Medeina Kilij" , model = 24978} +models.main[20708] = { name = "Demersal Degen" , model = 24761} +models.main[20709] = { name = "Demers. Degen +1" , model = 24761} +models.main[20710] = { name = "Nibiru Blade" , model = 25309} +models.main[20711] = { name = "Blurred Sword" , model = 25036} +models.main[20712] = { name = "Blurred Sword +1" , model = 25036} +models.main[20713] = { name = "Excalipoor" , model = 25305} +models.main[20714] = { name = "Excalipoor II" , model = 25305} +models.main[20715] = { name = "Acclimator" , model = 25301} +models.main[20716] = { name = "Perfervid Sword" , model = 24831} +models.main[20717] = { name = "Arendsi Fleuret" , model = 24768} +models.main[20718] = { name = "Claidheamh Soluis" , model = 25287} +models.main[20719] = { name = "Homestead Blade" , model = 24838} +models.main[20720] = { name = "Egeking" , model = 24830} +models.main[20721] = { name = "Mimesis" , model = 24858} +models.main[20722] = { name = "Usonmunku" , model = 24843} +models.main[20723] = { name = "Dija Sword" , model = 24843} +models.main[20724] = { name = "Dija Sword +1" , model = 24843} +models.main[20725] = { name = "Iztaasu +2" , model = 25094} +models.main[20726] = { name = "Eminent Scimitar" , model = 24834} +models.main[20727] = { name = "Tabahi Fleuret" , model = 24768} +models.main[20728] = { name = "Kheshig Blade" , model = 24857} +models.main[20729] = { name = "Vivifiante" , model = 24862} +models.main[20730] = { name = "Predatrice" , model = 24960} +models.main[20731] = { name = "Xiutleato" , model = 25192} +models.main[20732] = { name = "Brunello -1" , model = 24851} +models.main[20733] = { name = "Anahera Saber" , model = 25160} +models.main[20734] = { name = "Anahera Sword" , model = 25161} +models.main[20735] = { name = "Cama. Blade" , model = 25205} +models.main[20736] = { name = "Iztaasu +1" , model = 25094} +models.main[20737] = { name = "Forefront Blade" , model = 24838} +models.main[20738] = { name = "Buramenk'ah" , model = 25192} +models.main[20739] = { name = "Halachuinic Sword" , model = 24860} +models.main[20740] = { name = "Camatlatia" , model = 25192} +models.main[20741] = { name = "Coalition Blade" , model = 25183} +models.main[20742] = { name = "Iztaasu" , model = 25094} +models.main[20743] = { name = "Bihkah Sword +1" , model = 24846} +models.main[20744] = { name = "Bihkah Sword" , model = 24846} +models.main[20745] = { name = "Ragnarok" , model = 24895} +models.main[20746] = { name = "Ragnarok" , model = 25122} +models.main[20747] = { name = "Caladbolg" , model = 25043} +models.main[20748] = { name = "Caladbolg" , model = 25149} +models.main[20749] = { name = "Trial Blade" , model = 25184} +models.main[20750] = { name = "Lexeme Blade" , model = 25184} +models.main[20751] = { name = "Lexeme Blade" , model = 25184} +models.main[20752] = { name = "Lexeme Blade" , model = 25184} +models.main[20753] = { name = "Epeolatry" , model = 25282} +models.main[20754] = { name = "Malfeasance" , model = 25306} +models.main[20755] = { name = "Malfeasance +1" , model = 25306} +models.main[20756] = { name = "Soulcleaver" , model = 24983} +models.main[20757] = { name = "Foreshock Sword" , model = 25174} +models.main[20758] = { name = "Mekosuchus Blade" , model = 25202} +models.main[20759] = { name = "Macbain" , model = 25288} +models.main[20760] = { name = "Home. Claymore" , model = 24642} +models.main[20761] = { name = "Aettir" , model = 25281} +models.main[20762] = { name = "Ukudyoni" , model = 25214} +models.main[20763] = { name = "Kbiroj" , model = 24641} +models.main[20764] = { name = "Crobaci +2" , model = 25008} +models.main[20765] = { name = "Tunglmyrkvi" , model = 24983} +models.main[20766] = { name = "Eminent Sword" , model = 24641} +models.main[20767] = { name = "Medicor Sword" , model = 24640} +models.main[20768] = { name = "Kaquljaan" , model = 25214} +models.main[20769] = { name = "Xiphias -1" , model = 24645} +models.main[20770] = { name = "Mes'yohi Sword" , model = 24647} +models.main[20771] = { name = "Cama. Claymore" , model = 25206} +models.main[20772] = { name = "Voay Sword -1" , model = 25202} +models.main[20773] = { name = "Voay Sword" , model = 25202} +models.main[20774] = { name = "Voay Sword +1" , model = 25202} +models.main[20775] = { name = "Crobaci +1" , model = 25008} +models.main[20776] = { name = "Beorc Sword" , model = 25184} +models.main[20777] = { name = "F.front Claymore" , model = 24642} +models.main[20778] = { name = "Bereaver" , model = 24644} +models.main[20779] = { name = "Senbaak Nagan" , model = 24649} +models.main[20780] = { name = "Senbaak Nagan +1" , model = 24649} +models.main[20781] = { name = "Sowilo Claymore" , model = 24644} +models.main[20782] = { name = "Coalition Sword" , model = 25184} +models.main[20783] = { name = "Uruz Blade" , model = 24648} +models.main[20784] = { name = "Uruz Blade +1" , model = 24648} +models.main[20785] = { name = "Thurisaz Blade" , model = 24643} +models.main[20786] = { name = "Thurisaz Blade +1" , model = 24643} +models.main[20787] = { name = "Crobaci" , model = 25008} +models.main[20788] = { name = "Hatzoaar Sword +1" , model = 24642} +models.main[20789] = { name = "Hatzoaar Sword" , model = 24642} +models.main[20790] = { name = "Guttler" , model = 24923} +models.main[20791] = { name = "Guttler" , model = 25123} +models.main[20792] = { name = "Aymur" , model = 24989} +models.main[20793] = { name = "Aymur" , model = 25138} +models.main[20794] = { name = "Farsha" , model = 25044} +models.main[20795] = { name = "Farsha" , model = 25150} +models.main[20796] = { name = "Purgation" , model = 24963} +models.main[20797] = { name = "Skullrender" , model = 25167} +models.main[20798] = { name = "Deacon Tabar" , model = 25163} +models.main[20799] = { name = "Mdomo Axe" , model = 24929} +models.main[20800] = { name = "Mdomo Axe +1" , model = 24929} +models.main[20801] = { name = "Nibiru Tabar" , model = 25311} +models.main[20802] = { name = "Blurred Axe" , model = 25319} +models.main[20803] = { name = "Blurred Axe +1" , model = 25319} +models.main[20804] = { name = "Perun" , model = 24667} +models.main[20805] = { name = "Perun +1" , model = 24667} +models.main[20806] = { name = "Buramgh" , model = 24659} +models.main[20807] = { name = "Buramgh +1" , model = 24659} +models.main[20808] = { name = "Tramontane Axe" , model = 24657} +models.main[20809] = { name = "Kumbhakarna" , model = 25289} +models.main[20810] = { name = "Homestead Axe" , model = 24659} +models.main[20811] = { name = "Arktoi" , model = 25176} +models.main[20812] = { name = "Izizoeksi" , model = 25197} +models.main[20813] = { name = "Emxgha" , model = 24663} +models.main[20814] = { name = "Budliqa" , model = 24666} +models.main[20815] = { name = "Budliqa +1" , model = 24666} +models.main[20816] = { name = "Faizzeer +2" , model = 24963} +models.main[20817] = { name = "Eminent Axe" , model = 24658} +models.main[20818] = { name = "Hurlbat" , model = 24667} +models.main[20819] = { name = "Antican Axe" , model = 24658} +models.main[20820] = { name = "Hatxiik" , model = 25193} +models.main[20821] = { name = "Sacripante -1" , model = 24657} +models.main[20822] = { name = "Anahera Tabar" , model = 25163} +models.main[20823] = { name = "Cama. Axe" , model = 25207} +models.main[20824] = { name = "Faizzeer +1" , model = 24963} +models.main[20825] = { name = "Forefront Axe" , model = 24659} +models.main[20826] = { name = "Hunahpu" , model = 25197} +models.main[20827] = { name = "Kerehcatl" , model = 25193} +models.main[20828] = { name = "Brethren Axe" , model = 24667} +models.main[20829] = { name = "Icoyoca" , model = 25193} +models.main[20830] = { name = "Coalition Axe" , model = 25185} +models.main[20831] = { name = "Aalak' Axe" , model = 24660} +models.main[20832] = { name = "Aalak' Axe +1" , model = 24660} +models.main[20833] = { name = "Faizzeer" , model = 24963} +models.main[20835] = { name = "Bravura" , model = 24915} +models.main[20836] = { name = "Bravura" , model = 25124} +models.main[20837] = { name = "Conqueror" , model = 24990} +models.main[20838] = { name = "Conqueror" , model = 25131} +models.main[20839] = { name = "Ukonvasara" , model = 25045} +models.main[20840] = { name = "Ukonvasara" , model = 25151} +models.main[20842] = { name = "Reikiono" , model = 25348} +models.main[20843] = { name = "Chango" , model = 25340} +models.main[20844] = { name = "Ferocity" , model = 25096} +models.main[20845] = { name = "Instigator" , model = 24939} +models.main[20846] = { name = "Jokushuono" , model = 24674} +models.main[20847] = { name = "Router" , model = 25179} +models.main[20848] = { name = "Nibiru Chopper" , model = 24940} +models.main[20849] = { name = "Blurred Cleaver" , model = 25320} +models.main[20850] = { name = "Blurred Cleaver +1" , model = 25320} +models.main[20851] = { name = "Aizkora" , model = 24915} +models.main[20852] = { name = "Aizkora +1" , model = 24915} +models.main[20853] = { name = "Beheader" , model = 24669} +models.main[20854] = { name = "Beheader +1" , model = 24669} +models.main[20855] = { name = "Devivifier" , model = 25298} +models.main[20856] = { name = "Phreatic Axe" , model = 25027} +models.main[20857] = { name = "Svarga" , model = 25290} +models.main[20858] = { name = "Lightreaver" , model = 24674} +models.main[20859] = { name = "Home. Labrys" , model = 25190} +models.main[20860] = { name = "Minos" , model = 24911} +models.main[20861] = { name = "Qalgwer" , model = 25199} +models.main[20862] = { name = "Lekboza" , model = 24915} +models.main[20863] = { name = "Iclamar +2" , model = 25024} +models.main[20864] = { name = "Castigation" , model = 25024} +models.main[20865] = { name = "Eminent Voulge" , model = 24941} +models.main[20866] = { name = "Parashu" , model = 24671} +models.main[20867] = { name = "Shamash -1" , model = 24668} +models.main[20869] = { name = "Cama. Reaver" , model = 24669} +models.main[20870] = { name = "Iclamar +1" , model = 25024} +models.main[20871] = { name = "Forefront Labrys" , model = 25190} +models.main[20872] = { name = "Ixtab" , model = 25199} +models.main[20873] = { name = "Bloodbath Axe" , model = 24668} +models.main[20874] = { name = "Razorfury" , model = 24924} +models.main[20875] = { name = "Razorfury +1" , model = 24924} +models.main[20876] = { name = "Trunkcleaver" , model = 24673} +models.main[20877] = { name = "Iclamar" , model = 25024} +models.main[20878] = { name = "Nohkux Axe" , model = 24669} +models.main[20879] = { name = "Nohkux Axe +1" , model = 24669} +models.main[20880] = { name = "Apocalypse" , model = 24914} +models.main[20881] = { name = "Apocalypse" , model = 25126} +models.main[20882] = { name = "Liberator" , model = 25011} +models.main[20883] = { name = "Liberator" , model = 25137} +models.main[20884] = { name = "Redemption" , model = 25046} +models.main[20885] = { name = "Redemption" , model = 25152} +models.main[20887] = { name = "Dacnomania" , model = 25349} +models.main[20889] = { name = "Misanthropy" , model = 25335} +models.main[20890] = { name = "Anguta" , model = 25341} +models.main[20891] = { name = "Brutality" , model = 24898} +models.main[20892] = { name = "Deathbane" , model = 24777} +models.main[20893] = { name = "Shukuyu's Scythe" , model = 24773} +models.main[20894] = { name = "Deacon Scythe" , model = 25162} +models.main[20895] = { name = "Nibiru Sickle" , model = 25313} +models.main[20896] = { name = "Blurred Scythe" , model = 25321} +models.main[20897] = { name = "Blurred Scythe +1" , model = 25321} +models.main[20898] = { name = "Triska Scythe" , model = 24777} +models.main[20899] = { name = "Triska Scythe +1" , model = 24777} +models.main[20900] = { name = "Meekculler" , model = 24777} +models.main[20901] = { name = "Inanna" , model = 25291} +models.main[20903] = { name = "Home. Scythe" , model = 25196} +models.main[20904] = { name = "Cronus" , model = 25011} +models.main[20905] = { name = "Tajabit" , model = 25198} +models.main[20906] = { name = "Vunetshelo" , model = 24777} +models.main[20907] = { name = "Iizamal +2" , model = 25097} +models.main[20908] = { name = "Eminent Sickle" , model = 24969} +models.main[20909] = { name = "Hoe" , model = 25215} +models.main[20910] = { name = "Anaimatos Scythe" , model = 24777} +models.main[20911] = { name = "Last Rest" , model = 24942} +models.main[20912] = { name = "Umiliati -1" , model = 24770} +models.main[20913] = { name = "Anahera Scythe" , model = 25162} +models.main[20914] = { name = "Cama. Scythe" , model = 24770} +models.main[20915] = { name = "Iizamal +1" , model = 25097} +models.main[20916] = { name = "Forefront Scythe" , model = 25196} +models.main[20917] = { name = "Xbalanque" , model = 25198} +models.main[20918] = { name = "Dimmet Scythe" , model = 24772} +models.main[20919] = { name = "Lacryma Sickle" , model = 24942} +models.main[20920] = { name = "Lacryma Sickle +1" , model = 24942} +models.main[20921] = { name = "Fieldrazer Scythe" , model = 24948} +models.main[20922] = { name = "Aak'ab Scythe" , model = 24777} +models.main[20923] = { name = "Aak'ab Scythe +1" , model = 24777} +models.main[20924] = { name = "Iizamal" , model = 25097} +models.main[20925] = { name = "Gungnir" , model = 24793} +models.main[20926] = { name = "Gungnir" , model = 25125} +models.main[20927] = { name = "Ryunohige" , model = 24999} +models.main[20928] = { name = "Ryunohige" , model = 25142} +models.main[20929] = { name = "Rhongomiant" , model = 25088} +models.main[20930] = { name = "Rhongomiant" , model = 25153} +models.main[20932] = { name = "Habile Mazrak" , model = 24964} +models.main[20933] = { name = "Hotengeki" , model = 25435} +models.main[20935] = { name = "Trishula" , model = 25342} +models.main[20936] = { name = "Koresuke" , model = 25020} +models.main[20937] = { name = "Rhomphaia" , model = 24984} +models.main[20938] = { name = "Annealed Lance" , model = 25166} +models.main[20939] = { name = "Nibiru Lance" , model = 25314} +models.main[20940] = { name = "Blurred Lance" , model = 25037} +models.main[20941] = { name = "Blurred Lance +1" , model = 25037} +models.main[20942] = { name = "Gae Derg" , model = 24785} +models.main[20943] = { name = "Gae Derg +1" , model = 24785} +models.main[20944] = { name = "Pelagos Lance" , model = 24792} +models.main[20945] = { name = "Nativus Halberd" , model = 24778} +models.main[20946] = { name = "Olyndicus" , model = 25292} +models.main[20947] = { name = "Homestead Lance" , model = 24789} +models.main[20948] = { name = "Areadbhar" , model = 24984} +models.main[20949] = { name = "Kumalo" , model = 24946} +models.main[20950] = { name = "Terebrokath" , model = 24788} +models.main[20951] = { name = "Terebrokath +1" , model = 24788} +models.main[20952] = { name = "Qatsunoci +2" , model = 25028} +models.main[20953] = { name = "Escritorio" , model = 25280} +models.main[20954] = { name = "Eminent Lance" , model = 25020} +models.main[20955] = { name = "Aigilis Lance" , model = 24787} +models.main[20956] = { name = "Sibat" , model = 24778} +models.main[20957] = { name = "Concido Course" , model = 24925} +models.main[20958] = { name = "Kuakuakait" , model = 25195} +models.main[20959] = { name = "Daboya -1" , model = 24785} +models.main[20960] = { name = "Cama. Lance" , model = 25208} +models.main[20961] = { name = "Qatsunoci +1" , model = 25028} +models.main[20962] = { name = "Forefront Lance" , model = 24789} +models.main[20963] = { name = "Upukirex" , model = 25195} +models.main[20964] = { name = "Ophidian Trident" , model = 24792} +models.main[20965] = { name = "Tlamini" , model = 25195} +models.main[20966] = { name = "Coalition Lance" , model = 25186} +models.main[20967] = { name = "Qatsunoci" , model = 25028} +models.main[20968] = { name = "Chanar Xyston +1" , model = 24786} +models.main[20969] = { name = "Chanar Xyston" , model = 24786} +models.main[20970] = { name = "Kikoku" , model = 24920} +models.main[20971] = { name = "Kikoku" , model = 25127} +models.main[20972] = { name = "Nagi" , model = 24997} +models.main[20973] = { name = "Nagi" , model = 25141} +models.main[20974] = { name = "Kannagi" , model = 25089} +models.main[20975] = { name = "Kannagi" , model = 25154} +models.main[20977] = { name = "Heishi Shorinken" , model = 25343} +models.main[20978] = { name = "Ochu" , model = 25189} +models.main[20979] = { name = "Aizushintogo" , model = 25015} +models.main[20980] = { name = "Raicho" , model = 24976} +models.main[20981] = { name = "Raicho +1" , model = 24976} +models.main[20982] = { name = "Shuhansadamune" , model = 25098} +models.main[20983] = { name = "Mijin" , model = 25308} +models.main[20984] = { name = "Kujaku" , model = 25322} +models.main[20985] = { name = "Kujaku +1" , model = 25322} +models.main[20986] = { name = "Achiuchikapu" , model = 25303} +models.main[20987] = { name = "Tancho" , model = 24888} +models.main[20988] = { name = "Tancho +1" , model = 24888} +models.main[20989] = { name = "Izuna" , model = 25293} +models.main[20990] = { name = "Jushimatsu" , model = 25285} +models.main[20991] = { name = "Chidori" , model = 24885} +models.main[20992] = { name = "Taikogane" , model = 25285} +models.main[20993] = { name = "Senkutanto" , model = 25189} +models.main[20994] = { name = "Shigi" , model = 25181} +models.main[20995] = { name = "Isuka" , model = 24888} +models.main[20996] = { name = "Kannakiri +2" , model = 25023} +models.main[20997] = { name = "Raimitsukane" , model = 24889} +models.main[20998] = { name = "Kaitsuburi" , model = 24970} +models.main[20999] = { name = "Habukatana" , model = 24886} +models.main[21000] = { name = "Magorokuhocho" , model = 24885} +models.main[21001] = { name = "Kasasagi -1" , model = 24889} +models.main[21003] = { name = "Cama. Katana" , model = 24886} +models.main[21004] = { name = "Kannakiri +1" , model = 25023} +models.main[21005] = { name = "Kiji" , model = 24890} +models.main[21006] = { name = "Pamun" , model = 24943} +models.main[21007] = { name = "Pamun +1" , model = 24943} +models.main[21008] = { name = "Kotekirigo" , model = 24888} +models.main[21009] = { name = "Nakajimarai" , model = 24886} +models.main[21010] = { name = "Nakajimarai +1" , model = 24886} +models.main[21011] = { name = "Enju" , model = 24889} +models.main[21012] = { name = "Enju +1" , model = 24889} +models.main[21013] = { name = "Kannakiri" , model = 25023} +models.main[21014] = { name = "Ichijintanto" , model = 25189} +models.main[21015] = { name = "Amanomurakumo" , model = 24916} +models.main[21016] = { name = "Amanomurakumo" , model = 25128} +models.main[21017] = { name = "Kogarasumaru" , model = 25000} +models.main[21018] = { name = "Kogarasumaru" , model = 25140} +models.main[21019] = { name = "Masamune" , model = 25090} +models.main[21020] = { name = "Masamune" , model = 25155} +models.main[21021] = { name = "Umaru" , model = 25178} +models.main[21022] = { name = "Shishio" , model = 24727} +models.main[21025] = { name = "Dojikiri Yasutsuna" , model = 25344} +models.main[21026] = { name = "Himetsuruichimonji" , model = 25188} +models.main[21027] = { name = "Ichigohitofuri" , model = 25016} +models.main[21028] = { name = "Deacon Blade" , model = 25164} +models.main[21029] = { name = "Norifusa" , model = 24731} +models.main[21030] = { name = "Norifusa +1" , model = 24731} +models.main[21031] = { name = "Sensui" , model = 25316} +models.main[21032] = { name = "Kunitsuna" , model = 25323} +models.main[21033] = { name = "Kunitsuna +1" , model = 25323} +models.main[21034] = { name = "Kunimune" , model = 24722} +models.main[21035] = { name = "Kunimune +1" , model = 24722} +models.main[21036] = { name = "Atakigiri" , model = 25016} +models.main[21037] = { name = "Nenekirimaru" , model = 25294} +models.main[21038] = { name = "Senkuto" , model = 25188} +models.main[21039] = { name = "Kurikaranotachi" , model = 24899} +models.main[21040] = { name = "Shokudaikiri" , model = 24727} +models.main[21041] = { name = "Sukezane" , model = 24720} +models.main[21042] = { name = "Sukezane +1" , model = 24720} +models.main[21043] = { name = "Shichishito +2" , model = 25099} +models.main[21044] = { name = "Ichimonji-Yofusa" , model = 24720} +models.main[21045] = { name = "Bukyoku" , model = 24727} +models.main[21046] = { name = "Kiikanemitsu" , model = 24732} +models.main[21047] = { name = "Azukinagamitsu" , model = 25194} +models.main[21048] = { name = "Torigashira -1" , model = 24968} +models.main[21049] = { name = "Anahera Blade" , model = 25164} +models.main[21050] = { name = "Cama. Tachi" , model = 24723} +models.main[21051] = { name = "Shichishito +1" , model = 25099} +models.main[21052] = { name = "Tsurumaru" , model = 25194} +models.main[21053] = { name = "Uguisumaru" , model = 24732} +models.main[21054] = { name = "Suijingiri KM" , model = 25194} +models.main[21055] = { name = "Kashiwadachi" , model = 24722} +models.main[21056] = { name = "Tomonari" , model = 24968} +models.main[21057] = { name = "Tomonari +1" , model = 24968} +models.main[21058] = { name = "Shichishito" , model = 25099} +models.main[21059] = { name = "Ichijinto" , model = 25188} +models.main[21060] = { name = "Mjollnir" , model = 24883} +models.main[21061] = { name = "Mjollnir" , model = 25129} +models.main[21062] = { name = "Yagrush" , model = 24991} +models.main[21063] = { name = "Yagrush" , model = 25132} +models.main[21064] = { name = "Gambanteinn" , model = 25091} +models.main[21065] = { name = "Gambanteinn" , model = 25156} +models.main[21066] = { name = "Trial Wand" , model = 25209} +models.main[21067] = { name = "Nodal Wand" , model = 25209} +models.main[21068] = { name = "Nodal Wand" , model = 25209} +models.main[21069] = { name = "Nodal Wand" , model = 25209} +models.main[21070] = { name = "Idris" , model = 25283} +models.main[21072] = { name = "Gada" , model = 25013} +models.main[21073] = { name = "Izcalli" , model = 24691} +models.main[21074] = { name = "Kupo Rod" , model = 24950} +models.main[21075] = { name = "Septoptic" , model = 24935} +models.main[21076] = { name = "Septoptic +1" , model = 24935} +models.main[21077] = { name = "Mjollnir" , model = 25129} +models.main[21078] = { name = "Yagrush" , model = 25132} +models.main[21079] = { name = "Gambanteinn" , model = 25156} +models.main[21080] = { name = "Idris" , model = 25283} +models.main[21082] = { name = "Tishtrya" , model = 25345} +models.main[21083] = { name = "Sucellus" , model = 24912} +models.main[21084] = { name = "Queller Rod" , model = 24816} +models.main[21085] = { name = "Solstice" , model = 25175} +models.main[21086] = { name = "Heartstopper" , model = 25331} +models.main[21087] = { name = "Heartstopper +1" , model = 25331} +models.main[21088] = { name = "Divinity" , model = 25327} +models.main[21089] = { name = "Rubicundity" , model = 25329} +models.main[21090] = { name = "Loxotic Mace" , model = 24679} +models.main[21091] = { name = "Loxotic Mace +1" , model = 24679} +models.main[21092] = { name = "Nibiru Cudgel" , model = 25317} +models.main[21093] = { name = "Blurred Rod" , model = 25324} +models.main[21094] = { name = "Blurred Rod +1" , model = 25324} +models.main[21095] = { name = "Heartbeater" , model = 25304} +models.main[21096] = { name = "Heartbeater +1" , model = 25304} +models.main[21097] = { name = "Leafkin Bopper" , model = 25299} +models.main[21098] = { name = "Leafkin Bopper +1" , model = 25299} +models.main[21099] = { name = "Magesmasher" , model = 24689} +models.main[21100] = { name = "Magesmasher +1" , model = 24689} +models.main[21101] = { name = "Herkuleskeule" , model = 24936} +models.main[21102] = { name = "Mafic Cudgel" , model = 24676} +models.main[21103] = { name = "Vadose Rod" , model = 24797} +models.main[21104] = { name = "Eosuchus Club" , model = 24686} +models.main[21105] = { name = "Nehushtan" , model = 25295} +models.main[21107] = { name = "Kyuka Uchiwa" , model = 25284} +models.main[21108] = { name = "Kyuka Uchiwa +1" , model = 25284} +models.main[21109] = { name = "Homestead Wand" , model = 24808} +models.main[21110] = { name = "Sindri" , model = 24688} +models.main[21111] = { name = "Bolelabunga" , model = 25203} +models.main[21112] = { name = "Gabaxorea" , model = 24802} +models.main[21113] = { name = "P. Sprig. Club" , model = 25213} +models.main[21114] = { name = "R. Sprig. Club" , model = 25211} +models.main[21115] = { name = "Aedold +2" , model = 25022} +models.main[21116] = { name = "Cagliostro's Rod" , model = 24816} +models.main[21117] = { name = "Hagoita" , model = 24973} +models.main[21118] = { name = "G. Spriggan Club" , model = 25212} +models.main[21119] = { name = "Eminent Wand" , model = 24804} +models.main[21120] = { name = "Patriarch Cane" , model = 24817} +models.main[21121] = { name = "Rose Couverte -1" , model = 24690} +models.main[21122] = { name = "Mes'yohi Rod" , model = 24796} +models.main[21123] = { name = "Cama. Wand" , model = 25187} +models.main[21124] = { name = "Dowser's Wand" , model = 24824} +models.main[21125] = { name = "Tamaxchi" , model = 25203} +models.main[21126] = { name = "Aedold +1" , model = 25022} +models.main[21127] = { name = "Forefront Wand" , model = 24808} +models.main[21128] = { name = "Mondaha Cudgel" , model = 24677} +models.main[21129] = { name = "Sharur" , model = 24936} +models.main[21130] = { name = "Sharur +1" , model = 24936} +models.main[21131] = { name = "Coalition Rod" , model = 25187} +models.main[21132] = { name = "Aedold" , model = 25022} +models.main[21133] = { name = "Sasah Wand +1" , model = 24955} +models.main[21134] = { name = "Sasah Wand" , model = 24955} +models.main[21135] = { name = "Claustrum" , model = 24918} +models.main[21136] = { name = "Claustrum" , model = 25130} +models.main[21137] = { name = "Tupsimati" , model = 25005} +models.main[21138] = { name = "Tupsimati" , model = 25146} +models.main[21139] = { name = "Laevateinn" , model = 24992} +models.main[21140] = { name = "Laevateinn" , model = 25133} +models.main[21141] = { name = "Nirvana" , model = 24993} +models.main[21142] = { name = "Nirvana" , model = 25143} +models.main[21143] = { name = "Hvergelmir" , model = 25092} +models.main[21144] = { name = "Hvergelmir" , model = 25157} +models.main[21145] = { name = "Exemplar" , model = 25346} +models.main[21147] = { name = "Khatvanga" , model = 25346} +models.main[21148] = { name = "Serenity" , model = 24865} +models.main[21149] = { name = "Espiritus" , model = 25018} +models.main[21150] = { name = "Akademos" , model = 25014} +models.main[21151] = { name = "Lathi" , model = 24881} +models.main[21152] = { name = "Reikikon" , model = 24878} +models.main[21153] = { name = "Malice Masher" , model = 25330} +models.main[21154] = { name = "Malice Masher +1" , model = 25330} +models.main[21155] = { name = "Marquetry Staff" , model = 24878} +models.main[21156] = { name = "Nibiru Staff" , model = 25318} +models.main[21157] = { name = "Blurred Staff" , model = 25038} +models.main[21158] = { name = "Blurred Staff +1" , model = 25038} +models.main[21159] = { name = "Marin Staff" , model = 24902} +models.main[21160] = { name = "Marin Staff +1" , model = 24902} +models.main[21161] = { name = "Mindmelter" , model = 25302} +models.main[21162] = { name = "Pouwhenua" , model = 24875} +models.main[21163] = { name = "Pouwhenua +1" , model = 24875} +models.main[21164] = { name = "Ababinili" , model = 24868} +models.main[21165] = { name = "Ababinili +1" , model = 24868} +models.main[21166] = { name = "Staccato Staff" , model = 24865} +models.main[21167] = { name = "Frazil Staff" , model = 24903} +models.main[21168] = { name = "Ungeri Staff" , model = 25201} +models.main[21169] = { name = "Keraunos" , model = 25296} +models.main[21170] = { name = "Nilgal Pole" , model = 25106} +models.main[21171] = { name = "Homestead Staff" , model = 24871} +models.main[21172] = { name = "Home. Scepter" , model = 25201} +models.main[21173] = { name = "Kaladanda" , model = 25180} +models.main[21174] = { name = "Gridarvor" , model = 24882} +models.main[21175] = { name = "Coeus" , model = 24881} +models.main[21176] = { name = "Ngqoqwanb" , model = 25210} +models.main[21177] = { name = "Twebuliij" , model = 24868} +models.main[21178] = { name = "Tumafyrig" , model = 24870} +models.main[21179] = { name = "Lehbrailg +2" , model = 25014} +models.main[21180] = { name = "Uffrat +2" , model = 25018} +models.main[21181] = { name = "Venabulum" , model = 25014} +models.main[21182] = { name = "Eminent Staff" , model = 24917} +models.main[21183] = { name = "Eminent Pole" , model = 24917} +models.main[21184] = { name = "Surma Staff" , model = 24937} +models.main[21185] = { name = "Boonwell Staff" , model = 24870} +models.main[21186] = { name = "Baqil Staff" , model = 25038} +models.main[21187] = { name = "Paikea -1" , model = 24878} +models.main[21188] = { name = "Cama. Staff" , model = 24869} +models.main[21189] = { name = "Cama. Pole" , model = 24871} +models.main[21191] = { name = "Voay Staff -1" , model = 25159} +models.main[21192] = { name = "Voay Staff" , model = 25159} +models.main[21193] = { name = "Voay Staff +1" , model = 25159} +models.main[21194] = { name = "Lehbrailg +1" , model = 25014} +models.main[21195] = { name = "Uffrat +1" , model = 25018} +models.main[21196] = { name = "Forefront Staff" , model = 24871} +models.main[21197] = { name = "Forefront Scepter" , model = 25201} +models.main[21198] = { name = "Soothsayer Staff" , model = 24907} +models.main[21199] = { name = "Yaskomo's Pole" , model = 24874} +models.main[21200] = { name = "Atinian Staff" , model = 24865} +models.main[21201] = { name = "Atinian Staff +1" , model = 24865} +models.main[21202] = { name = "Balsam Staff" , model = 24869} +models.main[21203] = { name = "Astralwatcher" , model = 24869} +models.main[21204] = { name = "Sortilevel Staff" , model = 24900} +models.main[21205] = { name = "Avitap Pole" , model = 24878} +models.main[21206] = { name = "Hemolele Staff" , model = 24865} +models.main[21207] = { name = "Hemolele Staff +1" , model = 24865} +models.main[21208] = { name = "Lehbrailg" , model = 25014} +models.main[21209] = { name = "Uffrat" , model = 25018} +models.main[21504] = { name = "Arasy Sainti" , model = 25082} +models.main[21505] = { name = "Arasy Sainti +1" , model = 25082} +models.main[21506] = { name = "Jolt Counter" , model = 24705} +models.main[21507] = { name = "Jolt Counter +1" , model = 24705} +models.main[21509] = { name = "Premium Mogti" , model = 25057} +models.main[21510] = { name = "Voluspa Knuckles" , model = 24705} +models.main[21511] = { name = "Hep. Baghnakhs" , model = 24717} +models.main[21512] = { name = "Hep. Baghnakhs +1" , model = 24717} +models.main[21513] = { name = "Raetic Baghnakhs" , model = 24719} +models.main[21514] = { name = "Rae. Baghnakhs +1" , model = 24719} +models.main[21515] = { name = "Tokko Knuckles" , model = 24705} +models.main[21516] = { name = "Ajja Knuckles" , model = 24711} +models.main[21517] = { name = "Eletta Knuckles" , model = 24710} +models.main[21518] = { name = "Kaja Knuckles" , model = 25055} +models.main[21519] = { name = "Karambit" , model = 25054} +models.main[21521] = { name = "Melee Fists" , model = 24697} +models.main[21522] = { name = "Hes. Fists" , model = 24697} +models.main[21523] = { name = "Sagitta" , model = 25056} +models.main[21524] = { name = "Pantin Fists" , model = 24697} +models.main[21525] = { name = "Pitre Fists" , model = 24697} +models.main[21526] = { name = "Xiucoatl" , model = 25056} +models.main[21554] = { name = "Arasy Knife" , model = 24733} +models.main[21555] = { name = "Arasy Knife +1" , model = 24733} +models.main[21556] = { name = "Beryllium Kris" , model = 24922} +models.main[21557] = { name = "Beryllium Kris +1" , model = 24922} +models.main[21558] = { name = "Rune Kris" , model = 24922} +models.main[21559] = { name = "Raetic Kris" , model = 24922} +models.main[21560] = { name = "Raetic Kris +1" , model = 24922} +models.main[21561] = { name = "Tokko Knife" , model = 24734} +models.main[21562] = { name = "Ajja Knife" , model = 24733} +models.main[21563] = { name = "Eletta Knife" , model = 25300} +models.main[21564] = { name = "Kaja Knife" , model = 25412} +models.main[21565] = { name = "Tauret" , model = 25423} +models.main[21566] = { name = "Voluspa Knife" , model = 24734} +models.main[21573] = { name = "Assassin's Knife" , model = 24733} +models.main[21574] = { name = "Plun. Knife" , model = 24733} +models.main[21575] = { name = "Gandring" , model = 25390} +models.main[21576] = { name = "Bard's Knife" , model = 24733} +models.main[21577] = { name = "Bihu Knife" , model = 24733} +models.main[21578] = { name = "Barfawc" , model = 25390} +models.main[21579] = { name = "Comm. Knife" , model = 24733} +models.main[21580] = { name = "Lanun Knife" , model = 24733} +models.main[21581] = { name = "Rostam" , model = 25390} +models.main[21582] = { name = "Etoile Knife" , model = 24733} +models.main[21583] = { name = "Horos Knife" , model = 24733} +models.main[21584] = { name = "Setan Kober" , model = 25390} +models.main[21604] = { name = "Arasy Sword" , model = 24854} +models.main[21605] = { name = "Arasy Sword +1" , model = 24854} +models.main[21606] = { name = "Enriching Sword" , model = 24826} +models.main[21607] = { name = "Enr. Sword +1" , model = 24826} +models.main[21608] = { name = "Onion Sword II" , model = 25363} +models.main[21609] = { name = "Save the Queen II" , model = 25366} +models.main[21610] = { name = "Hepatizon Rapier" , model = 24763} +models.main[21611] = { name = "Hep. Rapier +1" , model = 24763} +models.main[21612] = { name = "Raetic Blade" , model = 24830} +models.main[21613] = { name = "Raetic Blade +1" , model = 24830} +models.main[21614] = { name = "Hepatizon Sapara" , model = 24831} +models.main[21615] = { name = "Hep. Sapara +1" , model = 24831} +models.main[21617] = { name = "Tokko Sword" , model = 24843} +models.main[21618] = { name = "Ajja Sword" , model = 24848} +models.main[21619] = { name = "Eletta Sword" , model = 24864} +models.main[21620] = { name = "Kaja Sword" , model = 25413} +models.main[21621] = { name = "Naegling" , model = 25424} +models.main[21622] = { name = "Voluspa Sword" , model = 24851} +models.main[21625] = { name = "Duelist's Sword" , model = 24854} +models.main[21626] = { name = "Vitiation Sword" , model = 24854} +models.main[21627] = { name = "Crocea Mors" , model = 25395} +models.main[21628] = { name = "Valor Sword" , model = 24854} +models.main[21629] = { name = "Cabal. Sword" , model = 24854} +models.main[21630] = { name = "Moralltach" , model = 25395} +models.main[21631] = { name = "Mirage Sword" , model = 24854} +models.main[21632] = { name = "Luhlaza Sword" , model = 24854} +models.main[21633] = { name = "Zomorrodnegar" , model = 25395} +models.main[21635] = { name = "Malignance Sword" , model = 24856} +models.main[21654] = { name = "Arasy Claymore" , model = 24645} +models.main[21655] = { name = "Arasy Claymore +1" , model = 24645} +models.main[21656] = { name = "Dyrnwyn" , model = 24897} +models.main[21657] = { name = "Dyrnwyn +1" , model = 24897} +models.main[21658] = { name = "Brave Blade II" , model = 25368} +models.main[21659] = { name = "Beryllium Sword" , model = 24641} +models.main[21660] = { name = "Bery. Sword +1" , model = 24641} +models.main[21661] = { name = "Rune Algol" , model = 24962} +models.main[21662] = { name = "Raetic Algol" , model = 24962} +models.main[21663] = { name = "Raetic Algol +1" , model = 24962} +models.main[21665] = { name = "Voluspa Blade" , model = 24650} +models.main[21667] = { name = "Futhark Claymore" , model = 24640} +models.main[21668] = { name = "Peord Claymore" , model = 24640} +models.main[21669] = { name = "Morgelai" , model = 25386} +models.main[21670] = { name = "Tokko Claymore" , model = 24646} +models.main[21671] = { name = "Ajja Claymore" , model = 24645} +models.main[21672] = { name = "Eletta Claymore" , model = 25118} +models.main[21673] = { name = "Kaja Claymore" , model = 25414} +models.main[21674] = { name = "Nandaka" , model = 25425} +models.main[21682] = { name = "Lament" , model = 25384} +models.main[21683] = { name = "Ragnarok" , model = 25122} +models.main[21684] = { name = "Caladbolg" , model = 25149} +models.main[21685] = { name = "Epeolatry" , model = 25282} +models.main[21686] = { name = "Zulfiqar" , model = 25105} +models.main[21687] = { name = "Takoba" , model = 25118} +models.main[21688] = { name = "Montante" , model = 24953} +models.main[21689] = { name = "Montante +1" , model = 24953} +models.main[21690] = { name = "Ushenzi" , model = 24643} +models.main[21691] = { name = "Ushenzi +1" , model = 24643} +models.main[21693] = { name = "Irradiance Blade" , model = 25352} +models.main[21694] = { name = "Lionheart" , model = 25338} +models.main[21695] = { name = "Nullis" , model = 24650} +models.main[21696] = { name = "Nullis +1" , model = 24650} +models.main[21697] = { name = "Humility" , model = 25206} +models.main[21698] = { name = "Bidenhander" , model = 25281} +models.main[21699] = { name = "Nibiru Faussar" , model = 25310} +models.main[21700] = { name = "Blurred Claymore" , model = 25039} +models.main[21701] = { name = "Blurred Clay. +1" , model = 25039} +models.main[21702] = { name = "Kladenets" , model = 24650} +models.main[21703] = { name = "Kladenets +1" , model = 24650} +models.main[21704] = { name = "Arasy Tabar" , model = 24657} +models.main[21705] = { name = "Arasy Tabar +1" , model = 24657} +models.main[21706] = { name = "Barbarity" , model = 24667} +models.main[21707] = { name = "Barbarity +1" , model = 24667} +models.main[21708] = { name = "Beryllium Pick" , model = 24663} +models.main[21709] = { name = "Beryllium Pick +1" , model = 24663} +models.main[21710] = { name = "Raetic Axe" , model = 24661} +models.main[21711] = { name = "Raetic Axe +1" , model = 24661} +models.main[21712] = { name = "Voluspa Axe" , model = 24663} +models.main[21715] = { name = "Monster Axe" , model = 24657} +models.main[21716] = { name = "Ankusa Axe" , model = 24657} +models.main[21717] = { name = "Pangu" , model = 25387} +models.main[21718] = { name = "Tokko Axe" , model = 24658} +models.main[21719] = { name = "Ajja Axe" , model = 24657} +models.main[21720] = { name = "Eletta Axe" , model = 25167} +models.main[21721] = { name = "Kaja Axe" , model = 25426} +models.main[21722] = { name = "Dolichenus" , model = 25426} +models.main[21741] = { name = "Demonic Axe" , model = 25369} +models.main[21742] = { name = "Aern Axe" , model = 25403} +models.main[21744] = { name = "Gramk's Axe" , model = 25406} +models.main[21746] = { name = "Digirbalag" , model = 24658} +models.main[21747] = { name = "Freydis" , model = 25095} +models.main[21748] = { name = "Habilitator" , model = 24963} +models.main[21749] = { name = "Habilitator +1" , model = 24963} +models.main[21750] = { name = "Guttler" , model = 25123} +models.main[21751] = { name = "Aymur" , model = 25138} +models.main[21752] = { name = "Farsha" , model = 25150} +models.main[21753] = { name = "Tri-edge" , model = 25339} +models.main[21754] = { name = "Aganoshe" , model = 25027} +models.main[21755] = { name = "Hodadenon" , model = 25096} +models.main[21756] = { name = "Bravura" , model = 25124} +models.main[21757] = { name = "Conqueror" , model = 25131} +models.main[21758] = { name = "Ukonvasara" , model = 25151} +models.main[21761] = { name = "Za'Dha Chopper" , model = 24675} +models.main[21762] = { name = "Arasy Axe" , model = 24668} +models.main[21763] = { name = "Arasy Axe +1" , model = 24668} +models.main[21765] = { name = "Hepatizon Axe" , model = 24669} +models.main[21766] = { name = "Hepatizon Axe +1" , model = 24669} +models.main[21767] = { name = "Raetic Chopper" , model = 24911} +models.main[21768] = { name = "Raetic Chopper +1" , model = 24911} +models.main[21769] = { name = "Voluspa Chopper" , model = 24939} +models.main[21772] = { name = "War. Chopper" , model = 24668} +models.main[21773] = { name = "Agoge Chopper" , model = 24668} +models.main[21774] = { name = "Labraunda" , model = 25388} +models.main[21775] = { name = "Tokko Chopper" , model = 24674} +models.main[21776] = { name = "Ajja Chopper" , model = 24673} +models.main[21777] = { name = "Eletta Chopper" , model = 25096} +models.main[21778] = { name = "Kaja Chopper" , model = 25179} +models.main[21779] = { name = "Lycurgos" , model = 25179} +models.main[21804] = { name = "Obschine" , model = 24969} +models.main[21805] = { name = "Pixquizpan" , model = 24942} +models.main[21806] = { name = "Pixquizpan +1" , model = 24942} +models.main[21808] = { name = "Apocalypse" , model = 25126} +models.main[21809] = { name = "Liberator" , model = 25137} +models.main[21810] = { name = "Redemption" , model = 25152} +models.main[21812] = { name = "Arasy Scythe" , model = 24770} +models.main[21813] = { name = "Arasy Scythe +1" , model = 24770} +models.main[21815] = { name = "Maliya Sickle" , model = 24969} +models.main[21816] = { name = "Maliya Sickle +1" , model = 24969} +models.main[21817] = { name = "Rune Scythe" , model = 25097} +models.main[21818] = { name = "Raetic Scythe" , model = 25097} +models.main[21819] = { name = "Raetic Scythe +1" , model = 25097} +models.main[21820] = { name = "Lost Sickle" , model = 25371} +models.main[21821] = { name = "Lost Sickle +1" , model = 25371} +models.main[21822] = { name = "Voluspa Scythe" , model = 24770} +models.main[21823] = { name = "Abyss Scythe" , model = 24948} +models.main[21824] = { name = "Fallen's Scythe" , model = 24948} +models.main[21825] = { name = "Father Time" , model = 25391} +models.main[21826] = { name = "Tokko Scythe" , model = 24770} +models.main[21827] = { name = "Ajja Scythe" , model = 24770} +models.main[21828] = { name = "Eletta Scythe" , model = 24777} +models.main[21829] = { name = "Kaja Scythe" , model = 25418} +models.main[21830] = { name = "Drepanum" , model = 25418} +models.main[21854] = { name = "Reienkyo" , model = 24967} +models.main[21855] = { name = "Lembing" , model = 24790} +models.main[21857] = { name = "Gungnir" , model = 25125} +models.main[21858] = { name = "Ryunohige" , model = 25142} +models.main[21859] = { name = "Rhongomiant" , model = 25153} +models.main[21860] = { name = "Aern Spear" , model = 25404} +models.main[21862] = { name = "Mizukage Naginata" , model = 25375} +models.main[21863] = { name = "Tzee Xicu's Blade" , model = 25397} +models.main[21864] = { name = "Voluspa Lance" , model = 24785} +models.main[21865] = { name = "Arasy Lance" , model = 24946} +models.main[21866] = { name = "Arasy Lance +1" , model = 24946} +models.main[21869] = { name = "Exalted Spear" , model = 24782} +models.main[21870] = { name = "Exalted Spear +1" , model = 24782} +models.main[21871] = { name = "Raetic Halberd" , model = 24913} +models.main[21872] = { name = "Raetic Halberd +1" , model = 24913} +models.main[21876] = { name = "Wyrm Lance" , model = 24946} +models.main[21877] = { name = "Pteroslaver Lance" , model = 24946} +models.main[21878] = { name = "Aram" , model = 25393} +models.main[21879] = { name = "Tokko Lance" , model = 24925} +models.main[21880] = { name = "Ajja Lance" , model = 24967} +models.main[21881] = { name = "Eletta Lance" , model = 25029} +models.main[21882] = { name = "Kaja Lance" , model = 25417} +models.main[21883] = { name = "Shining One" , model = 25417} +models.main[21904] = { name = "Kanaria" , model = 24947} +models.main[21905] = { name = "Taka" , model = 25181} +models.main[21906] = { name = "Kikoku" , model = 25127} +models.main[21907] = { name = "Nagi" , model = 25141} +models.main[21908] = { name = "Kannagi" , model = 25154} +models.main[21909] = { name = "Yoshikiri" , model = 24976} +models.main[21910] = { name = "Yoshikiri +1" , model = 24976} +models.main[21912] = { name = "Voluspa Katana" , model = 24889} +models.main[21915] = { name = "Koga Shin." , model = 24889} +models.main[21916] = { name = "Mochi. Shin." , model = 24889} +models.main[21917] = { name = "Fudo Masamune" , model = 25392} +models.main[21918] = { name = "Tokko Katana" , model = 24889} +models.main[21919] = { name = "Ajja Katana" , model = 24885} +models.main[21920] = { name = "Eletta Katana" , model = 24976} +models.main[21921] = { name = "Kaja Katana" , model = 25419} +models.main[21922] = { name = "Gokotai" , model = 25419} +models.main[21923] = { name = "Debahocho" , model = 24888} +models.main[21924] = { name = "Debahocho +1" , model = 24888} +models.main[21954] = { name = "Amanomurakumo" , model = 25128} +models.main[21955] = { name = "Kogarasumaru" , model = 25140} +models.main[21956] = { name = "Masamune" , model = 25155} +models.main[21960] = { name = "Ashijiro no Tachi" , model = 24730} +models.main[21961] = { name = "Ashi. no Tachi +1" , model = 24730} +models.main[21963] = { name = "Beryllium Tachi" , model = 24730} +models.main[21964] = { name = "Beryllium Tachi +1" , model = 24730} +models.main[21965] = { name = "Zanmato" , model = 25364} +models.main[21966] = { name = "Zanmato +1" , model = 25364} +models.main[21967] = { name = "Melon Slicer" , model = 24944} +models.main[21968] = { name = "Saotome-no-Tachi" , model = 24724} +models.main[21969] = { name = "Sakonji-no-Tachi" , model = 24724} +models.main[21970] = { name = "Fusenaikyo" , model = 25389} +models.main[21971] = { name = "Tokko Tachi" , model = 24730} +models.main[21972] = { name = "Ajja Tachi" , model = 24732} +models.main[21973] = { name = "Eletta Tachi" , model = 24731} +models.main[21974] = { name = "Kaja Tachi" , model = 25420} +models.main[21975] = { name = "Hachimonji" , model = 25420} +models.main[21976] = { name = "Voluspa Tachi" , model = 24730} +models.main[22004] = { name = "Soulflayer's Wand" , model = 25399} +models.main[22006] = { name = "Voluspa Hammer" , model = 24688} +models.main[22015] = { name = "Arasy Rod" , model = 24794} +models.main[22016] = { name = "Arasy Rod +1" , model = 24794} +models.main[22017] = { name = "Seika Uchiwa" , model = 25374} +models.main[22018] = { name = "Seika Uchiwa +1" , model = 25374} +models.main[22019] = { name = "Jingly Rod" , model = 25377} +models.main[22020] = { name = "Jingly Rod +1" , model = 25377} +models.main[22021] = { name = "Ames" , model = 24805} +models.main[22022] = { name = "Ames +1" , model = 24805} +models.main[22023] = { name = "Beryllium Mace" , model = 24679} +models.main[22024] = { name = "Beryllium Mace +1" , model = 24679} +models.main[22025] = { name = "Raetic Rod" , model = 24912} +models.main[22026] = { name = "Raetic Rod +1" , model = 24912} +models.main[22027] = { name = "Tokko Rod" , model = 24795} +models.main[22028] = { name = "Ajja Rod" , model = 24794} +models.main[22029] = { name = "Eletta Rod" , model = 24816} +models.main[22030] = { name = "Kaja Rod" , model = 25421} +models.main[22031] = { name = "Maxentius" , model = 25421} +models.main[22033] = { name = "Cleric's Wand" , model = 24794} +models.main[22034] = { name = "Piety Wand" , model = 24794} +models.main[22035] = { name = "Asclepius" , model = 25394} +models.main[22036] = { name = "Bagua Wand" , model = 24794} +models.main[22037] = { name = "Sifang Wand" , model = 24794} +models.main[22038] = { name = "Bhima" , model = 25394} +models.main[22039] = { name = "Floral Hagoita" , model = 25411} +models.main[22054] = { name = "Grioavolr" , model = 25177} +models.main[22055] = { name = "Oranyan" , model = 24882} +models.main[22056] = { name = "Gozuki Mezuki" , model = 24937} +models.main[22057] = { name = "Contemplator" , model = 25018} +models.main[22058] = { name = "Contemplator +1" , model = 25018} +models.main[22060] = { name = "Claustrum" , model = 25130} +models.main[22061] = { name = "Tupsimati" , model = 25146} +models.main[22062] = { name = "Laevateinn" , model = 25133} +models.main[22063] = { name = "Nirvana" , model = 25143} +models.main[22064] = { name = "Hvergelmir" , model = 25157} +models.main[22065] = { name = "Aern Staff" , model = 25405} +models.main[22069] = { name = "Hapy Staff" , model = 25382} +models.main[22072] = { name = "Lamia Staff" , model = 25408} +models.main[22074] = { name = "Arasy Staff" , model = 24868} +models.main[22075] = { name = "Arasy Staff +1" , model = 24868} +models.main[22076] = { name = "Was" , model = 24882} +models.main[22077] = { name = "Was +1" , model = 24882} +models.main[22078] = { name = "Exalted Staff" , model = 24937} +models.main[22079] = { name = "Exalted Staff +1" , model = 24937} +models.main[22080] = { name = "Raetic Staff" , model = 24881} +models.main[22081] = { name = "Raetic Staff +1" , model = 24881} +models.main[22082] = { name = "Tokko Staff" , model = 24867} +models.main[22083] = { name = "Ajja Staff" , model = 24869} +models.main[22084] = { name = "Eletta Staff" , model = 24881} +models.main[22085] = { name = "Kaja Staff" , model = 25422} +models.main[22086] = { name = "Xoanon" , model = 25422} +models.main[22088] = { name = "Voluspa Pole" , model = 24874} +models.main[22091] = { name = "Sorcerer's Staff" , model = 24902} +models.main[22092] = { name = "Archmage's Staff" , model = 24902} +models.main[22093] = { name = "Kaumodaki" , model = 25396} +models.main[22094] = { name = "Summoner's Staff" , model = 24902} +models.main[22095] = { name = "Glyphic Staff" , model = 24902} +models.main[22096] = { name = "Draumstafir" , model = 25396} +models.main[22097] = { name = "Argute Staff" , model = 24902} +models.main[22098] = { name = "Pedagogy Staff" , model = 24902} +models.main[22099] = { name = "Musa" , model = 25396} \ No newline at end of file diff --git a/addons/DressUp/ranged.lua b/addons/DressUp/ranged.lua new file mode 100644 index 0000000000..a0072daa0e --- /dev/null +++ b/addons/DressUp/ranged.lua @@ -0,0 +1,656 @@ +-- Copyright © 2013, 2022 Cairthenn +-- 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 DressUp 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 Cairthenn 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. + + +models.ranged = {} + +models.ranged["None"] = { name = "empty" , enl = "empty", model = 32768 } + +models.ranged[17011] = { name="Ebisu Fishing Rod" , model = 32768} +models.ranged[17012] = { name="Judge's Rod" , model = 32768} +models.ranged[17013] = { name="Goldfish Basket" , model = 32768} +models.ranged[17014] = { name="Hume Fishing Rod" , model = 32768} +models.ranged[17015] = { name="Halcyon Rod" , model = 32768} +models.ranged[17152] = { name="Shortbow" , model = 32768} +models.ranged[17153] = { name="Self Bow" , model = 32768} +models.ranged[17154] = { name="Wrapped Bow" , model = 32768} +models.ranged[17155] = { name="Composite Bow" , model = 32768} +models.ranged[17156] = { name="Kaman" , model = 32768} +models.ranged[17157] = { name="Rapid Bow" , model = 32768} +models.ranged[17158] = { name="Rune Bow" , model = 32768} +models.ranged[17159] = { name="Freesword's Bow" , model = 32768} +models.ranged[17160] = { name="Longbow" , model = 32768} +models.ranged[17161] = { name="Power Bow" , model = 32768} +models.ranged[17162] = { name="Great Bow" , model = 32768} +models.ranged[17163] = { name="Battle Bow" , model = 32768} +models.ranged[17164] = { name="War Bow" , model = 32768} +models.ranged[17165] = { name="Arco de Velocidad" , model = 32768} +models.ranged[17166] = { name="Lamian Kaman" , model = 32768} +models.ranged[17167] = { name="Ryl.Arc. Longbow" , model = 32768} +models.ranged[17170] = { name="Speed Bow" , model = 32768} +models.ranged[17172] = { name="Wrapped Bow +1" , model = 32768} +models.ranged[17173] = { name="War Bow +1" , model = 32768} +models.ranged[17174] = { name="Judge's Bow" , model = 32768} +models.ranged[17175] = { name="Shortbow +1" , model = 32768} +models.ranged[17176] = { name="Self Bow +1" , model = 32768} +models.ranged[17177] = { name="Longbow +1" , model = 32768} +models.ranged[17178] = { name="Power Bow +1" , model = 32768} +models.ranged[17179] = { name="Composite Bow +1" , model = 32768} +models.ranged[17180] = { name="Great Bow +1" , model = 32768} +models.ranged[17181] = { name="Battle Bow +1" , model = 32768} +models.ranged[17182] = { name="Kaman +1" , model = 32768} +models.ranged[17183] = { name="Hunter's Longbow" , model = 32768} +models.ranged[17184] = { name="Assassin's Bow" , model = 32768} +models.ranged[17185] = { name="Siege Bow" , model = 32768} +models.ranged[17186] = { name="Sagittarius' Bow" , model = 32768} +models.ranged[17187] = { name="Eurytos' Bow" , model = 32768} +models.ranged[17188] = { name="Sniping Bow" , model = 32768} +models.ranged[17189] = { name="Rapid Bow +1" , model = 32768} +models.ranged[17190] = { name="Sarnga" , model = 32768} +models.ranged[17191] = { name="Pharaoh's Bow" , model = 32768} +models.ranged[17192] = { name="Ifrit's Bow" , model = 32768} +models.ranged[17193] = { name="Shadow Bow" , model = 32768} +models.ranged[17194] = { name="Shadow Bow +1" , model = 32768} +models.ranged[17195] = { name="Windurstian Bow" , model = 32768} +models.ranged[17196] = { name="Federation Bow" , model = 32768} +models.ranged[17197] = { name="San d'Orian Bow" , model = 32768} +models.ranged[17198] = { name="Kingdom Bow" , model = 32768} +models.ranged[17199] = { name="Loxley Bow" , model = 32768} +models.ranged[17200] = { name="Rosenbogen" , model = 32768} +models.ranged[17201] = { name="Rosenbogen +1" , model = 32768} +models.ranged[17202] = { name="Platoon Bow" , model = 32768} +models.ranged[17203] = { name="Shikar Bow" , model = 32768} +models.ranged[17204] = { name="Mighty Bow" , model = 32768} +models.ranged[17205] = { name="Gendawa" , model = 32768} +models.ranged[17206] = { name="Gendawa +1" , model = 32768} +models.ranged[17207] = { name="Expunger" , model = 32768} +models.ranged[17208] = { name="Hamayumi" , model = 32768} +models.ranged[17209] = { name="Martial Bow" , model = 32768} +models.ranged[17210] = { name="Martial Gun" , model = 32768} +models.ranged[17211] = { name="Almogavar Bow" , model = 32768} +models.ranged[17212] = { name="Selene's Bow" , model = 32768} +models.ranged[17213] = { name="Staurobow" , model = 32768} +models.ranged[17214] = { name="Staurobow +1" , model = 32768} +models.ranged[17215] = { name="Thug's Zamburak" , model = 32768} +models.ranged[17216] = { name="Light Crossbow" , model = 32768} +models.ranged[17217] = { name="Crossbow" , model = 32768} +models.ranged[17218] = { name="Zamburak" , model = 32768} +models.ranged[17219] = { name="Arbalest" , model = 32768} +models.ranged[17220] = { name="Heavy Crossbow" , model = 32768} +models.ranged[17221] = { name="Rpt. Crossbow" , model = 32768} +models.ranged[17222] = { name="Hexagun" , model = 32768} +models.ranged[17223] = { name="Lgn. Crossbow" , model = 32768} +models.ranged[17224] = { name="Killer Crossbow" , model = 32768} +models.ranged[17225] = { name="Crossbow +1" , model = 32768} +models.ranged[17226] = { name="Arbalest +1" , model = 32768} +models.ranged[17227] = { name="Heavy Crossbow+1" , model = 32768} +models.ranged[17228] = { name="Light Crossbow +1" , model = 32768} +models.ranged[17229] = { name="Zamburak +1" , model = 32768} +models.ranged[17230] = { name="Power Crossbow" , model = 32768} +models.ranged[17231] = { name="Tell's Crossbow" , model = 32768} +models.ranged[17232] = { name="Lion Crossbow" , model = 32768} +models.ranged[17233] = { name="Machine Crossbow" , model = 32768} +models.ranged[17234] = { name="Flagel. Crossbow" , model = 32768} +models.ranged[17235] = { name="Armbrust" , model = 32768} +models.ranged[17236] = { name="Leo Crossbow" , model = 32768} +models.ranged[17237] = { name="Leo Crossbow +1" , model = 32768} +models.ranged[17238] = { name="Bas. Crossbow" , model = 32768} +models.ranged[17239] = { name="Rep. Crossbow" , model = 32768} +models.ranged[17240] = { name="Lightning Bow" , model = 32768} +models.ranged[17241] = { name="Lightning Bow +1" , model = 32768} +models.ranged[17242] = { name="Velocity Bow" , model = 32768} +models.ranged[17243] = { name="Velocity Bow +1" , model = 32768} +models.ranged[17244] = { name="Othinus' Bow" , model = 32768} +models.ranged[17245] = { name="Grosveneur's Bow" , model = 32768} +models.ranged[17246] = { name="Ziska's Crossbow" , model = 32768} +models.ranged[17247] = { name="Rikonodo" , model = 32768} +models.ranged[17248] = { name="Arquebus" , model = 32768} +models.ranged[17249] = { name="Magoichi's Gun" , model = 32768} +models.ranged[17250] = { name="Matchlock Gun" , model = 32768} +models.ranged[17251] = { name="Hellfire" , model = 32768} +models.ranged[17252] = { name="Culverin" , model = 32768} +models.ranged[17253] = { name="Musketeer Gun" , model = 32768} +models.ranged[17254] = { name="Arquebus +1" , model = 32768} +models.ranged[17255] = { name="Hakenbuechse" , model = 32768} +models.ranged[17256] = { name="Serpentine Gun" , model = 32768} +models.ranged[17257] = { name="Bandit's Gun" , model = 32768} +models.ranged[17258] = { name="Bandit's Gun +1" , model = 32768} +models.ranged[17259] = { name="Pirate's Gun" , model = 32768} +models.ranged[17260] = { name="Pirate's Gun +1" , model = 32768} +models.ranged[17261] = { name="Matchlock Gun +1" , model = 32768} +models.ranged[17262] = { name="Corsair's Gun" , model = 32768} +models.ranged[17263] = { name="Corsair's Gun +1" , model = 32768} +models.ranged[17264] = { name="Hellfire +1" , model = 32768} +models.ranged[17265] = { name="Tanegashima" , model = 32768} +models.ranged[17266] = { name="Tanegashima +1" , model = 32768} +models.ranged[17267] = { name="Negoroshiki" , model = 32768} +models.ranged[17268] = { name="Negoroshiki +1" , model = 32768} +models.ranged[17269] = { name="Musketeer Gun +1" , model = 32768} +models.ranged[17270] = { name="Musketeer Gun +2" , model = 32768} +models.ranged[17271] = { name="Platoon Gun" , model = 32768} +models.ranged[17272] = { name="Military Gun" , model = 32768} +models.ranged[17273] = { name="Phineus' Gun" , model = 32768} +models.ranged[17274] = { name="Deluxe Carbine" , model = 32768} +models.ranged[17275] = { name="Coffinmaker" , model = 32768} +models.ranged[17279] = { name="Moonring Blade +1" , model = 32768} +models.ranged[17280] = { name="Boomerang" , model = 32768} +models.ranged[17281] = { name="Wingedge" , model = 32768} +models.ranged[17282] = { name="Cmb.Cst. B'merang" , model = 32768} +models.ranged[17283] = { name="Jr.Msk. Chakram" , model = 32768} +models.ranged[17284] = { name="Chakram" , model = 32768} +models.ranged[17285] = { name="Moonring Blade" , model = 32768} +models.ranged[17286] = { name="Rising Sun" , model = 32768} +models.ranged[17287] = { name="Boomerang +1" , model = 32768} +models.ranged[17288] = { name="Wingedge +1" , model = 32768} +models.ranged[17289] = { name="Chakram +1" , model = 32768} +models.ranged[17290] = { name="Coarse Boomerang" , model = 32768} +models.ranged[17291] = { name="Flame Boomerang" , model = 32768} +models.ranged[17292] = { name="Long Boomerang" , model = 32768} +models.ranged[17293] = { name="Yagudo Freezer" , model = 32768} +models.ranged[17294] = { name="Comet Tail" , model = 32768} +models.ranged[17295] = { name="Rising Sun +1" , model = 32768} +models.ranged[17344] = { name="Cornette" , model = 32768} +models.ranged[17345] = { name="Flute" , model = 32768} +models.ranged[17346] = { name="Siren Flute" , model = 32768} +models.ranged[17347] = { name="Piccolo" , model = 32768} +models.ranged[17348] = { name="Traversiere" , model = 32768} +models.ranged[17349] = { name="Faerie Piccolo" , model = 32768} +models.ranged[17350] = { name="Angel's Flute" , model = 32768} +models.ranged[17351] = { name="Gemshorn" , model = 32768} +models.ranged[17352] = { name="Horn" , model = 32768} +models.ranged[17353] = { name="Maple Harp" , model = 32768} +models.ranged[17354] = { name="Harp" , model = 32768} +models.ranged[17355] = { name="Rose Harp" , model = 32768} +models.ranged[17356] = { name="Lamia Harp" , model = 32768} +models.ranged[17357] = { name="Ebony Harp" , model = 32768} +models.ranged[17358] = { name="Oneiros Harp" , model = 32768} +models.ranged[17359] = { name="Mythic Harp" , model = 32768} +models.ranged[17360] = { name="Langeleik" , model = 32768} +models.ranged[17361] = { name="Crumhorn" , model = 32768} +models.ranged[17362] = { name="Shofar" , model = 32768} +models.ranged[17363] = { name="Mass Chalemie" , model = 32768} +models.ranged[17364] = { name="Cythara Anglica" , model = 32768} +models.ranged[17365] = { name="Frenzy Fife" , model = 32768} +models.ranged[17366] = { name="Mary's Horn" , model = 32768} +models.ranged[17367] = { name="Ryl.Spr. Horn" , model = 32768} +models.ranged[17368] = { name="Piccolo +1" , model = 32768} +models.ranged[17369] = { name="Cornette +1" , model = 32768} +models.ranged[17370] = { name="Gemshorn +1" , model = 32768} +models.ranged[17371] = { name="Horn +1" , model = 32768} +models.ranged[17372] = { name="Flute +1" , model = 32768} +models.ranged[17373] = { name="Maple Harp +1" , model = 32768} +models.ranged[17374] = { name="Harp +1" , model = 32768} +models.ranged[17375] = { name="Traversiere +1" , model = 32768} +models.ranged[17376] = { name="Rose Harp +1" , model = 32768} +models.ranged[17377] = { name="Crumhorn +1" , model = 32768} +models.ranged[17378] = { name="Angel's Flute +1" , model = 32768} +models.ranged[17379] = { name="Hamelin Flute" , model = 32768} +models.ranged[17380] = { name="Mithran Fish. Rod" , model = 32768} +models.ranged[17381] = { name="Comp. Fishing Rod" , model = 32768} +models.ranged[17382] = { name="S.H. Fishing Rod" , model = 32768} +models.ranged[17383] = { name="Clothespole" , model = 32768} +models.ranged[17384] = { name="Carbon Fish. Rod" , model = 32768} +models.ranged[17385] = { name="Glass Fiber F. Rod" , model = 32768} +models.ranged[17386] = { name="Lu Shang's F. Rod" , model = 32768} +models.ranged[17387] = { name="Tarutaru F. Rod" , model = 32768} +models.ranged[17388] = { name="Fastwater F. Rod" , model = 32768} +models.ranged[17389] = { name="Bamboo Fish. Rod" , model = 32768} +models.ranged[17390] = { name="Yew Fishing Rod" , model = 32768} +models.ranged[17391] = { name="Willow Fish. Rod" , model = 32768} +models.ranged[17832] = { name="Shofar +1" , model = 32768} +models.ranged[17833] = { name="Ebony Harp +1" , model = 32768} +models.ranged[17834] = { name="Mythic Harp +1" , model = 32768} +models.ranged[17835] = { name="San d'Orian Horn" , model = 32768} +models.ranged[17836] = { name="Kingdom Horn" , model = 32768} +models.ranged[17837] = { name="Cyt. Anglica +1" , model = 32768} +models.ranged[17838] = { name="Harlequin's Horn" , model = 32768} +models.ranged[17839] = { name="Military Harp" , model = 32768} +models.ranged[17840] = { name="Angel Lyre" , model = 32768} +models.ranged[17841] = { name="Nursemaid's Harp" , model = 32768} +models.ranged[17842] = { name="Sorrowful Harp" , model = 32768} +models.ranged[17843] = { name="Oliphant" , model = 32768} +models.ranged[17844] = { name="Flute +2" , model = 32768} +models.ranged[17845] = { name="Traversiere +2" , model = 32768} +models.ranged[17846] = { name="Cornette +2" , model = 32768} +models.ranged[17847] = { name="Crumhorn +2" , model = 32768} +models.ranged[17848] = { name="Ebony Harp +2" , model = 32768} +models.ranged[17849] = { name="Hellish Bugle" , model = 32768} +models.ranged[17850] = { name="Hellish Bugle +1" , model = 32768} +models.ranged[17851] = { name="Storm Fife" , model = 32768} +models.ranged[17852] = { name="Requiem Flute" , model = 32768} +models.ranged[17853] = { name="Iron Ram Horn" , model = 32768} +models.ranged[17854] = { name="Cradle Horn" , model = 32768} +models.ranged[17855] = { name="Ney" , model = 32768} +models.ranged[17856] = { name="Syrinx" , model = 32768} +models.ranged[17857] = { name="Animator +1" , model = 32768} +models.ranged[17858] = { name="Turbo Animator" , model = 32768} +models.ranged[17859] = { name="Animator" , model = 32768} +models.ranged[17923] = { name="Deluxe Animator" , model = 32768} +models.ranged[18132] = { name="Cmb.Cst.Bmrng +1" , model = 32768} +models.ranged[18133] = { name="Cmb.Cst.Bmrng +2" , model = 32768} +models.ranged[18134] = { name="Jr.Msk.Chakram +1" , model = 32768} +models.ranged[18135] = { name="Jr.Msk.Chakram +2" , model = 32768} +models.ranged[18141] = { name="Ungur Boomerang" , model = 32768} +models.ranged[18142] = { name="Shigeto Bow" , model = 32768} +models.ranged[18143] = { name="Shigeto Bow +1" , model = 32768} +models.ranged[18144] = { name="Bow of Trials" , model = 32768} +models.ranged[18145] = { name="Mst.Cst. Bow" , model = 32768} +models.ranged[18146] = { name="Gun of Trials" , model = 32768} +models.ranged[18147] = { name="Culverin +1" , model = 32768} +models.ranged[18170] = { name="Platoon Edge" , model = 32768} +models.ranged[18171] = { name="Platoon Disc" , model = 32768} +models.ranged[18172] = { name="Light Boomerang" , model = 32768} +models.ranged[18231] = { name="Death Chakram" , model = 32768} +models.ranged[18245] = { name="Aureole" , model = 32768} +models.ranged[18246] = { name="Rogetsurin" , model = 32768} +models.ranged[18332] = { name="Relic Gun" , model = 32768} +models.ranged[18333] = { name="Marksman Gun" , model = 32768} +models.ranged[18334] = { name="Dynamis Gun" , model = 32768} +models.ranged[18335] = { name="Ferdinand" , model = 32768} +models.ranged[18336] = { name="Annihilator" , model = 32768} +models.ranged[18337] = { name="Annihilator" , model = 32768} +models.ranged[18338] = { name="Relic Horn" , model = 32768} +models.ranged[18339] = { name="Pyrrhic Horn" , model = 32768} +models.ranged[18340] = { name="Dynamis horn" , model = 32768} +models.ranged[18341] = { name="Millennium Horn" , model = 32768} +models.ranged[18342] = { name="Gjallarhorn" , model = 32768} +models.ranged[18343] = { name="Pan's Horn" , model = 32768} +models.ranged[18344] = { name="Relic Bow" , model = 32768} +models.ranged[18345] = { name="Wolver Bow" , model = 32768} +models.ranged[18346] = { name="Dynamis Bow" , model = 32768} +models.ranged[18347] = { name="Futatokoroto" , model = 32768} +models.ranged[18348] = { name="Yoichinoyumi" , model = 32768} +models.ranged[18349] = { name="Yoichinoyumi" , model = 32768} +models.ranged[18571] = { name="Daurdabla" , model = 32768} +models.ranged[18572] = { name="Gjallarhorn" , model = 32768} +models.ranged[18573] = { name="Pyf Harp" , model = 32768} +models.ranged[18574] = { name="Daurdabla" , model = 32768} +models.ranged[18575] = { name="Daurdabla" , model = 32768} +models.ranged[18576] = { name="Daurdabla" , model = 32768} +models.ranged[18577] = { name="Gjallarhorn" , model = 32768} +models.ranged[18578] = { name="Gjallarhorn" , model = 32768} +models.ranged[18579] = { name="Gjallarhorn" , model = 32768} +models.ranged[18580] = { name="Gjallarhorn" , model = 32768} +models.ranged[18649] = { name="Annihilator" , model = 32768} +models.ranged[18650] = { name="Yoichinoyumi" , model = 32768} +models.ranged[18663] = { name="Annihilator" , model = 32768} +models.ranged[18664] = { name="Yoichinoyumi" , model = 32768} +models.ranged[18677] = { name="Annihilator" , model = 32768} +models.ranged[18678] = { name="Yoichinoyumi" , model = 32768} +models.ranged[18679] = { name="Soulgauger SGR-1" , model = 32768} +models.ranged[18682] = { name="Lamian Kaman +1" , model = 32768} +models.ranged[18683] = { name="Imperial Bow" , model = 32768} +models.ranged[18684] = { name="Storm Zamburak" , model = 32768} +models.ranged[18685] = { name="Imperial Kaman" , model = 32768} +models.ranged[18686] = { name="Imperial Gun" , model = 32768} +models.ranged[18687] = { name="Hexagun +1" , model = 32768} +models.ranged[18688] = { name="Lamian Kaman -1" , model = 32768} +models.ranged[18692] = { name="Mamoolbane" , model = 32768} +models.ranged[18693] = { name="Lamiabane" , model = 32768} +models.ranged[18694] = { name="Trollbane" , model = 32768} +models.ranged[18695] = { name="Cerberus Bow" , model = 32768} +models.ranged[18701] = { name="Cerberus Bow +1" , model = 32768} +models.ranged[18702] = { name="Trump Gun" , model = 32768} +models.ranged[18703] = { name="Shark Gun" , model = 32768} +models.ranged[18704] = { name="Darksteel Hexagun" , model = 32768} +models.ranged[18705] = { name="Dst. Hexagun +1" , model = 32768} +models.ranged[18706] = { name="Peacemaker" , model = 32768} +models.ranged[18708] = { name="Snakeeye" , model = 32768} +models.ranged[18709] = { name="Snakeeye +1" , model = 32768} +models.ranged[18710] = { name="Seadog Gun" , model = 32768} +models.ranged[18711] = { name="Seadog Gun +1" , model = 32768} +models.ranged[18714] = { name="Vali's Bow" , model = 32768} +models.ranged[18715] = { name="Mars's Hexagun" , model = 32768} +models.ranged[18716] = { name="Mars's Hexagun +1" , model = 32768} +models.ranged[18717] = { name="Perdu Bow" , model = 32768} +models.ranged[18718] = { name="Perdu Crossbow" , model = 32768} +models.ranged[18719] = { name="Killer Bow" , model = 32768} +models.ranged[18720] = { name="Quicksilver" , model = 32768} +models.ranged[18721] = { name="Soultrapper" , model = 32768} +models.ranged[18724] = { name="Soultrapper 2000" , model = 32768} +models.ranged[18727] = { name="Fourth Gun" , model = 32768} +models.ranged[18728] = { name="Cobra Bow" , model = 32768} +models.ranged[18736] = { name="Fay Gendawa" , model = 32768} +models.ranged[18737] = { name="Fane Hexagun" , model = 32768} +models.ranged[18831] = { name="Crooner's Cithara" , model = 32768} +models.ranged[18832] = { name="Apollo's Flute" , model = 32768} +models.ranged[18833] = { name="Cantabank's Horn" , model = 32768} +models.ranged[18834] = { name="Vihuela" , model = 32768} +models.ranged[18839] = { name="Daurdabla" , model = 32768} +models.ranged[18840] = { name="Gjallarhorn" , model = 32768} +models.ranged[18933] = { name="Harrier" , model = 32768} +models.ranged[18934] = { name="Condor" , model = 32768} +models.ranged[18935] = { name="Bateleur" , model = 32768} +models.ranged[18936] = { name="Sparrowhawk" , model = 32768} +models.ranged[18937] = { name="Bedlam" , model = 32768} +models.ranged[18938] = { name="Spitfire" , model = 32768} +models.ranged[18939] = { name="Mayhem" , model = 32768} +models.ranged[18940] = { name="Anarchy" , model = 32768} +models.ranged[18981] = { name="Gastraphetes" , model = 32768} +models.ranged[18987] = { name="Death Penalty" , model = 32768} +models.ranged[19001] = { name="Gastraphetes" , model = 32768} +models.ranged[19007] = { name="Death Penalty" , model = 32768} +models.ranged[19070] = { name="Gastraphetes" , model = 32768} +models.ranged[19076] = { name="Death Penalty" , model = 32768} +models.ranged[19090] = { name="Gastraphetes" , model = 32768} +models.ranged[19096] = { name="Death Penalty" , model = 32768} +models.ranged[19187] = { name="Murti Bow" , model = 32768} +models.ranged[19188] = { name="Killer Shortbow" , model = 32768} +models.ranged[19189] = { name="Virtus Crossbow" , model = 32768} +models.ranged[19190] = { name="Fluid Crossbow" , model = 32768} +models.ranged[19191] = { name="Exequy Gun" , model = 32768} +models.ranged[19192] = { name="Awilda's Gun" , model = 32768} +models.ranged[19203] = { name="War Hoop" , model = 32768} +models.ranged[19204] = { name="Fiendtrapper" , model = 32768} +models.ranged[19206] = { name="Silver Cassandra" , model = 32768} +models.ranged[19207] = { name="Great Cassandra" , model = 32768} +models.ranged[19208] = { name="Grand Crossbow" , model = 32768} +models.ranged[19209] = { name="Molybdosis" , model = 32768} +models.ranged[19215] = { name="Amanokakoyumi" , model = 32768} +models.ranged[19216] = { name="Failnaught" , model = 32768} +models.ranged[19217] = { name="Basilisk" , model = 32768} +models.ranged[19218] = { name="Murderer" , model = 32768} +models.ranged[19221] = { name="Firefly" , model = 32768} +models.ranged[19222] = { name="Wurger" , model = 32768} +models.ranged[19224] = { name="Musketoon" , model = 32768} +models.ranged[19225] = { name="Musketoon +1" , model = 32768} +models.ranged[19226] = { name="Blunderbuss" , model = 32768} +models.ranged[19227] = { name="Blunderbuss +1" , model = 32768} +models.ranged[19230] = { name="Nous Arbalest" , model = 32768} +models.ranged[19231] = { name="Tracker's Bow" , model = 32768} +models.ranged[19232] = { name="Octant" , model = 32768} +models.ranged[19233] = { name="Lyft Crossbow" , model = 32768} +models.ranged[19234] = { name="Lyft Hexagun" , model = 32768} +models.ranged[19235] = { name="Veuglaire" , model = 32768} +models.ranged[19241] = { name="Tracker's Bow +1" , model = 32768} +models.ranged[19260] = { name="Raider's Bmrng." , model = 32768} +models.ranged[19261] = { name="Jinx Discus" , model = 32768} +models.ranged[19263] = { name="Amazon Bow" , model = 32768} +models.ranged[19264] = { name="Amazon Bow +1" , model = 32768} +models.ranged[19265] = { name="Darkwing" , model = 32768} +models.ranged[19266] = { name="Darkwing +1" , model = 32768} +models.ranged[19267] = { name="Ribauldequin" , model = 32768} +models.ranged[19268] = { name="Ribauldequin +1" , model = 32768} +models.ranged[19319] = { name="MMM Fishing Rod" , model = 32768} +models.ranged[19320] = { name="Lu Sh. F. Rod +1" , model = 32768} +models.ranged[19321] = { name="Ebisu F. Rod +1" , model = 32768} +models.ranged[19387] = { name="Sparrow" , model = 32768} +models.ranged[19388] = { name="Kestrel" , model = 32768} +models.ranged[19389] = { name="Astrild" , model = 32768} +models.ranged[19390] = { name="Goshawk" , model = 32768} +models.ranged[19391] = { name="Gyrfalcon" , model = 32768} +models.ranged[19392] = { name="Thunderstick" , model = 32768} +models.ranged[19393] = { name="Blue Steel" , model = 32768} +models.ranged[19394] = { name="Magnatus" , model = 32768} +models.ranged[19395] = { name="Dragonmaw" , model = 32768} +models.ranged[19396] = { name="Huracan" , model = 32768} +models.ranged[19409] = { name="Gandiva" , model = 32768} +models.ranged[19410] = { name="Armageddon" , model = 32768} +models.ranged[19468] = { name="Gandiva" , model = 32768} +models.ranged[19469] = { name="Armageddon" , model = 32768} +models.ranged[19526] = { name="Harrier +1" , model = 32768} +models.ranged[19527] = { name="Condor +1" , model = 32768} +models.ranged[19528] = { name="Bateleur +1" , model = 32768} +models.ranged[19529] = { name="Sparrowhawk +1" , model = 32768} +models.ranged[19530] = { name="Bedlam +1" , model = 32768} +models.ranged[19531] = { name="Spitfire +1" , model = 32768} +models.ranged[19532] = { name="Mayhem +1" , model = 32768} +models.ranged[19533] = { name="Anarchy +1" , model = 32768} +models.ranged[19546] = { name="Gandiva" , model = 32768} +models.ranged[19547] = { name="Armageddon" , model = 32768} +models.ranged[19604] = { name="Harrier +2" , model = 32768} +models.ranged[19605] = { name="Condor +2" , model = 32768} +models.ranged[19606] = { name="Bateleur +2" , model = 32768} +models.ranged[19607] = { name="Sparrowhawk +2" , model = 32768} +models.ranged[19608] = { name="Bedlam +2" , model = 32768} +models.ranged[19609] = { name="Spitfire +2" , model = 32768} +models.ranged[19610] = { name="Mayhem +2" , model = 32768} +models.ranged[19611] = { name="Anarchy +2" , model = 32768} +models.ranged[19622] = { name="Gastraphetes" , model = 32768} +models.ranged[19628] = { name="Death Penalty" , model = 32768} +models.ranged[19644] = { name="Gandiva" , model = 32768} +models.ranged[19645] = { name="Armageddon" , model = 32768} +models.ranged[19702] = { name="Harrier +3" , model = 32768} +models.ranged[19703] = { name="Condor +3" , model = 32768} +models.ranged[19704] = { name="Bateleur +3" , model = 32768} +models.ranged[19705] = { name="Sparrowhawk +3" , model = 32768} +models.ranged[19706] = { name="Bedlam +3" , model = 32768} +models.ranged[19707] = { name="Spitfire +3" , model = 32768} +models.ranged[19708] = { name="Mayhem +3" , model = 32768} +models.ranged[19709] = { name="Anarchy +3" , model = 32768} +models.ranged[19720] = { name="Gastraphetes" , model = 32768} +models.ranged[19726] = { name="Death Penalty" , model = 32768} +models.ranged[19730] = { name="Vision Bow" , model = 32768} +models.ranged[19731] = { name="Suppressor Gun" , model = 32768} +models.ranged[19732] = { name="Miramar Gun" , model = 32768} +models.ranged[19733] = { name="Beursault Bow" , model = 32768} +models.ranged[19734] = { name="Beursault Bow +1" , model = 32768} +models.ranged[19735] = { name="Cecchino's Fucile" , model = 32768} +models.ranged[19736] = { name="Cecchin. Fucile +1" , model = 32768} +models.ranged[19737] = { name="Percept Bow" , model = 32768} +models.ranged[19738] = { name="Aife's Bow" , model = 32768} +models.ranged[19739] = { name="Moros Crossbow" , model = 32768} +models.ranged[19740] = { name="Stoertebeker" , model = 32768} +models.ranged[19741] = { name="Handgonne" , model = 32768} +models.ranged[19742] = { name="Handgonne +1" , model = 32768} +models.ranged[19743] = { name="Opprimo" , model = 32768} +models.ranged[19744] = { name="Opprimo +1" , model = 32768} +models.ranged[19758] = { name="Annihilator" , model = 32768} +models.ranged[19759] = { name="Yoichinoyumi" , model = 32768} +models.ranged[19770] = { name="Aliyat Chakram" , model = 32768} +models.ranged[19784] = { name="Lanner Bow" , model = 32768} +models.ranged[19785] = { name="Lanner Bow +1" , model = 32768} +models.ranged[19786] = { name="Nurigomeyumi" , model = 32768} +models.ranged[19787] = { name="Nurigomeyumi +1" , model = 32768} +models.ranged[19817] = { name="Gandiva" , model = 32768} +models.ranged[19818] = { name="Armageddon" , model = 32768} +models.ranged[19829] = { name="Gastraphetes" , model = 32768} +models.ranged[19835] = { name="Death Penalty" , model = 32768} +models.ranged[19851] = { name="Annihilator" , model = 32768} +models.ranged[19852] = { name="Yoichinoyumi" , model = 32768} +models.ranged[19865] = { name="Gandiva" , model = 32768} +models.ranged[19866] = { name="Armageddon" , model = 32768} +models.ranged[19940] = { name="Circinae" , model = 32768} +models.ranged[19941] = { name="Gymnogyps" , model = 32768} +models.ranged[19942] = { name="Terathopus" , model = 32768} +models.ranged[19943] = { name="Accipiter" , model = 32768} +models.ranged[19944] = { name="Mollfrith" , model = 32768} +models.ranged[19945] = { name="Aithon" , model = 32768} +models.ranged[19946] = { name="Erra" , model = 32768} +models.ranged[19947] = { name="Ataktos" , model = 32768} +models.ranged[19958] = { name="Gastraphetes" , model = 32768} +models.ranged[19964] = { name="Death Penalty" , model = 32768} +models.ranged[21210] = { name="Yoichinoyumi" , model = 32768} +models.ranged[21211] = { name="Yoichinoyumi" , model = 32768} +models.ranged[21212] = { name="Gandiva" , model = 32768} +models.ranged[21213] = { name="Gandiva" , model = 32768} +models.ranged[21214] = { name="Nobility" , model = 32768} +models.ranged[21215] = { name="Vijaya Bow" , model = 32768} +models.ranged[21216] = { name="Nibiru Bow" , model = 32768} +models.ranged[21217] = { name="Blurred Bow" , model = 32768} +models.ranged[21218] = { name="Blurred Bow +1" , model = 32768} +models.ranged[21219] = { name="Paloma Bow" , model = 32768} +models.ranged[21220] = { name="Paloma Bow +1" , model = 32768} +models.ranged[21221] = { name="Brahmastra" , model = 32768} +models.ranged[21222] = { name="Mengado" , model = 32768} +models.ranged[21223] = { name="Mengado +1" , model = 32768} +models.ranged[21224] = { name="Phaosphaelia" , model = 32768} +models.ranged[21226] = { name="Homestead Bow" , model = 32768} +models.ranged[21227] = { name="Hangaku-no-Yumi" , model = 32768} +models.ranged[21228] = { name="Falubeza" , model = 32768} +models.ranged[21229] = { name="Cibitshavore" , model = 32768} +models.ranged[21230] = { name="Bocluamni +2" , model = 32768} +models.ranged[21231] = { name="Eminent Bow" , model = 32768} +models.ranged[21232] = { name="Phulax Bow" , model = 32768} +models.ranged[21233] = { name="Ajjub Bow" , model = 32768} +models.ranged[21234] = { name="Circinae -1" , model = 32768} +models.ranged[21235] = { name="Cama. Bow" , model = 32768} +models.ranged[21236] = { name="Bocluamni +1" , model = 32768} +models.ranged[21237] = { name="Forefront Bow" , model = 32768} +models.ranged[21238] = { name="Speleogen Bow" , model = 32768} +models.ranged[21239] = { name="Echidna's Bow" , model = 32768} +models.ranged[21240] = { name="Echidna's Bow +1" , model = 32768} +models.ranged[21241] = { name="Coalition Bow" , model = 32768} +models.ranged[21242] = { name="Bocluamni" , model = 32768} +models.ranged[21243] = { name="Ahkormaar Bow" , model = 32768} +models.ranged[21244] = { name="Ahkormaar Bow +1" , model = 32768} +models.ranged[21245] = { name="Guglielmo's Bow" , model = 32768} +models.ranged[21246] = { name="Gastraphetes" , model = 32768} +models.ranged[21247] = { name="Gastraphetes" , model = 32768} +models.ranged[21248] = { name="Home. Bowgun" , model = 32768} +models.ranged[21249] = { name="Iqonde Crossbow" , model = 32768} +models.ranged[21250] = { name="Iqonde Cross. +1" , model = 32768} +models.ranged[21251] = { name="Em. Crossbow" , model = 32768} +models.ranged[21252] = { name="One-eyed" , model = 32768} +models.ranged[21253] = { name="Atetepeyorg" , model = 32768} +models.ranged[21254] = { name="Cama. Bowgun" , model = 32768} +models.ranged[21255] = { name="Forefront Bowgun" , model = 32768} +models.ranged[21256] = { name="Illapa" , model = 32768} +models.ranged[21257] = { name="Zoquittihuitz" , model = 32768} +models.ranged[21258] = { name="Malayo Crossbow" , model = 32768} +models.ranged[21259] = { name="Malayo Crossbow +1" , model = 32768} +models.ranged[21260] = { name="Annihilator" , model = 32768} +models.ranged[21261] = { name="Annihilator" , model = 32768} +models.ranged[21262] = { name="Death Penalty" , model = 32768} +models.ranged[21263] = { name="Death Penalty" , model = 32768} +models.ranged[21264] = { name="Armageddon" , model = 32768} +models.ranged[21265] = { name="Armageddon" , model = 32768} +models.ranged[21266] = { name="Gastraphetes" , model = 32768} +models.ranged[21267] = { name="Annihilator" , model = 32768} +models.ranged[21268] = { name="Death Penalty" , model = 32768} +models.ranged[21269] = { name="Armageddon" , model = 32768} +models.ranged[21272] = { name="Troll Gun" , model = 32768} +models.ranged[21273] = { name="Nibiru Gun" , model = 32768} +models.ranged[21274] = { name="Donar Gun" , model = 32768} +models.ranged[21275] = { name="Homestead Gun" , model = 32768} +models.ranged[21276] = { name="Pulfanxa" , model = 32768} +models.ranged[21277] = { name="Lionsquall" , model = 32768} +models.ranged[21278] = { name="Deathlocke" , model = 32768} +models.ranged[21279] = { name="Hgafircian +2" , model = 32768} +models.ranged[21280] = { name="Decazoom Mk-XI" , model = 32768} +models.ranged[21281] = { name="Eminent Gun" , model = 32768} +models.ranged[21282] = { name="Qasama Hexagun" , model = 32768} +models.ranged[21283] = { name="Mollfrith -1" , model = 32768} +models.ranged[21284] = { name="Vanir Gun" , model = 32768} +models.ranged[21285] = { name="Cama. Gun" , model = 32768} +models.ranged[21286] = { name="Hgafircian +1" , model = 32768} +models.ranged[21287] = { name="Forefront Gun" , model = 32768} +models.ranged[21288] = { name="Surefire Arquebus" , model = 32768} +models.ranged[21289] = { name="Donderbuss" , model = 32768} +models.ranged[21290] = { name="Donderbuss +1" , model = 32768} +models.ranged[21291] = { name="Shadeshot Gun" , model = 32768} +models.ranged[21292] = { name="Bandeiras Gun" , model = 32768} +models.ranged[21293] = { name="Bandeiras Gun +1" , model = 32768} +models.ranged[21294] = { name="Hgafircian" , model = 32768} +models.ranged[21340] = { name="Halakaala" , model = 32768} +models.ranged[21348] = { name="Narmar Boomerang" , model = 32768} +models.ranged[21349] = { name="Wingcutter" , model = 32768} +models.ranged[21350] = { name="Wingcutter +1" , model = 32768} +models.ranged[21368] = { name="Bestas Bane" , model = 32768} +models.ranged[21372] = { name="Dunna" , model = 32768} +models.ranged[21375] = { name="Magneto" , model = 32768} +models.ranged[21390] = { name="Albin Bane" , model = 32768} +models.ranged[21392] = { name="Animator Z" , model = 32768} +models.ranged[21398] = { name="Marsyas" , model = 32768} +models.ranged[21399] = { name="Nibiru Harp" , model = 32768} +models.ranged[21400] = { name="Blurred Harp" , model = 32768} +models.ranged[21401] = { name="Blurred Harp +1" , model = 32768} +models.ranged[21402] = { name="Damani Horn" , model = 32768} +models.ranged[21403] = { name="Damani Horn +1" , model = 32768} +models.ranged[21404] = { name="Linos" , model = 32768} +models.ranged[21405] = { name="Eminent Flute" , model = 32768} +models.ranged[21406] = { name="Homestead Flute" , model = 32768} +models.ranged[21407] = { name="Terpander" , model = 32768} +models.ranged[21408] = { name="Cama. Harp" , model = 32768} +models.ranged[21409] = { name="Forefront Flute" , model = 32768} +models.ranged[21452] = { name="Divinator" , model = 32768} +models.ranged[21453] = { name="Em. Animator" , model = 32768} +models.ranged[21454] = { name="F. Animator" , model = 32768} +models.ranged[21455] = { name="Alternator" , model = 32768} +models.ranged[21456] = { name="Animator P" , model = 32768} +models.ranged[21457] = { name="Animator P +1" , model = 32768} +models.ranged[21458] = { name="Animator P II" , model = 32768} +models.ranged[21459] = { name="Animator P II +1" , model = 32768} +models.ranged[21460] = { name="Matre Bell" , model = 32768} +models.ranged[21461] = { name="Filiae Bell" , model = 32768} +models.ranged[21462] = { name="Eminent Bell" , model = 32768} +models.ranged[21463] = { name="Nepote Bell" , model = 32768} +models.ranged[21476] = { name="Doomsday" , model = 32768} +models.ranged[21477] = { name="Atalanta" , model = 32768} +models.ranged[21478] = { name="Moros Cross. +1" , model = 32768} +models.ranged[21479] = { name="Tsoa. Crossbow" , model = 32768} +models.ranged[21480] = { name="Blurred Crossbow" , model = 32768} +models.ranged[21481] = { name="Blurred Cross. +1" , model = 32768} +models.ranged[21482] = { name="Compensator" , model = 32768} +models.ranged[21483] = { name="Malison" , model = 32768} +models.ranged[21484] = { name="Malison +1" , model = 32768} +models.ranged[21485] = { name="Fomalhaut" , model = 32768} +models.ranged[22107] = { name="Ullr" , model = 32768} +models.ranged[22108] = { name="Tokko Bow" , model = 32768} +models.ranged[22109] = { name="Ajja Bow" , model = 32768} +models.ranged[22110] = { name="Eletta Bow" , model = 32768} +models.ranged[22111] = { name="Kaja Bow" , model = 32768} +models.ranged[22112] = { name="Mizukage-no-Yumi" , model = 32768} +models.ranged[22113] = { name="Teller" , model = 32768} +models.ranged[22114] = { name="Steinthor" , model = 32768} +models.ranged[22115] = { name="Yoichinoyumi" , model = 32768} +models.ranged[22116] = { name="Gandiva" , model = 32768} +models.ranged[22117] = { name="Fail-Not" , model = 32768} +models.ranged[22118] = { name="Venery Bow" , model = 32768} +models.ranged[22119] = { name="Wochowsen" , model = 32768} +models.ranged[22120] = { name="Imati" , model = 32768} +models.ranged[22121] = { name="Imati +1" , model = 32768} +models.ranged[22122] = { name="Arasy Bow" , model = 32768} +models.ranged[22123] = { name="Arasy Bow +1" , model = 32768} +models.ranged[22124] = { name="Artemis's Bow" , model = 32768} +models.ranged[22125] = { name="Exalted Bow" , model = 32768} +models.ranged[22126] = { name="Exalted Bow +1" , model = 32768} +models.ranged[22127] = { name="Raetic Bow" , model = 32768} +models.ranged[22128] = { name="Raetic Bow +1" , model = 32768} +models.ranged[22129] = { name="Yoichinoyumi" , model = 32768} +models.ranged[22130] = { name="Gandiva" , model = 32768} +models.ranged[22131] = { name="Fail-Not" , model = 32768} +models.ranged[22132] = { name="Artemis's Bow +1" , model = 32768} +models.ranged[22133] = { name="Voluspa Bow" , model = 32768} +models.ranged[22134] = { name="Holliday" , model = 32768} +models.ranged[22135] = { name="Arasy Gun" , model = 32768} +models.ranged[22136] = { name="Arasy Gun +1" , model = 32768} +models.ranged[22137] = { name="Exalted C.bow" , model = 32768} +models.ranged[22138] = { name="Exalted C.bow +1" , model = 32768} +models.ranged[22139] = { name="Gastraphetes" , model = 32768} +models.ranged[22140] = { name="Annihilator" , model = 32768} +models.ranged[22141] = { name="Death Penalty" , model = 32768} +models.ranged[22142] = { name="Armageddon" , model = 32768} +models.ranged[22143] = { name="Fomalhaut" , model = 32768} +models.ranged[22144] = { name="Voluspa Gun" , model = 32768} +models.ranged[22147] = { name="Scout's Crossbow" , model = 32768} +models.ranged[22148] = { name="Arke Crossbow" , model = 32768} +models.ranged[22149] = { name="Sharanga" , model = 32768} +models.ranged[22260] = { name="E. Animator II" , model = 32768} +models.ranged[22261] = { name="Divinator II" , model = 32768} +models.ranged[22266] = { name="Antitail" , model = 32768} +models.ranged[22267] = { name="Antitail +1" , model = 32768} +models.ranged[22283] = { name="Marvelous Cheer" , model = 32768} \ No newline at end of file diff --git a/addons/DressUp/static_variables.lua b/addons/DressUp/static_variables.lua index e05b43341e..0359eeade2 100644 --- a/addons/DressUp/static_variables.lua +++ b/addons/DressUp/static_variables.lua @@ -74,22 +74,22 @@ _races["g"] = 8 -- Maps commonly known face IDs to their actual IDs _faces = {} -_faces["1a"] = 1 -_faces["1b"] = 2 -_faces["2a"] = 3 -_faces["2b"] = 4 -_faces["3a"] = 5 -_faces["3b"] = 6 -_faces["4a"] = 7 -_faces["4b"] = 8 -_faces["5a"] = 9 -_faces["5b"] = 10 -_faces["6a"] = 11 -_faces["6b"] = 12 -_faces["7a"] = 13 -_faces["7b"] = 14 -_faces["8a"] = 15 -_faces["8b"] = 16 +_faces["1a"] = 0 +_faces["1b"] = 1 +_faces["2a"] = 2 +_faces["2b"] = 3 +_faces["3a"] = 4 +_faces["3b"] = 5 +_faces["4a"] = 6 +_faces["4b"] = 7 +_faces["5a"] = 8 +_faces["5b"] = 9 +_faces["6a"] = 10 +_faces["6b"] = 11 +_faces["7a"] = 12 +_faces["7b"] = 13 +_faces["8a"] = 14 +_faces["8b"] = 15 _faces["Fomor"] = 29 _faces["Mannequin"] = 30 diff --git a/addons/DressUp/sub.lua b/addons/DressUp/sub.lua new file mode 100644 index 0000000000..11f3f21427 --- /dev/null +++ b/addons/DressUp/sub.lua @@ -0,0 +1,1729 @@ +-- Copyright © 2013, 2022 Cairthenn +-- 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 DressUp 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 Cairthenn 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. + + +models.sub = {} + +models.sub["None"] = { name = "empty" , enl = "empty", model = 28672 } + +models.sub[16447] = { name = "Rusty Dagger" , model = 28836} +models.sub[16448] = { name = "Bronze Dagger" , model = 28836} +models.sub[16449] = { name = "Brass Dagger" , model = 28837} +models.sub[16450] = { name = "Dagger" , model = 28838} +models.sub[16451] = { name = "Mythril Dagger" , model = 28839} +models.sub[16452] = { name = "Misericorde" , model = 28835} +models.sub[16453] = { name = "Orichalcum Dagger" , model = 28851} +models.sub[16454] = { name = "Blind Dagger" , model = 28836} +models.sub[16455] = { name = "Baselard" , model = 28841} +models.sub[16456] = { name = "Mythril Baselard" , model = 28842} +models.sub[16457] = { name = "Dst. Baselard" , model = 28840} +models.sub[16458] = { name = "Poison Baselard" , model = 28841} +models.sub[16459] = { name = "Acid Baselard" , model = 28842} +models.sub[16460] = { name = "Kris" , model = 28850} +models.sub[16461] = { name = "Adaman Kris" , model = 28849} +models.sub[16463] = { name = "Cmb.Cst. Dagger" , model = 28849} +models.sub[16465] = { name = "Bronze Knife" , model = 28831} +models.sub[16466] = { name = "Knife" , model = 28832} +models.sub[16467] = { name = "Mythril Knife" , model = 28833} +models.sub[16468] = { name = "Darksteel Knife" , model = 28830} +models.sub[16469] = { name = "Cermet Knife" , model = 28834} +models.sub[16470] = { name = "Gully" , model = 28829} +models.sub[16471] = { name = "Blind Knife" , model = 28831} +models.sub[16472] = { name = "Poison Knife" , model = 28832} +models.sub[16473] = { name = "Kukri" , model = 28844} +models.sub[16475] = { name = "Mythril Kukri" , model = 28845} +models.sub[16476] = { name = "Darksteel Kukri" , model = 28843} +models.sub[16477] = { name = "Cermet Kukri" , model = 28846} +models.sub[16478] = { name = "Poison Kukri" , model = 28844} +models.sub[16479] = { name = "Acid Kukri" , model = 28845} +models.sub[16480] = { name = "Thief's Knife" , model = 28848} +models.sub[16481] = { name = "Yataghan +1" , model = 29070} +models.sub[16482] = { name = "Onion Dagger" , model = 28836} +models.sub[16483] = { name = "Onion Knife" , model = 28831} +models.sub[16484] = { name = "Burglar's Dagger" , model = 28838} +models.sub[16485] = { name = "Yataghan" , model = 29070} +models.sub[16486] = { name = "Beestinger" , model = 28839} +models.sub[16487] = { name = "Minstrel's Dagger" , model = 28836} +models.sub[16488] = { name = "Nguul" , model = 28829} +models.sub[16489] = { name = "Poison Kukri +1" , model = 28844} +models.sub[16490] = { name = "Blind Knife +1" , model = 28831} +models.sub[16491] = { name = "Bronze Knife +1" , model = 28831} +models.sub[16492] = { name = "Bronze Dagger +1" , model = 28836} +models.sub[16493] = { name = "Blind Dagger +1" , model = 28836} +models.sub[16494] = { name = "Corrosive Kukri" , model = 28845} +models.sub[16495] = { name = "Silence Dagger" , model = 28837} +models.sub[16496] = { name = "Poison Dagger" , model = 28838} +models.sub[16497] = { name = "Sleep Dagger" , model = 28839} +models.sub[16498] = { name = "Carabineer Dagger" , model = 28851} +models.sub[16499] = { name = "Venom Kris" , model = 28850} +models.sub[16500] = { name = "Aluh Jambiya" , model = 29081} +models.sub[16501] = { name = "Acid Knife" , model = 28833} +models.sub[16502] = { name = "Venom Knife" , model = 28830} +models.sub[16503] = { name = "Stun Knife" , model = 28834} +models.sub[16504] = { name = "Oynos Knife" , model = 28834} +models.sub[16505] = { name = "Venom Kukri" , model = 28843} +models.sub[16506] = { name = "Stun Kukri" , model = 28846} +models.sub[16507] = { name = "Venom Baselard" , model = 28840} +models.sub[16508] = { name = "Silence Dagger +1" , model = 28837} +models.sub[16509] = { name = "Aspir Knife" , model = 28831} +models.sub[16510] = { name = "Vnm. Baselard +1" , model = 28840} +models.sub[16511] = { name = "Burnite Shell" , model = 28852} +models.sub[16512] = { name = "Bilbo" , model = 28855} +models.sub[16513] = { name = "Tuck" , model = 28856} +models.sub[16514] = { name = "Mailbreaker" , model = 28859} +models.sub[16515] = { name = "Colichemarde" , model = 28853} +models.sub[16516] = { name = "Jr.Msk. Tuck" , model = 28856} +models.sub[16517] = { name = "Degen" , model = 28860} +models.sub[16518] = { name = "Mythril Degen" , model = 28861} +models.sub[16519] = { name = "Schlaeger" , model = 28858} +models.sub[16520] = { name = "Verdun" , model = 28857} +models.sub[16521] = { name = "Rapier" , model = 28859} +models.sub[16522] = { name = "Flame Degen" , model = 28860} +models.sub[16523] = { name = "Holy Degen" , model = 28861} +models.sub[16524] = { name = "Fleuret" , model = 28863} +models.sub[16525] = { name = "Hornet Fleuret" , model = 28865} +models.sub[16526] = { name = "Schwert" , model = 28864} +models.sub[16527] = { name = "Epee" , model = 28862} +models.sub[16528] = { name = "Bloody Rapier" , model = 28860} +models.sub[16529] = { name = "Musketeer's Sword" , model = 28860} +models.sub[16530] = { name = "Xiphos" , model = 28936} +models.sub[16531] = { name = "Brass Xiphos" , model = 28937} +models.sub[16532] = { name = "Gladius" , model = 28938} +models.sub[16533] = { name = "Ancient Sword" , model = 28955} +models.sub[16534] = { name = "Onion Sword" , model = 28937} +models.sub[16535] = { name = "Bronze Sword" , model = 28940} +models.sub[16536] = { name = "Iron Sword" , model = 28942} +models.sub[16537] = { name = "Mythril Sword" , model = 28943} +models.sub[16538] = { name = "Darksteel Sword" , model = 28939} +models.sub[16539] = { name = "Cermet Sword" , model = 28945} +models.sub[16540] = { name = "Tyrfing" , model = 29190} +models.sub[16541] = { name = "Jagdplaute" , model = 28941} +models.sub[16542] = { name = "Wing Sword" , model = 28960} +models.sub[16543] = { name = "Fire Sword" , model = 28940} +models.sub[16544] = { name = "Ryl.Arc. Sword" , model = 28923} +models.sub[16545] = { name = "Broadsword" , model = 28948} +models.sub[16546] = { name = "Katzbalger" , model = 28947} +models.sub[16547] = { name = "Anelace" , model = 28946} +models.sub[16548] = { name = "Coral Sword" , model = 28949} +models.sub[16549] = { name = "Divine Sword" , model = 28948} +models.sub[16550] = { name = "Hallowed Sword" , model = 28948} +models.sub[16551] = { name = "Sapara" , model = 28927} +models.sub[16552] = { name = "Scimitar" , model = 28928} +models.sub[16553] = { name = "Tulwar" , model = 28929} +models.sub[16554] = { name = "Hanger" , model = 28930} +models.sub[16555] = { name = "Ridill" , model = 28931} +models.sub[16556] = { name = "Bloody Blade" , model = 28934} +models.sub[16557] = { name = "Msk.Cmd. Falchion" , model = 28934} +models.sub[16558] = { name = "Falchion" , model = 28934} +models.sub[16559] = { name = "Darksteel Falchion" , model = 28932} +models.sub[16560] = { name = "Cutlass" , model = 28935} +models.sub[16562] = { name = "Platinum Cutlass" , model = 28933} +models.sub[16563] = { name = "Rune Blade" , model = 28926} +models.sub[16564] = { name = "Flame Blade" , model = 28934} +models.sub[16565] = { name = "Spatha" , model = 28921} +models.sub[16566] = { name = "Longsword" , model = 28923} +models.sub[16567] = { name = "Knight's Sword" , model = 28924} +models.sub[16568] = { name = "Saber" , model = 28925} +models.sub[16569] = { name = "Gold Sword" , model = 28922} +models.sub[16571] = { name = "T.K. Army Sword" , model = 28923} +models.sub[16572] = { name = "Bee Spatha" , model = 28921} +models.sub[16575] = { name = "Curtana" , model = 28941} +models.sub[16576] = { name = "Hunting Sword" , model = 28952} +models.sub[16577] = { name = "Bastard Sword" , model = 28951} +models.sub[16578] = { name = "Espadon" , model = 28953} +models.sub[16579] = { name = "Kaskara" , model = 28950} +models.sub[16580] = { name = "Bloodsword" , model = 28959} +models.sub[16581] = { name = "Holy Sword" , model = 28958} +models.sub[16582] = { name = "Vetala Sword" , model = 28960} +models.sub[16600] = { name = "Wax Sword" , model = 28940} +models.sub[16604] = { name = "Save the Queen" , model = 28924} +models.sub[16605] = { name = "Enhancing Sword" , model = 28922} +models.sub[16608] = { name = "Gladiator" , model = 28938} +models.sub[16609] = { name = "Bloody Sword" , model = 28939} +models.sub[16610] = { name = "Wax Sword +1" , model = 28940} +models.sub[16611] = { name = "Bee Spatha +1" , model = 28921} +models.sub[16612] = { name = "Saber +1" , model = 28925} +models.sub[16613] = { name = "Spirit Sword" , model = 28958} +models.sub[16614] = { name = "Knife +1" , model = 28832} +models.sub[16615] = { name = "Falchion +1" , model = 28934} +models.sub[16617] = { name = "Tuck +1" , model = 28856} +models.sub[16618] = { name = "Mailbreaker +1" , model = 28859} +models.sub[16619] = { name = "Epee +1" , model = 28862} +models.sub[16620] = { name = "Merman's Sword" , model = 28949} +models.sub[16621] = { name = "Flame Sword" , model = 28940} +models.sub[16623] = { name = "Bronze Sword +1" , model = 28940} +models.sub[16624] = { name = "Xiphos +1" , model = 28936} +models.sub[16625] = { name = "Scimitar +1" , model = 28928} +models.sub[16626] = { name = "Iron Sword +1" , model = 28942} +models.sub[16627] = { name = "Spatha +1" , model = 28921} +models.sub[16628] = { name = "Longsword +1" , model = 28923} +models.sub[16629] = { name = "Small Sword" , model = 28854} +models.sub[16630] = { name = "Striker Sword" , model = 28955} +models.sub[16631] = { name = "Kaiser Sword" , model = 28956} +models.sub[16632] = { name = "Bilbo +1" , model = 28855} +models.sub[16633] = { name = "Degen +1" , model = 28860} +models.sub[16634] = { name = "Broadsword +1" , model = 28948} +models.sub[16635] = { name = "Mythril Sword +1" , model = 28943} +models.sub[16636] = { name = "Tulwar +1" , model = 28929} +models.sub[16640] = { name = "Bronze Axe" , model = 28748} +models.sub[16641] = { name = "Brass Axe" , model = 28749} +models.sub[16642] = { name = "Bone Axe" , model = 28752} +models.sub[16643] = { name = "Battleaxe" , model = 28750} +models.sub[16644] = { name = "Mythril Axe" , model = 28751} +models.sub[16645] = { name = "Darksteel Axe" , model = 28756} +models.sub[16646] = { name = "Bronze Axe +1" , model = 28748} +models.sub[16647] = { name = "Rune Axe" , model = 28757} +models.sub[16648] = { name = "Legionnaire's Axe" , model = 28750} +models.sub[16649] = { name = "Bone Pick" , model = 28762} +models.sub[16650] = { name = "War Pick" , model = 28760} +models.sub[16651] = { name = "Mythril Pick" , model = 28761} +models.sub[16652] = { name = "Darksteel Pick" , model = 28759} +models.sub[16653] = { name = "Nadziak" , model = 28758} +models.sub[16654] = { name = "Glyph Axe" , model = 29191} +models.sub[16655] = { name = "Rusty Pick" , model = 28760} +models.sub[16656] = { name = "Orcish Axe" , model = 28763} +models.sub[16657] = { name = "Tabar" , model = 28755} +models.sub[16658] = { name = "Darksteel Tabar" , model = 28754} +models.sub[16659] = { name = "Tabarzin" , model = 28753} +models.sub[16660] = { name = "Doom Tabar" , model = 28753} +models.sub[16661] = { name = "Brass Axe +1" , model = 28749} +models.sub[16662] = { name = "Doom Tabar +1" , model = 28753} +models.sub[16663] = { name = "Battleaxe +1" , model = 28750} +models.sub[16664] = { name = "War Pick +1" , model = 28760} +models.sub[16665] = { name = "Mythril Axe +1" , model = 28751} +models.sub[16666] = { name = "Bone Axe +1" , model = 28752} +models.sub[16667] = { name = "Light Axe" , model = 28750} +models.sub[16668] = { name = "Bone Pick +1" , model = 28762} +models.sub[16669] = { name = "Cmb.Cst. Axe" , model = 28755} +models.sub[16670] = { name = "Mythril Pick +1" , model = 28761} +models.sub[16671] = { name = "Tabar +1" , model = 28755} +models.sub[16672] = { name = "Tigerhunter" , model = 28752} +models.sub[16673] = { name = "Warrior's Axe" , model = 28750} +models.sub[16674] = { name = "Emeth Pick" , model = 28761} +models.sub[16675] = { name = "Storm Axe" , model = 28751} +models.sub[16676] = { name = "Viking Axe" , model = 28756} +models.sub[16677] = { name = "Darksteel Axe +1" , model = 28756} +models.sub[16678] = { name = "Razor Axe" , model = 28750} +models.sub[16679] = { name = "Wrath Tabar" , model = 28754} +models.sub[16680] = { name = "Barbaroi Axe" , model = 28763} +models.sub[16681] = { name = "Gerwitz's Axe" , model = 28755} +models.sub[16682] = { name = "Darksteel Pick +1" , model = 28759} +models.sub[16683] = { name = "Dst. Tabar +1" , model = 28754} +models.sub[16684] = { name = "Kabrakan's Axe" , model = 28763} +models.sub[16685] = { name = "Nadziak +1" , model = 28758} +models.sub[16686] = { name = "Arcanabane" , model = 28762} +models.sub[16687] = { name = "Platoon Axe" , model = 28749} +models.sub[16736] = { name = "Dagger +1" , model = 28838} +models.sub[16737] = { name = "Baselard +1" , model = 28841} +models.sub[16738] = { name = "Mythril Dagger +1" , model = 28839} +models.sub[16739] = { name = "Mythril Knife +1" , model = 28833} +models.sub[16740] = { name = "Brass Dagger +1" , model = 28837} +models.sub[16741] = { name = "Poison Dagger +1" , model = 28838} +models.sub[16742] = { name = "Poison Knife +1" , model = 28832} +models.sub[16743] = { name = "Python Baselard" , model = 28841} +models.sub[16744] = { name = "Ryl.Sqr. Dagger" , model = 28842} +models.sub[16745] = { name = "Decurion's Dagger" , model = 28839} +models.sub[16746] = { name = "Mercenary's Knife" , model = 28832} +models.sub[16747] = { name = "Mrc.Cpt. Kukri" , model = 28844} +models.sub[16748] = { name = "Kukri +1" , model = 28844} +models.sub[16749] = { name = "Kris +1" , model = 28850} +models.sub[16750] = { name = "Mythril Kukri +1" , model = 28845} +models.sub[16751] = { name = "Dst. Knife +1" , model = 28830} +models.sub[16752] = { name = "Fine Baselard" , model = 28839} +models.sub[16753] = { name = "Ceremonial Dagger" , model = 28836} +models.sub[16754] = { name = "Parrying Knife" , model = 28848} +models.sub[16755] = { name = "Archer's Knife" , model = 28833} +models.sub[16756] = { name = "Leste Jambiya" , model = 29051} +models.sub[16757] = { name = "Corsair's Knife" , model = 28843} +models.sub[16758] = { name = "Dst. Baselard +1" , model = 28840} +models.sub[16759] = { name = "Darksteel Kris" , model = 28850} +models.sub[16760] = { name = "Darksteel Kris +1" , model = 28850} +models.sub[16761] = { name = "Venom Kris +1" , model = 28850} +models.sub[16762] = { name = "Venom Knife +1" , model = 28830} +models.sub[16763] = { name = "Darksteel Kukri +1" , model = 28843} +models.sub[16764] = { name = "Marauder's Knife" , model = 28832} +models.sub[16765] = { name = "Lust Dagger" , model = 28837} +models.sub[16766] = { name = "Paper Knife" , model = 28831} +models.sub[16767] = { name = "Triple Dagger" , model = 28851} +models.sub[16800] = { name = "Knight's Sword +1" , model = 28924} +models.sub[16801] = { name = "Sapara +1" , model = 28927} +models.sub[16802] = { name = "Brass Xiphos +1" , model = 28937} +models.sub[16803] = { name = "Fleuret +1" , model = 28863} +models.sub[16804] = { name = "Flame Blade +1" , model = 28934} +models.sub[16805] = { name = "Ryl.Grd. Fleuret" , model = 28865} +models.sub[16806] = { name = "Centurion's Sword" , model = 28943} +models.sub[16807] = { name = "Cmb.Cst. Scimitar" , model = 28929} +models.sub[16808] = { name = "Wis.Wiz. Bilbo" , model = 28854} +models.sub[16809] = { name = "Wis.Wiz. Anelace" , model = 28946} +models.sub[16810] = { name = "Tct.Mag. Espadon" , model = 28952} +models.sub[16811] = { name = "Dst. Sword +1" , model = 28939} +models.sub[16812] = { name = "War Sword" , model = 28952} +models.sub[16813] = { name = "Schlaeger +1" , model = 28858} +models.sub[16814] = { name = "Crescent Sword" , model = 28932} +models.sub[16815] = { name = "Mythril Degen +1" , model = 28861} +models.sub[16816] = { name = "Holy Sword +1" , model = 28958} +models.sub[16817] = { name = "Holy Degen +1" , model = 28861} +models.sub[16818] = { name = "San d'Orian Sword" , model = 28923} +models.sub[16819] = { name = "Mithran Scimitar" , model = 28928} +models.sub[16820] = { name = "Strider Sword" , model = 28942} +models.sub[16821] = { name = "Duel Rapier" , model = 28859} +models.sub[16822] = { name = "Crimson Blade" , model = 28940} +models.sub[16823] = { name = "Flame Degen +1" , model = 28860} +models.sub[16824] = { name = "Carnage Rapier" , model = 28860} +models.sub[16825] = { name = "Cermet Sword +1" , model = 28945} +models.sub[16826] = { name = "Divine Sword +1" , model = 28948} +models.sub[16827] = { name = "Carnage Blade" , model = 28934} +models.sub[16828] = { name = "Bastard Sword +1" , model = 28951} +models.sub[16829] = { name = "Fencing Degen" , model = 28860} +models.sub[16830] = { name = "Gluttony Sword" , model = 28959} +models.sub[16831] = { name = "Greed Scimitar" , model = 28954} +models.sub[16896] = { name = "Kunai" , model = 28987} +models.sub[16897] = { name = "Kageboshi" , model = 28986} +models.sub[16898] = { name = "Cmb.Cst. Kusabi" , model = 28986} +models.sub[16899] = { name = "Hototogisu" , model = 28987} +models.sub[16900] = { name = "Wakizashi" , model = 28982} +models.sub[16901] = { name = "Kodachi" , model = 28983} +models.sub[16902] = { name = "Sakurafubuki" , model = 28984} +models.sub[16903] = { name = "Kabutowari" , model = 28985} +models.sub[16904] = { name = "Fudo" , model = 28981} +models.sub[16905] = { name = "Bokuto" , model = 28982} +models.sub[16906] = { name = "Mokuto" , model = 28982} +models.sub[16907] = { name = "Busuto" , model = 28982} +models.sub[16908] = { name = "Yoto" , model = 28982} +models.sub[16909] = { name = "Kororito" , model = 28982} +models.sub[16910] = { name = "Mamushito" , model = 28982} +models.sub[16911] = { name = "Amanojaku" , model = 28982} +models.sub[16912] = { name = "Kitsutsuki" , model = 28987} +models.sub[16913] = { name = "Shinogi" , model = 28983} +models.sub[16914] = { name = "Kunai +1" , model = 28987} +models.sub[16915] = { name = "Hien" , model = 28987} +models.sub[16916] = { name = "Hien +1" , model = 28987} +models.sub[16917] = { name = "Suzume" , model = 28987} +models.sub[16918] = { name = "Wakizashi +1" , model = 28982} +models.sub[16919] = { name = "Shinobi-Gatana" , model = 28982} +models.sub[16920] = { name = "Shinobi-Gatana +1" , model = 28982} +models.sub[16921] = { name = "Kodachi +1" , model = 28983} +models.sub[16922] = { name = "Sakurafubuki +1" , model = 28984} +models.sub[16923] = { name = "Kabutowari +1" , model = 28985} +models.sub[16924] = { name = "Hocho" , model = 28984} +models.sub[16925] = { name = "Mokuto +1" , model = 28982} +models.sub[16926] = { name = "Bokuto +1" , model = 28982} +models.sub[16927] = { name = "Busuto +1" , model = 28982} +models.sub[17024] = { name = "Ash Club" , model = 28780} +models.sub[17025] = { name = "Chestnut Club" , model = 28781} +models.sub[17026] = { name = "Bone Cudgel" , model = 28773} +models.sub[17027] = { name = "Oak Cudgel" , model = 28772} +models.sub[17028] = { name = "Freesword's Club" , model = 28780} +models.sub[17029] = { name = "Bouncer Club" , model = 28781} +models.sub[17030] = { name = "Great Club" , model = 28783} +models.sub[17031] = { name = "Shell Scepter" , model = 29264} +models.sub[17032] = { name = "Gobbie Gavel" , model = 29265} +models.sub[17033] = { name = "Bone Cudgel +1" , model = 28773} +models.sub[17034] = { name = "Bronze Mace" , model = 28776} +models.sub[17035] = { name = "Mace" , model = 28778} +models.sub[17036] = { name = "Mythril Mace" , model = 28779} +models.sub[17037] = { name = "Darksteel Mace" , model = 28775} +models.sub[17038] = { name = "Buzdygan" , model = 28774} +models.sub[17039] = { name = "Platinum Mace" , model = 28777} +models.sub[17040] = { name = "Warp Cudgel" , model = 28772} +models.sub[17041] = { name = "Holy Mace" , model = 28779} +models.sub[17042] = { name = "Bronze Hammer" , model = 28785} +models.sub[17043] = { name = "Brass Hammer" , model = 28786} +models.sub[17044] = { name = "Warhammer" , model = 28787} +models.sub[17045] = { name = "Maul" , model = 28788} +models.sub[17046] = { name = "Darksteel Maul" , model = 28784} +models.sub[17047] = { name = "Magnus Hammer" , model = 28788} +models.sub[17048] = { name = "Decurion's Hammer" , model = 28787} +models.sub[17049] = { name = "Maple Wand" , model = 28899} +models.sub[17050] = { name = "Willow Wand" , model = 28904} +models.sub[17051] = { name = "Yew Wand" , model = 28898} +models.sub[17052] = { name = "Chestnut Wand" , model = 28903} +models.sub[17053] = { name = "Rose Wand" , model = 28902} +models.sub[17054] = { name = "Ebony Wand" , model = 28897} +models.sub[17056] = { name = "Mythic Wand" , model = 28900} +models.sub[17057] = { name = "Tefnut Wand" , model = 29204} +models.sub[17058] = { name = "Caduceus" , model = 28905} +models.sub[17059] = { name = "Bronze Rod" , model = 28892} +models.sub[17060] = { name = "Rod" , model = 28894} +models.sub[17061] = { name = "Mythril Rod" , model = 28895} +models.sub[17062] = { name = "Bone Rod" , model = 28896} +models.sub[17063] = { name = "Darksteel Rod" , model = 28891} +models.sub[17064] = { name = "Scepter" , model = 28890} +models.sub[17065] = { name = "Platinum Rod" , model = 28893} +models.sub[17066] = { name = "Molva Maul" , model = 28786} +models.sub[17067] = { name = "Ryl. Guard's Rod" , model = 28893} +models.sub[17068] = { name = "Onion Rod" , model = 28892} +models.sub[17069] = { name = "Moepapa Mace" , model = 28779} +models.sub[17070] = { name = "Living Rod" , model = 28893} +models.sub[17071] = { name = "Heat Rod" , model = 28892} +models.sub[17072] = { name = "Lilith's Rod" , model = 28892} +models.sub[17073] = { name = "Mistilteinn" , model = 28901} +models.sub[17074] = { name = "Chocobo Wand" , model = 28908} +models.sub[17075] = { name = "Star Rod" , model = 28912} +models.sub[17076] = { name = "Earth Wand" , model = 28916} +models.sub[17077] = { name = "Beneficus" , model = 28890} +models.sub[17078] = { name = "Siriti" , model = 28905} +models.sub[17079] = { name = "Winged Wand" , model = 28900} +models.sub[17080] = { name = "Holy Maul" , model = 28788} +models.sub[17081] = { name = "Brass Rod" , model = 28893} +models.sub[17082] = { name = "Tct.Mag. Wand" , model = 28903} +models.sub[17083] = { name = "Time Hammer" , model = 28787} +models.sub[17085] = { name = "Holy Wand" , model = 28900} +models.sub[17086] = { name = "Bronze Mace +1" , model = 28776} +models.sub[17087] = { name = "Maple Wand +1" , model = 28899} +models.sub[17111] = { name = "Bronze Rod +1" , model = 28892} +models.sub[17113] = { name = "Owleyes" , model = 29196} +models.sub[17114] = { name = "Holy Maul +1" , model = 28788} +models.sub[17115] = { name = "Warhammer +1" , model = 28787} +models.sub[17121] = { name = "Maul +1" , model = 28788} +models.sub[17136] = { name = "Sloth Wand" , model = 28902} +models.sub[17137] = { name = "Ash Club +1" , model = 28780} +models.sub[17138] = { name = "Willow Wand +1" , model = 28904} +models.sub[17139] = { name = "Solid Club" , model = 28781} +models.sub[17140] = { name = "Yew Wand +1" , model = 28898} +models.sub[17141] = { name = "Solid Wand" , model = 28903} +models.sub[17142] = { name = "Oak Cudgel +1" , model = 28772} +models.sub[17143] = { name = "Rose Wand +1" , model = 28902} +models.sub[17144] = { name = "Bronze Hammer +1" , model = 28785} +models.sub[17145] = { name = "Mace +1" , model = 28778} +models.sub[17146] = { name = "Rod +1" , model = 28894} +models.sub[17147] = { name = "Mythril Mace +1" , model = 28779} +models.sub[17148] = { name = "Brass Rod +1" , model = 28893} +models.sub[17149] = { name = "Brass Hammer +1" , model = 28786} +models.sub[17150] = { name = "Ryl.Sqr. Mace" , model = 28778} +models.sub[17151] = { name = "Msk.Cmd. Rod" , model = 28891} +models.sub[17408] = { name = "Great Club +1" , model = 28783} +models.sub[17409] = { name = "Mythril Rod +1" , model = 28895} +models.sub[17410] = { name = "Bone Rod +1" , model = 28896} +models.sub[17411] = { name = "Holy Mace +1" , model = 28779} +models.sub[17412] = { name = "Wild Cudgel" , model = 28773} +models.sub[17413] = { name = "Hermit's Wand" , model = 28904} +models.sub[17414] = { name = "Pixie Mace" , model = 28779} +models.sub[17415] = { name = "Shellbuster" , model = 28782} +models.sub[17416] = { name = "Arcana Breaker" , model = 28785} +models.sub[17417] = { name = "Rabbit Stick" , model = 28900} +models.sub[17418] = { name = "Moonlight Wand" , model = 28900} +models.sub[17419] = { name = "Artemis's Wand" , model = 28900} +models.sub[17420] = { name = "Selene's Wand" , model = 28900} +models.sub[17421] = { name = "Moonwatch Wand" , model = 28900} +models.sub[17422] = { name = "Blessed Hammer" , model = 28787} +models.sub[17423] = { name = "Casting Wand" , model = 28898} +models.sub[17426] = { name = "Replica Maul" , model = 28788} +models.sub[17427] = { name = "Ebony Wand +1" , model = 28897} +models.sub[17428] = { name = "Darksteel Mace +1" , model = 28775} +models.sub[17429] = { name = "Dominion Mace" , model = 28777} +models.sub[17430] = { name = "Fey Wand" , model = 28920} +models.sub[17431] = { name = "Platinum Mace +1" , model = 28777} +models.sub[17432] = { name = "Darksteel Maul +1" , model = 28784} +models.sub[17433] = { name = "Mythic Wand +1" , model = 28900} +models.sub[17434] = { name = "Holy Wand +1" , model = 28900} +models.sub[17435] = { name = "Darksteel Rod +1" , model = 28891} +models.sub[17436] = { name = "Platinum Rod +1" , model = 28893} +models.sub[17437] = { name = "Curse Wand" , model = 28914} +models.sub[17438] = { name = "Titan's Cudgel" , model = 28772} +models.sub[17439] = { name = "Leviathan's Rod" , model = 28893} +models.sub[17440] = { name = "Kraken Club" , model = 28782} +models.sub[17441] = { name = "Eremite's Wand" , model = 28904} +models.sub[17442] = { name = "Eremite's Wand +1" , model = 28904} +models.sub[17443] = { name = "Thoth's Wand" , model = 28900} +models.sub[17444] = { name = "Windurstian Club" , model = 28780} +models.sub[17445] = { name = "Federation Club" , model = 28780} +models.sub[17446] = { name = "T.M. Wand +1" , model = 28903} +models.sub[17447] = { name = "T.M. Wand +2" , model = 28903} +models.sub[17448] = { name = "San d'Orian Mace" , model = 28778} +models.sub[17449] = { name = "Kingdom Mace" , model = 28778} +models.sub[17450] = { name = "Healing Mace" , model = 28776} +models.sub[17451] = { name = "Morgenstern" , model = 29032} +models.sub[17452] = { name = "Bastokan Hammer" , model = 28787} +models.sub[17453] = { name = "Republic Hammer" , model = 28787} +models.sub[17454] = { name = "Asklepios" , model = 28913} +models.sub[17455] = { name = "Skirnir's Wand" , model = 28915} +models.sub[17456] = { name = "Club of Trials" , model = 28780} +models.sub[17457] = { name = "Snr.Msk. Rod" , model = 28890} +models.sub[17458] = { name = "Rsv.Cpt. Mace" , model = 28777} +models.sub[17459] = { name = "Scepter +1" , model = 28890} +models.sub[17460] = { name = "Buzdygan +1" , model = 28774} +models.sub[17461] = { name = "Rune Rod" , model = 29008} +models.sub[17462] = { name = "Platoon Mace" , model = 28776} +models.sub[17463] = { name = "Sealed Mace" , model = 28778} +models.sub[17464] = { name = "Purgatory Mace" , model = 28775} +models.sub[17465] = { name = "Mighty Cudgel" , model = 28772} +models.sub[17466] = { name = "Dia Wand" , model = 28899} +models.sub[17467] = { name = "Martial Wand" , model = 28914} +models.sub[17468] = { name = "Raise Rod" , model = 28895} +models.sub[17469] = { name = "Raise II Rod" , model = 28895} +models.sub[17470] = { name = "Pealing Buzdygan" , model = 28774} +models.sub[17471] = { name = "Horrent Mace" , model = 28775} +models.sub[17600] = { name = "Stun Knife +1" , model = 28834} +models.sub[17601] = { name = "Demon's Knife" , model = 28852} +models.sub[17602] = { name = "Demon's Knife +1" , model = 28852} +models.sub[17603] = { name = "Cermet Kukri +1" , model = 28846} +models.sub[17604] = { name = "Venom Kukri +1" , model = 28843} +models.sub[17605] = { name = "Acid Dagger" , model = 28839} +models.sub[17606] = { name = "Corrosive Dagger" , model = 28839} +models.sub[17607] = { name = "Corrosive Baselard" , model = 28842} +models.sub[17608] = { name = "Corrosive Knife" , model = 28833} +models.sub[17609] = { name = "Cermet Knife +1" , model = 28834} +models.sub[17610] = { name = "Bone Knife" , model = 28852} +models.sub[17611] = { name = "Bone Knife +1" , model = 28852} +models.sub[17612] = { name = "Beetle Knife" , model = 28852} +models.sub[17613] = { name = "Beetle Knife +1" , model = 28852} +models.sub[17614] = { name = "Stun Kukri +1" , model = 28846} +models.sub[17615] = { name = "Chicken Knife" , model = 28831} +models.sub[17616] = { name = "Dagger of Trials" , model = 28836} +models.sub[17617] = { name = "Mst.Cst. Knife" , model = 28852} +models.sub[17618] = { name = "Kidney Dagger" , model = 28841} +models.sub[17619] = { name = "Daylight Dagger" , model = 28842} +models.sub[17620] = { name = "Misericorde +1" , model = 28835} +models.sub[17621] = { name = "Gully +1" , model = 28829} +models.sub[17622] = { name = "Buccaneer's Knife" , model = 28845} +models.sub[17623] = { name = "Btm. Knife" , model = 28845} +models.sub[17624] = { name = "Anubis's Knife" , model = 28829} +models.sub[17625] = { name = "Ponderous Gully" , model = 28829} +models.sub[17626] = { name = "Auric Dagger" , model = 29189} +models.sub[17627] = { name = "Garuda's Dagger" , model = 28838} +models.sub[17628] = { name = "Behemoth Knife" , model = 28852} +models.sub[17629] = { name = "Behem. Knife +1" , model = 28852} +models.sub[17630] = { name = "Hawker's Knife" , model = 28833} +models.sub[17631] = { name = "Hawker's Knife +1" , model = 28833} +models.sub[17632] = { name = "Colichemarde +1" , model = 28853} +models.sub[17633] = { name = "Rapier +1" , model = 28859} +models.sub[17634] = { name = "Wasp Fleuret" , model = 28865} +models.sub[17635] = { name = "Schwert +1" , model = 28864} +models.sub[17636] = { name = "Jagdplaute +1" , model = 28941} +models.sub[17637] = { name = "Wing Sword +1" , model = 28960} +models.sub[17638] = { name = "Katzbalger +1" , model = 28947} +models.sub[17639] = { name = "Cutlass +1" , model = 28935} +models.sub[17640] = { name = "Ptm. Cutlass +1" , model = 28933} +models.sub[17641] = { name = "Gold Sword +1" , model = 28922} +models.sub[17642] = { name = "Hanger +1" , model = 28930} +models.sub[17643] = { name = "Honor Sword" , model = 28924} +models.sub[17644] = { name = "Judge's Sword" , model = 29062} +models.sub[17645] = { name = "Espadon +1" , model = 28953} +models.sub[17646] = { name = "Carnage Sword" , model = 28939} +models.sub[17647] = { name = "Aramis's Rapier" , model = 28859} +models.sub[17648] = { name = "Dragvandil" , model = 28952} +models.sub[17649] = { name = "Nightmare Sword" , model = 28939} +models.sub[17650] = { name = "Nadrs" , model = 28954} +models.sub[17651] = { name = "Dainslaif" , model = 28944} +models.sub[17652] = { name = "Joyeuse" , model = 28857} +models.sub[17653] = { name = "Hrotti" , model = 28950} +models.sub[17654] = { name = "Sapara of Trials" , model = 28927} +models.sub[17655] = { name = "Snr.Msk. Scimitar" , model = 28933} +models.sub[17656] = { name = "Verdun +1" , model = 28857} +models.sub[17657] = { name = "Anelace +1" , model = 28946} +models.sub[17658] = { name = "Tutelary" , model = 28856} +models.sub[17659] = { name = "Seiryu's Sword" , model = 28931} +models.sub[17660] = { name = "Kilij" , model = 29047} +models.sub[17661] = { name = "Storm Scimitar" , model = 28954} +models.sub[17662] = { name = "Company Sword" , model = 28953} +models.sub[17663] = { name = "Kilij +1" , model = 29047} +models.sub[17664] = { name = "Firmament" , model = 28949} +models.sub[17665] = { name = "Ifrit's Blade" , model = 28927} +models.sub[17666] = { name = "Jr.Msk. Tuck +1" , model = 28856} +models.sub[17667] = { name = "Jr.Msk. Tuck +2" , model = 28856} +models.sub[17668] = { name = "Firmament +1" , model = 28949} +models.sub[17669] = { name = "Sagasinger" , model = 29200} +models.sub[17670] = { name = "T.K. Sword +1" , model = 28923} +models.sub[17671] = { name = "T.K. Sword +2" , model = 28923} +models.sub[17672] = { name = "Bastokan Sword" , model = 28943} +models.sub[17673] = { name = "Republic Sword" , model = 28943} +models.sub[17674] = { name = "Cmb.Cst.Scmtr. +1" , model = 28929} +models.sub[17675] = { name = "Cmb.Cst.Scmtr. +2" , model = 28929} +models.sub[17676] = { name = "T.M. Espadon +1" , model = 28952} +models.sub[17677] = { name = "T.M. Espadon +2" , model = 28952} +models.sub[17678] = { name = "San d'Orian Sword" , model = 28937} +models.sub[17679] = { name = "Kingdom Sword" , model = 28937} +models.sub[17680] = { name = "Msk. Sword +1" , model = 28860} +models.sub[17681] = { name = "Msk. Sword +2" , model = 28860} +models.sub[17682] = { name = "Sacred Sword" , model = 28958} +models.sub[17683] = { name = "Sacred Degen" , model = 28861} +models.sub[17684] = { name = "Griffinclaw" , model = 28922} +models.sub[17685] = { name = "Lex Talionis" , model = 28856} +models.sub[17686] = { name = "Spark Bilbo" , model = 28856} +models.sub[17687] = { name = "Spark Bilbo +1" , model = 28856} +models.sub[17688] = { name = "Spark Degen" , model = 28861} +models.sub[17689] = { name = "Spark Degen +1" , model = 28861} +models.sub[17690] = { name = "Spark Rapier" , model = 28859} +models.sub[17691] = { name = "Spark Rapier +1" , model = 28859} +models.sub[17692] = { name = "Platoon Spatha" , model = 28921} +models.sub[17693] = { name = "Grudge Sword" , model = 28924} +models.sub[17694] = { name = "Guespiere" , model = 28858} +models.sub[17695] = { name = "Bayard's Sword" , model = 28945} +models.sub[17696] = { name = "Buzzard Tuck" , model = 28856} +models.sub[17697] = { name = "Mighty Talwar" , model = 28929} +models.sub[17698] = { name = "Princely Sword" , model = 28950} +models.sub[17699] = { name = "Dissector" , model = 28957} +models.sub[17700] = { name = "Durandal" , model = 28949} +models.sub[17701] = { name = "Shotel" , model = 29030} +models.sub[17702] = { name = "Shotel +1" , model = 29030} +models.sub[17703] = { name = "Pealing Anelace" , model = 28946} +models.sub[17704] = { name = "Vulcan Sword" , model = 28940} +models.sub[17705] = { name = "Vulcan Degen" , model = 28860} +models.sub[17706] = { name = "Vulcan Blade" , model = 28935} +models.sub[17707] = { name = "Martial Anelace" , model = 28946} +models.sub[17708] = { name = "Auriga Xiphos" , model = 28936} +models.sub[17709] = { name = "Swan Bilbo" , model = 28853} +models.sub[17710] = { name = "Justice Sword" , model = 28926} +models.sub[17711] = { name = "Shiva's Shotel" , model = 29030} +models.sub[17712] = { name = "Kaskara +1" , model = 28950} +models.sub[17713] = { name = "Macuahuitl" , model = 29053} +models.sub[17714] = { name = "Macuahuitl +1" , model = 29053} +models.sub[17715] = { name = "Storm Tulwar" , model = 28929} +models.sub[17716] = { name = "Macuahuitl -1" , model = 29053} +models.sub[17717] = { name = "Immortal's Scimitar" , model = 28954} +models.sub[17718] = { name = "Leech Scimitar" , model = 28928} +models.sub[17719] = { name = "Mensur Epee" , model = 28865} +models.sub[17720] = { name = "Company Fleuret" , model = 28863} +models.sub[17721] = { name = "Sanguine Sword" , model = 29062} +models.sub[17722] = { name = "Phantom Fleuret" , model = 28863} +models.sub[17723] = { name = "Singh Kilij" , model = 29047} +models.sub[17724] = { name = "Darksteel Kilij" , model = 29054} +models.sub[17725] = { name = "Darksteel Kilij +1" , model = 29054} +models.sub[17726] = { name = "Immortal's Shotel" , model = 29030} +models.sub[17727] = { name = "Adaman Kilij" , model = 29056} +models.sub[17728] = { name = "Adaman Kilij +1" , model = 29056} +models.sub[17729] = { name = "Vermin Slayer" , model = 29054} +models.sub[17730] = { name = "Insect Slayer" , model = 29054} +models.sub[17731] = { name = "Aquan Slayer" , model = 29054} +models.sub[17732] = { name = "Marine Slayer" , model = 29054} +models.sub[17733] = { name = "Dragon Slayer" , model = 29056} +models.sub[17734] = { name = "Wyrm Slayer" , model = 29056} +models.sub[17735] = { name = "Demon Slayer" , model = 29056} +models.sub[17736] = { name = "Devil Slayer" , model = 29056} +models.sub[17737] = { name = "Corsair's Scimitar" , model = 28928} +models.sub[17738] = { name = "Hauteclaire" , model = 29071} +models.sub[17739] = { name = "Steel Kilij" , model = 29074} +models.sub[17740] = { name = "Steel Kilij +1" , model = 29074} +models.sub[17741] = { name = "Perdu Hanger" , model = 28930} +models.sub[17742] = { name = "Vorpal Sword" , model = 28863} +models.sub[17743] = { name = "Wightslayer" , model = 29047} +models.sub[17744] = { name = "Brave Blade" , model = 28953} +models.sub[17745] = { name = "Hofud" , model = 29076} +models.sub[17746] = { name = "Cermet Kilij" , model = 29074} +models.sub[17747] = { name = "Cermet Kilij +1" , model = 29074} +models.sub[17748] = { name = "Ibushi Shinai" , model = 29084} +models.sub[17749] = { name = "Ibushi Shinai +1" , model = 29084} +models.sub[17750] = { name = "Anthos Xiphos" , model = 28936} +models.sub[17751] = { name = "Fragarach" , model = 29103} +models.sub[17753] = { name = "Organics" , model = 29117} +models.sub[17754] = { name = "Sylphid Epee" , model = 28862} +models.sub[17755] = { name = "Beast Slayer" , model = 29074} +models.sub[17756] = { name = "Sinfender" , model = 28928} +models.sub[17757] = { name = "Merveilleuse" , model = 28922} +models.sub[17758] = { name = "Ruler" , model = 28925} +models.sub[17759] = { name = "Koggelmander" , model = 28938} +models.sub[17760] = { name = "Buc. Scimitar" , model = 28930} +models.sub[17761] = { name = "Oberon's Rapier" , model = 28859} +models.sub[17762] = { name = "Erlking's Sword" , model = 28947} +models.sub[17763] = { name = "Erlking's Blade" , model = 28932} +models.sub[17764] = { name = "Trainee Sword" , model = 28925} +models.sub[17765] = { name = "Concordia" , model = 29132} +models.sub[17766] = { name = "Lyft Scimitar" , model = 28927} +models.sub[17767] = { name = "Chipped Scimitar" , model = 28928} +models.sub[17768] = { name = "Yoto +1" , model = 28982} +models.sub[17769] = { name = "Kororito +1" , model = 28982} +models.sub[17770] = { name = "Mamushito +1" , model = 28982} +models.sub[17771] = { name = "Anju" , model = 28987} +models.sub[17772] = { name = "Zushio" , model = 28983} +models.sub[17773] = { name = "Kodachi of Trials" , model = 28983} +models.sub[17774] = { name = "Shiranui" , model = 28985} +models.sub[17775] = { name = "Fukuro" , model = 28986} +models.sub[17776] = { name = "Hibari" , model = 28987} +models.sub[17777] = { name = "Hibari +1" , model = 28987} +models.sub[17778] = { name = "Muketsu" , model = 28984} +models.sub[17779] = { name = "Muketsu +1" , model = 28984} +models.sub[17780] = { name = "Kyofu" , model = 28982} +models.sub[17781] = { name = "Kyofu +1" , model = 28982} +models.sub[17782] = { name = "Reppu" , model = 28983} +models.sub[17783] = { name = "Reppu +1" , model = 28983} +models.sub[17784] = { name = "Keppu" , model = 28984} +models.sub[17785] = { name = "Keppu +1" , model = 28984} +models.sub[17786] = { name = "Ganko" , model = 28986} +models.sub[17787] = { name = "Ohaguro" , model = 28986} +models.sub[17788] = { name = "Sairen" , model = 28984} +models.sub[17789] = { name = "Unsho" , model = 28984} +models.sub[17790] = { name = "Unji" , model = 28984} +models.sub[17791] = { name = "Rai Kunimitsu" , model = 28983} +models.sub[17792] = { name = "Nikkariaoe" , model = 28984} +models.sub[17793] = { name = "Senjuinrikio" , model = 28985} +models.sub[17794] = { name = "Niokiyotsuna" , model = 28983} +models.sub[17795] = { name = "Sai" , model = 29039} +models.sub[17796] = { name = "Sai +1" , model = 29039} +models.sub[17797] = { name = "Seito" , model = 28982} +models.sub[17798] = { name = "Shamo" , model = 28985} +models.sub[17799] = { name = "Imanotsurugi" , model = 29043} +models.sub[17924] = { name = "Tungi" , model = 28763} +models.sub[17925] = { name = "Fransisca" , model = 28763} +models.sub[17926] = { name = "Acha d'Armas" , model = 28753} +models.sub[17927] = { name = "Lohar" , model = 28758} +models.sub[17928] = { name = "Juggernaut" , model = 28763} +models.sub[17929] = { name = "Bastokan Axe" , model = 28750} +models.sub[17930] = { name = "Republic Axe" , model = 28750} +models.sub[17931] = { name = "Cmb.Cst. Axe +1" , model = 28755} +models.sub[17932] = { name = "Cmb.Cst. Axe +2" , model = 28755} +models.sub[17933] = { name = "Pick of Trials" , model = 28762} +models.sub[17934] = { name = "Rsv.Cpt. Pick" , model = 28758} +models.sub[17935] = { name = "Tabarzin +1" , model = 28753} +models.sub[17936] = { name = "De Saintre's Axe" , model = 28748} +models.sub[17937] = { name = "Leopard Axe" , model = 28749} +models.sub[17938] = { name = "Woodville's Axe" , model = 28755} +models.sub[17939] = { name = "Kriegsbeil" , model = 28763} +models.sub[17940] = { name = "Military Pick" , model = 28760} +models.sub[17941] = { name = "Mighty Pick" , model = 28759} +models.sub[17942] = { name = "Tomahawk" , model = 29025} +models.sub[17943] = { name = "Tomahawk +1" , model = 29025} +models.sub[17944] = { name = "Retributor" , model = 29025} +models.sub[17945] = { name = "Martial Axe" , model = 28748} +models.sub[17946] = { name = "Maneater" , model = 28754} +models.sub[17947] = { name = "Garde Pick" , model = 28761} +models.sub[17948] = { name = "Temperance Axe" , model = 28757} +models.sub[17949] = { name = "Furnace Tabarzin" , model = 28753} +models.sub[17950] = { name = "Marid Ancus" , model = 28758} +models.sub[17951] = { name = "Storm Tabar" , model = 28754} +models.sub[17952] = { name = "Sirius Axe" , model = 29059} +models.sub[17953] = { name = "Zoraal Ja's Axe" , model = 29025} +models.sub[17954] = { name = "Jolt Axe" , model = 28748} +models.sub[17955] = { name = "Plain Pick" , model = 28760} +models.sub[17956] = { name = "Double Axe" , model = 28756} +models.sub[17957] = { name = "Navy Axe" , model = 28751} +models.sub[17958] = { name = "Iron Ram Pick" , model = 28760} +models.sub[17959] = { name = "Viperine Pick" , model = 28760} +models.sub[17960] = { name = "Labrys" , model = 29105} +models.sub[17961] = { name = "Lion Tamer" , model = 28760} +models.sub[17962] = { name = "Fleetwing" , model = 28756} +models.sub[17963] = { name = "Rainmaker" , model = 29025} +models.sub[17964] = { name = "Barkborer" , model = 28762} +models.sub[17965] = { name = "Sirocco Axe" , model = 28751} +models.sub[17966] = { name = "Erlking's Tabar" , model = 28754} +models.sub[17967] = { name = "Felling Axe" , model = 28749} +models.sub[17968] = { name = "Veldt Axe" , model = 28749} +models.sub[17969] = { name = "Fendoir" , model = 28748} +models.sub[17970] = { name = "Lyft Tabar" , model = 28753} +models.sub[17971] = { name = "Tartaglia" , model = 28751} +models.sub[17972] = { name = "San. Dagger" , model = 28839} +models.sub[17973] = { name = "Kingdom Dagger" , model = 28839} +models.sub[17974] = { name = "Bastokan Dagger" , model = 28839} +models.sub[17975] = { name = "Republic Dagger" , model = 28839} +models.sub[17976] = { name = "Windurstian Knife" , model = 28832} +models.sub[17977] = { name = "Federation Knife" , model = 28832} +models.sub[17978] = { name = "Windurstian Kukri" , model = 28844} +models.sub[17979] = { name = "Federation Kukri" , model = 28844} +models.sub[17980] = { name = "Hornetneedle" , model = 28835} +models.sub[17981] = { name = "Bano del Sol" , model = 28849} +models.sub[17982] = { name = "Kard" , model = 28989} +models.sub[17983] = { name = "Valiant Knife" , model = 28829} +models.sub[17984] = { name = "Spark Dagger" , model = 28838} +models.sub[17985] = { name = "Spark Dagger +1" , model = 28838} +models.sub[17986] = { name = "Spark Baselard" , model = 28842} +models.sub[17987] = { name = "Spark Baselard +1" , model = 28842} +models.sub[17988] = { name = "Spark Kris" , model = 28850} +models.sub[17989] = { name = "Spark Kris +1" , model = 28850} +models.sub[17990] = { name = "Cmb.Cst.Dagger +1" , model = 28849} +models.sub[17991] = { name = "Cmb.Cst.Dagger +2" , model = 28849} +models.sub[17992] = { name = "Triton's Dagger" , model = 28851} +models.sub[17993] = { name = "Platoon Dagger" , model = 28837} +models.sub[17994] = { name = "Calveley's Dagger" , model = 29067} +models.sub[17995] = { name = "Jongleur's Dagger" , model = 28836} +models.sub[17996] = { name = "Stylet" , model = 28841} +models.sub[17997] = { name = "Argent Dagger" , model = 29018} +models.sub[17998] = { name = "Thanatos Baselard" , model = 28840} +models.sub[17999] = { name = "Taillefer's Dagger" , model = 28851} +models.sub[18000] = { name = "Mighty Knife" , model = 28830} +models.sub[18001] = { name = "Harpe" , model = 29026} +models.sub[18002] = { name = "Perseus's Harpe" , model = 29026} +models.sub[18003] = { name = "Swordbreaker" , model = 28847} +models.sub[18004] = { name = "Trailer's Kukri" , model = 28846} +models.sub[18005] = { name = "Heart Snatcher" , model = 28847} +models.sub[18006] = { name = "Hoplites Harpe" , model = 29026} +models.sub[18007] = { name = "Chiroptera Dagger" , model = 29018} +models.sub[18008] = { name = "Hushed Dagger" , model = 28837} +models.sub[18009] = { name = "Martial Knife" , model = 28830} +models.sub[18010] = { name = "Melt Dagger" , model = 28839} +models.sub[18011] = { name = "Melt Knife" , model = 28833} +models.sub[18012] = { name = "Melt Baselard" , model = 28842} +models.sub[18013] = { name = "Melt Kukri" , model = 28845} +models.sub[18014] = { name = "Odorous Knife" , model = 28989} +models.sub[18015] = { name = "Blau Dolch" , model = 28835} +models.sub[18016] = { name = "Odorous Knife +1" , model = 28989} +models.sub[18017] = { name = "Asn. Jambiya" , model = 29051} +models.sub[18018] = { name = "Sirocco Kukri" , model = 28843} +models.sub[18019] = { name = "X's Knife" , model = 28852} +models.sub[18020] = { name = "Mercurial Kris" , model = 28850} +models.sub[18021] = { name = "Titan's Baselarde" , model = 28841} +models.sub[18022] = { name = "Adaman Kris +1" , model = 28849} +models.sub[18023] = { name = "Jambiya" , model = 29051} +models.sub[18024] = { name = "Jambiya +1" , model = 29051} +models.sub[18025] = { name = "Khanjar" , model = 28849} +models.sub[18026] = { name = "Magnet Knife" , model = 28830} +models.sub[18027] = { name = "Palladium Dagger" , model = 29067} +models.sub[18028] = { name = "Matron's Knife" , model = 29068} +models.sub[18029] = { name = "Piercing Dagger" , model = 28837} +models.sub[18030] = { name = "Khimaira Jambiya" , model = 29070} +models.sub[18031] = { name = "Amir Jambiya" , model = 29070} +models.sub[18032] = { name = "Adder Jambiya" , model = 29070} +models.sub[18033] = { name = "Adder Jambiya +1" , model = 29070} +models.sub[18034] = { name = "Dancing Dagger" , model = 29018} +models.sub[18035] = { name = "Deathbone Knife" , model = 28852} +models.sub[18266] = { name = "Relic Dagger" , model = 28835} +models.sub[18267] = { name = "Malefic Dagger" , model = 28835} +models.sub[18268] = { name = "Dynamis Dagger" , model = 28835} +models.sub[18269] = { name = "Batardeau" , model = 28835} +models.sub[18270] = { name = "Mandau" , model = 29006} +models.sub[18271] = { name = "Mandau" , model = 29006} +models.sub[18272] = { name = "Relic Sword" , model = 28941} +models.sub[18273] = { name = "Glyptic Sword" , model = 28941} +models.sub[18274] = { name = "Dynamis Sword" , model = 28941} +models.sub[18275] = { name = "Caliburn" , model = 28941} +models.sub[18276] = { name = "Excalibur" , model = 28992} +models.sub[18277] = { name = "Excalibur" , model = 28992} +models.sub[18284] = { name = "Relic Axe" , model = 28763} +models.sub[18285] = { name = "Leonine Axe" , model = 28763} +models.sub[18286] = { name = "Dynamis Axe" , model = 28763} +models.sub[18287] = { name = "Ogre Killer" , model = 28763} +models.sub[18288] = { name = "Guttler" , model = 29019} +models.sub[18289] = { name = "Guttler" , model = 29019} +models.sub[18308] = { name = "Ihintanto" , model = 28981} +models.sub[18309] = { name = "Mimizuku" , model = 28981} +models.sub[18310] = { name = "Rogetsu" , model = 28981} +models.sub[18311] = { name = "Yoshimitsu" , model = 28981} +models.sub[18312] = { name = "Kikoku" , model = 29016} +models.sub[18313] = { name = "Kikoku" , model = 29016} +models.sub[18320] = { name = "Relic Maul" , model = 28786} +models.sub[18321] = { name = "Battering Maul" , model = 28786} +models.sub[18322] = { name = "Dynamis Maul" , model = 28786} +models.sub[18323] = { name = "Gullintani" , model = 28786} +models.sub[18324] = { name = "Mjollnir" , model = 28979} +models.sub[18325] = { name = "Mjollnir" , model = 28979} +models.sub[18390] = { name = "Templar Hammer" , model = 28785} +models.sub[18391] = { name = "Sacred Mace" , model = 28779} +models.sub[18392] = { name = "Sacred Maul" , model = 28788} +models.sub[18393] = { name = "Sacred Wand" , model = 28900} +models.sub[18394] = { name = "Pilgrim's Wand" , model = 28914} +models.sub[18395] = { name = "Seawolf Cudgel" , model = 28772} +models.sub[18396] = { name = "Sea Rob. Cudgel" , model = 28773} +models.sub[18397] = { name = "Prudence Rod" , model = 29008} +models.sub[18398] = { name = "Raphael's Rod" , model = 28912} +models.sub[18399] = { name = "Charm Wand" , model = 29045} +models.sub[18400] = { name = "Charm Wand +1" , model = 29045} +models.sub[18401] = { name = "Moogle Rod" , model = 29046} +models.sub[18402] = { name = "Mana Wand" , model = 28904} +models.sub[18403] = { name = "High Mana Wand" , model = 28903} +models.sub[18404] = { name = "Ramuh's Mace" , model = 29032} +models.sub[18405] = { name = "Jadagna" , model = 29052} +models.sub[18406] = { name = "Jadagna +1" , model = 29052} +models.sub[18407] = { name = "Imperial Wand" , model = 28917} +models.sub[18408] = { name = "Yigit Bulawa" , model = 29032} +models.sub[18409] = { name = "Jadagna -1" , model = 29052} +models.sub[18410] = { name = "Melt Katana" , model = 28982} +models.sub[18411] = { name = "Buboso" , model = 28986} +models.sub[18412] = { name = "Gassan" , model = 28984} +models.sub[18413] = { name = "Hirenjaku" , model = 29043} +models.sub[18414] = { name = "Hirenjaku +1" , model = 29043} +models.sub[18415] = { name = "Tojaku" , model = 29043} +models.sub[18416] = { name = "Karasuageha" , model = 28986} +models.sub[18417] = { name = "Sayosamonji" , model = 28983} +models.sub[18418] = { name = "Otori" , model = 29039} +models.sub[18419] = { name = "Kugui" , model = 29039} +models.sub[18420] = { name = "Hayabusa" , model = 29066} +models.sub[18421] = { name = "Hayabusa +1" , model = 29066} +models.sub[18422] = { name = "Ryumon" , model = 29061} +models.sub[18423] = { name = "Izayoi" , model = 29072} +models.sub[18424] = { name = "Izayoi +1" , model = 29072} +models.sub[18425] = { name = "Perdu Blade" , model = 29066} +models.sub[18426] = { name = "Sasuke Katana" , model = 29061} +models.sub[18427] = { name = "Hanafubuki" , model = 28984} +models.sub[18428] = { name = "Kogitsunemaru" , model = 29072} +models.sub[18429] = { name = "Shusui" , model = 29111} +models.sub[18430] = { name = "Oninohocho" , model = 29119} +models.sub[18531] = { name = "Veldt Axe +1" , model = 28749} +models.sub[18532] = { name = "Cleofun Axe" , model = 28763} +models.sub[18533] = { name = "Magnus Axe" , model = 28753} +models.sub[18534] = { name = "Charmer's Merlin" , model = 28753} +models.sub[18535] = { name = "Carabinier's Axe" , model = 28750} +models.sub[18536] = { name = "Artio's Axe" , model = 28750} +models.sub[18537] = { name = "Maiden Tabar" , model = 28754} +models.sub[18538] = { name = "Maiden Tabar +1" , model = 28754} +models.sub[18539] = { name = "Tonatiuh Axe" , model = 29263} +models.sub[18540] = { name = "Barbican Axe" , model = 28761} +models.sub[18541] = { name = "Tjukurrpa Axe" , model = 28754} +models.sub[18542] = { name = "Aytanri" , model = 29263} +models.sub[18543] = { name = "Breidox" , model = 28754} +models.sub[18544] = { name = "Breidox +1" , model = 28754} +models.sub[18545] = { name = "Ark Tabar" , model = 29259} +models.sub[18546] = { name = "Gibbous Axe" , model = 29203} +models.sub[18547] = { name = "Ravana's Axe" , model = 29272} +models.sub[18638] = { name = "Mandau" , model = 29006} +models.sub[18639] = { name = "Excalibur" , model = 28992} +models.sub[18641] = { name = "Guttler" , model = 29019} +models.sub[18645] = { name = "Kikoku" , model = 29016} +models.sub[18647] = { name = "Mjollnir" , model = 28979} +models.sub[18652] = { name = "Mandau" , model = 29006} +models.sub[18653] = { name = "Excalibur" , model = 28992} +models.sub[18655] = { name = "Guttler" , model = 29019} +models.sub[18659] = { name = "Kikoku" , model = 29006} +models.sub[18661] = { name = "Mjollnir" , model = 28979} +models.sub[18666] = { name = "Mandau" , model = 29006} +models.sub[18667] = { name = "Excalibur" , model = 28992} +models.sub[18669] = { name = "Guttler" , model = 29019} +models.sub[18673] = { name = "Kikoku" , model = 29016} +models.sub[18675] = { name = "Mjollnir" , model = 28979} +models.sub[18827] = { name = "Oxossi Facon" , model = 29269} +models.sub[18828] = { name = "Oxossi Facon +1" , model = 29269} +models.sub[18829] = { name = "Blustery Dagger" , model = 28847} +models.sub[18830] = { name = "Gusterion" , model = 28847} +models.sub[18841] = { name = "Templar Mace" , model = 28777} +models.sub[18842] = { name = "Nmd. Moogle Rod" , model = 29055} +models.sub[18843] = { name = "Flan Smasher" , model = 28775} +models.sub[18844] = { name = "Miracle Wand" , model = 29045} +models.sub[18845] = { name = "Miracle Wand +1" , model = 29045} +models.sub[18846] = { name = "Battledore" , model = 29069} +models.sub[18847] = { name = "Seveneyes" , model = 29031} +models.sub[18848] = { name = "Brass Jadagna" , model = 29073} +models.sub[18849] = { name = "Brass Jadagna +1" , model = 29073} +models.sub[18850] = { name = "Perdu Wand" , model = 28900} +models.sub[18851] = { name = "Werebuster" , model = 28783} +models.sub[18852] = { name = "Octave Club" , model = 28782} +models.sub[18853] = { name = "Spirit Maul" , model = 28788} +models.sub[18854] = { name = "Fourth Mace" , model = 28777} +models.sub[18855] = { name = "Trainee Hammer" , model = 28787} +models.sub[18856] = { name = "Deae Gratia" , model = 28774} +models.sub[18857] = { name = "Antares" , model = 29109} +models.sub[18858] = { name = "Flanged Mace" , model = 29118} +models.sub[18859] = { name = "Kerykeion" , model = 28905} +models.sub[18860] = { name = "Flanged Mace +1" , model = 29118} +models.sub[18861] = { name = "Grandeur" , model = 28913} +models.sub[18862] = { name = "Clearpath" , model = 28895} +models.sub[18863] = { name = "Dream Bell" , model = 29121} +models.sub[18864] = { name = "Dream Bell +1" , model = 29121} +models.sub[18865] = { name = "Zonure" , model = 29032} +models.sub[18866] = { name = "Club Hammer" , model = 29126} +models.sub[18867] = { name = "Daedalus Hammer" , model = 28785} +models.sub[18868] = { name = "Lady Bell" , model = 29128} +models.sub[18869] = { name = "Lady Bell +1" , model = 29128} +models.sub[18870] = { name = "Dweomer Maul" , model = 28784} +models.sub[18871] = { name = "Kitty Rod" , model = 28912} +models.sub[18872] = { name = "Lyft Ferule" , model = 28900} +models.sub[18873] = { name = "Brise-os" , model = 29073} +models.sub[18874] = { name = "Brise-os +1" , model = 29073} +models.sub[18875] = { name = "Vodun Mace" , model = 28775} +models.sub[18876] = { name = "Vodun Mace +1" , model = 28775} +models.sub[18877] = { name = "Robur Mace" , model = 28775} +models.sub[18878] = { name = "Robur Mace +1" , model = 28775} +models.sub[18879] = { name = "Rounsey Wand" , model = 29207} +models.sub[18880] = { name = "Maestro's Baton" , model = 29211} +models.sub[18881] = { name = "Melomane Mallet" , model = 29212} +models.sub[18882] = { name = "Beaivi's Scepter" , model = 28893} +models.sub[18883] = { name = "Luckitoo" , model = 29032} +models.sub[18884] = { name = "Vejovis Wand" , model = 28897} +models.sub[18885] = { name = "Vejovis Wand +1" , model = 28897} +models.sub[18886] = { name = "Dhyana Rod" , model = 29267} +models.sub[18887] = { name = "Dukkha" , model = 29267} +models.sub[18888] = { name = "Ankylosis Wand" , model = 29271} +models.sub[18891] = { name = "Hannibal's Sword" , model = 28957} +models.sub[18892] = { name = "Corbenic Sword" , model = 28941} +models.sub[18893] = { name = "Magnus Sword" , model = 28945} +models.sub[18894] = { name = "Accolade Sword" , model = 28953} +models.sub[18895] = { name = "Chimeric Fleuret" , model = 28865} +models.sub[18896] = { name = "Honorbound" , model = 29062} +models.sub[18897] = { name = "Isador" , model = 29074} +models.sub[18898] = { name = "Mageblade" , model = 28939} +models.sub[18899] = { name = "Runic Anelace" , model = 28946} +models.sub[18900] = { name = "Skeld Sword" , model = 28953} +models.sub[18901] = { name = "Falcata" , model = 28941} +models.sub[18902] = { name = "Falcata +1" , model = 28941} +models.sub[18903] = { name = "Talekeeper" , model = 29200} +models.sub[18904] = { name = "Ephemeron" , model = 29210} +models.sub[18905] = { name = "Swiftwing" , model = 28960} +models.sub[18906] = { name = "Galenus" , model = 28938} +models.sub[18907] = { name = "Devourer" , model = 28959} +models.sub[18908] = { name = "Dhampyr Sword" , model = 28947} +models.sub[18909] = { name = "Sanus Ensis" , model = 29254} +models.sub[18910] = { name = "Apaisante" , model = 28938} +models.sub[18911] = { name = "Apaisante +1" , model = 28938} +models.sub[18912] = { name = "Ark Saber" , model = 29256} +models.sub[18913] = { name = "Ark Sword" , model = 29257} +models.sub[18914] = { name = "Killer's Kilij" , model = 29056} +models.sub[18915] = { name = "Eradicator's Kilij" , model = 29056} +models.sub[18916] = { name = "Heimdall's Doom" , model = 29076} +models.sub[18969] = { name = "Terpsichore" , model = 29100} +models.sub[18973] = { name = "Yagrush" , model = 29087} +models.sub[18975] = { name = "Murgleis" , model = 29092} +models.sub[18976] = { name = "Vajra" , model = 29094} +models.sub[18977] = { name = "Burtgang" , model = 29098} +models.sub[18979] = { name = "Aymur" , model = 29085} +models.sub[18980] = { name = "Carnwenhan" , model = 29099} +models.sub[18983] = { name = "Nagi" , model = 29093} +models.sub[18986] = { name = "Tizona" , model = 29091} +models.sub[18989] = { name = "Terpsichore" , model = 29100} +models.sub[18993] = { name = "Yagrush" , model = 29087} +models.sub[18995] = { name = "Murgleis" , model = 29092} +models.sub[18996] = { name = "Vajra" , model = 29094} +models.sub[18997] = { name = "Burtgang" , model = 29098} +models.sub[18999] = { name = "Aymur" , model = 29085} +models.sub[19000] = { name = "Carnwenhan" , model = 29099} +models.sub[19003] = { name = "Nagi" , model = 29093} +models.sub[19006] = { name = "Tizona" , model = 29091} +models.sub[19062] = { name = "Yagrush" , model = 29087} +models.sub[19064] = { name = "Murgleis" , model = 29092} +models.sub[19065] = { name = "Vajra" , model = 29094} +models.sub[19066] = { name = "Burtgang" , model = 29098} +models.sub[19068] = { name = "Aymur" , model = 29085} +models.sub[19069] = { name = "Carnwenhan" , model = 29099} +models.sub[19072] = { name = "Nagi" , model = 29093} +models.sub[19075] = { name = "Tizona" , model = 29091} +models.sub[19078] = { name = "Terpsichore" , model = 29100} +models.sub[19082] = { name = "Yagrush" , model = 29087} +models.sub[19084] = { name = "Murgleis" , model = 29092} +models.sub[19085] = { name = "Vajra" , model = 29094} +models.sub[19086] = { name = "Burtgang" , model = 29098} +models.sub[19088] = { name = "Aymur" , model = 29085} +models.sub[19089] = { name = "Carnwenhan" , model = 29099} +models.sub[19092] = { name = "Nagi" , model = 29093} +models.sub[19095] = { name = "Tizona" , model = 29091} +models.sub[19098] = { name = "Terpsichore" , model = 29100} +models.sub[19100] = { name = "Cobra Knife" , model = 28852} +models.sub[19101] = { name = "Trainee Knife" , model = 28989} +models.sub[19102] = { name = "Main Gauche" , model = 28848} +models.sub[19103] = { name = "Darksteel Jambiya" , model = 29081} +models.sub[19104] = { name = "Dst. Jambiya +1" , model = 29081} +models.sub[19105] = { name = "Thug's Jambiya" , model = 29051} +models.sub[19106] = { name = "Thug's Jambiya +1" , model = 29051} +models.sub[19107] = { name = "Azoth" , model = 29102} +models.sub[19108] = { name = "Zareehkl Jambiya" , model = 29081} +models.sub[19109] = { name = "Trilling Dagger" , model = 28840} +models.sub[19110] = { name = "Trainee's Needle" , model = 28841} +models.sub[19111] = { name = "Silktone" , model = 28840} +models.sub[19112] = { name = "Farseer" , model = 28840} +models.sub[19113] = { name = "Ermine's Tail" , model = 29122} +models.sub[19114] = { name = "Galkan Dagger" , model = 28840} +models.sub[19115] = { name = "Fane Baselard" , model = 28840} +models.sub[19116] = { name = "Dweomer Knife" , model = 28830} +models.sub[19117] = { name = "Ogre Jambiya" , model = 29081} +models.sub[19118] = { name = "Machismo" , model = 29131} +models.sub[19119] = { name = "Ranging Knife" , model = 28852} +models.sub[19120] = { name = "Avis" , model = 29082} +models.sub[19121] = { name = "Sleight Kukri" , model = 28846} +models.sub[19122] = { name = "Courser's Pugio" , model = 28834} +models.sub[19123] = { name = "Cinquedea" , model = 28830} +models.sub[19124] = { name = "Creve-coeur" , model = 29051} +models.sub[19125] = { name = "Lyft Jambiya" , model = 29051} +models.sub[19126] = { name = "Papilio Kirpan" , model = 29081} +models.sub[19127] = { name = "Ranging Knife +1" , model = 28852} +models.sub[19128] = { name = "Edgeless Knife" , model = 28832} +models.sub[19129] = { name = "Rapidus Sax" , model = 28851} +models.sub[19130] = { name = "Clement Skean" , model = 28835} +models.sub[19131] = { name = "Magnus Dagger" , model = 28835} +models.sub[19132] = { name = "Twilight Knife" , model = 29199} +models.sub[19133] = { name = "Triplus Dagger" , model = 28849} +models.sub[19134] = { name = "Felibre's Dague" , model = 28830} +models.sub[19135] = { name = "Acinaces" , model = 29051} +models.sub[19136] = { name = "Phurba" , model = 28834} +models.sub[19137] = { name = "Angr Harpe" , model = 29026} +models.sub[19138] = { name = "Verus Knife" , model = 28830} +models.sub[19139] = { name = "Verus Knife +1" , model = 28830} +models.sub[19140] = { name = "Mantodea Harpe" , model = 29205} +models.sub[19141] = { name = "Oneiros Knife" , model = 28830} +models.sub[19142] = { name = "Gnadgott" , model = 28840} +models.sub[19143] = { name = "Lux Pugio" , model = 29206} +models.sub[19144] = { name = "Coruscanti" , model = 29208} +models.sub[19145] = { name = "Asteria" , model = 29213} +models.sub[19146] = { name = "Supernal Knife" , model = 29067} +models.sub[19147] = { name = "Janamaraka" , model = 29051} +models.sub[19148] = { name = "Pugiunculus" , model = 28840} +models.sub[19149] = { name = "Strategema Knife" , model = 28829} +models.sub[19271] = { name = "Osoraku" , model = 28985} +models.sub[19272] = { name = "Yagentoshiro" , model = 28984} +models.sub[19273] = { name = "Onishibari" , model = 29066} +models.sub[19274] = { name = "Trainee Burin" , model = 28987} +models.sub[19275] = { name = "Tsukumo" , model = 28986} +models.sub[19276] = { name = "Midare" , model = 28984} +models.sub[19277] = { name = "Tsugumi" , model = 28987} +models.sub[19278] = { name = "Fuchingiri" , model = 28981} +models.sub[19279] = { name = "Musanto" , model = 28983} +models.sub[19280] = { name = "Narigitsune" , model = 28981} +models.sub[19281] = { name = "Midare +1" , model = 28984} +models.sub[19282] = { name = "Hochomasamune" , model = 29194} +models.sub[19283] = { name = "Rusty Kunai" , model = 28987} +models.sub[19284] = { name = "Hiwa" , model = 28986} +models.sub[19285] = { name = "Kakko" , model = 29072} +models.sub[19286] = { name = "Kakko +1" , model = 29072} +models.sub[19287] = { name = "Kamome" , model = 28986} +models.sub[19288] = { name = "Sekirei" , model = 28984} +models.sub[19289] = { name = "Toki" , model = 28982} +models.sub[19290] = { name = "Aizenkunitoshi" , model = 28985} +models.sub[19291] = { name = "Oirandori" , model = 29066} +models.sub[19292] = { name = "Kogara" , model = 28986} +models.sub[19293] = { name = "Ichi-an" , model = 28984} +models.sub[19294] = { name = "Ichi-an +1" , model = 28984} +models.sub[19295] = { name = "Mujin Tanto" , model = 28985} +models.sub[19296] = { name = "Ban" , model = 28987} +models.sub[19297] = { name = "Kakesu" , model = 28985} +models.sub[19298] = { name = "Ikarigiri" , model = 29261} +models.sub[19299] = { name = "Aisa" , model = 28985} +models.sub[19300] = { name = "Aisa +1" , model = 28985} +models.sub[19301] = { name = "Kawasemi" , model = 29072} +models.sub[19302] = { name = "Uguisu" , model = 29277} +models.sub[19332] = { name = "Peeler" , model = 28831} +models.sub[19333] = { name = "Renegade" , model = 28833} +models.sub[19334] = { name = "Kartika" , model = 29082} +models.sub[19335] = { name = "Athame" , model = 28848} +models.sub[19336] = { name = "Dakini" , model = 28852} +models.sub[19337] = { name = "Side-sword" , model = 28940} +models.sub[19338] = { name = "Schiavona" , model = 28942} +models.sub[19339] = { name = "Nobilis" , model = 28949} +models.sub[19340] = { name = "Antea" , model = 28955} +models.sub[19341] = { name = "Soulsaber" , model = 28925} +models.sub[19347] = { name = "Chopper" , model = 28763} +models.sub[19348] = { name = "Splinter" , model = 28755} +models.sub[19349] = { name = "Bonebiter" , model = 28754} +models.sub[19350] = { name = "Punisher" , model = 28760} +models.sub[19351] = { name = "Skeggiold" , model = 28750} +models.sub[19367] = { name = "Kibashiri" , model = 28982} +models.sub[19368] = { name = "Koruri" , model = 28984} +models.sub[19369] = { name = "Mozu" , model = 28985} +models.sub[19370] = { name = "Isatu" , model = 29039} +models.sub[19371] = { name = "Kuina" , model = 28984} +models.sub[19377] = { name = "Stenz" , model = 28785} +models.sub[19378] = { name = "Rageblow" , model = 28787} +models.sub[19379] = { name = "Culacula" , model = 28788} +models.sub[19380] = { name = "Goedendag" , model = 28775} +models.sub[19381] = { name = "Ingrimm" , model = 28915} +models.sub[19398] = { name = "Twashtar" , model = 29137} +models.sub[19399] = { name = "Almace" , model = 29138} +models.sub[19401] = { name = "Farsha" , model = 29140} +models.sub[19405] = { name = "Kannagi" , model = 29185} +models.sub[19407] = { name = "Gambanteinn" , model = 29187} +models.sub[19416] = { name = "Daka" , model = 29051} +models.sub[19417] = { name = "Parazonium" , model = 28848} +models.sub[19418] = { name = "Kila" , model = 28852} +models.sub[19419] = { name = "Fusetto" , model = 28840} +models.sub[19420] = { name = "Badelaire" , model = 28949} +models.sub[19421] = { name = "Khanda" , model = 28955} +models.sub[19422] = { name = "Shamshir" , model = 28925} +models.sub[19423] = { name = "Machaera" , model = 29053} +models.sub[19428] = { name = "Alard's Axe" , model = 28754} +models.sub[19429] = { name = "Richardet's Axe" , model = 28760} +models.sub[19430] = { name = "Guichard's Axe" , model = 28750} +models.sub[19431] = { name = "Renaud's Axe" , model = 28750} +models.sub[19444] = { name = "Tobi" , model = 28985} +models.sub[19445] = { name = "Enchu" , model = 29039} +models.sub[19446] = { name = "Sekka" , model = 28984} +models.sub[19447] = { name = "Uzura" , model = 28982} +models.sub[19452] = { name = "Canne de Combat" , model = 28788} +models.sub[19453] = { name = "Naboot" , model = 28775} +models.sub[19454] = { name = "Hoeroa" , model = 28916} +models.sub[19455] = { name = "Makhila" , model = 28783} +models.sub[19457] = { name = "Twashtar" , model = 29137} +models.sub[19458] = { name = "Almace" , model = 29138} +models.sub[19460] = { name = "Farsha" , model = 29140} +models.sub[19464] = { name = "Kannagi" , model = 29185} +models.sub[19466] = { name = "Gambanteinn" , model = 29187} +models.sub[19474] = { name = "Daka +1" , model = 29051} +models.sub[19475] = { name = "Parazonium +1" , model = 28848} +models.sub[19476] = { name = "Kila +1" , model = 28852} +models.sub[19477] = { name = "Fusetto +1" , model = 28840} +models.sub[19478] = { name = "Badelaire +1" , model = 28949} +models.sub[19479] = { name = "Khanda +1" , model = 28955} +models.sub[19480] = { name = "Shamshir +1" , model = 28925} +models.sub[19481] = { name = "Machaera +1" , model = 29053} +models.sub[19486] = { name = "Alard's Axe +1" , model = 28754} +models.sub[19487] = { name = "Richardet's Axe +1" , model = 28760} +models.sub[19488] = { name = "Guichard's Axe +1" , model = 28750} +models.sub[19489] = { name = "Renaud's Axe +1" , model = 28750} +models.sub[19502] = { name = "Tobi +1" , model = 28985} +models.sub[19503] = { name = "Enchu +1" , model = 29039} +models.sub[19504] = { name = "Sekka +1" , model = 28984} +models.sub[19505] = { name = "Uzura +1" , model = 28982} +models.sub[19510] = { name = "Canne de Cbt. +1" , model = 28788} +models.sub[19511] = { name = "Naboot +1" , model = 28775} +models.sub[19512] = { name = "Hoeroa +1" , model = 28916} +models.sub[19513] = { name = "Makhila +1" , model = 28783} +models.sub[19535] = { name = "Twashtar" , model = 29137} +models.sub[19536] = { name = "Almace" , model = 29138} +models.sub[19538] = { name = "Farsha" , model = 29140} +models.sub[19542] = { name = "Kannagi" , model = 29185} +models.sub[19544] = { name = "Gambanteinn" , model = 29187} +models.sub[19552] = { name = "Daka +2" , model = 29051} +models.sub[19553] = { name = "Parazonium +2" , model = 28848} +models.sub[19554] = { name = "Kila +2" , model = 28852} +models.sub[19555] = { name = "Fusetto +2" , model = 28840} +models.sub[19556] = { name = "Badelaire +2" , model = 28949} +models.sub[19557] = { name = "Khanda +2" , model = 28955} +models.sub[19558] = { name = "Shamshir +2" , model = 28925} +models.sub[19559] = { name = "Machaera +2" , model = 29053} +models.sub[19564] = { name = "Alard's Axe +2" , model = 28754} +models.sub[19565] = { name = "Richard. Axe +2" , model = 28760} +models.sub[19566] = { name = "Guichard's Axe +2" , model = 28750} +models.sub[19567] = { name = "Renaud's Axe +2" , model = 28750} +models.sub[19580] = { name = "Tobi +2" , model = 28985} +models.sub[19581] = { name = "Enchu +2" , model = 29039} +models.sub[19582] = { name = "Sekka +2" , model = 28984} +models.sub[19583] = { name = "Uzura +2" , model = 28982} +models.sub[19588] = { name = "Canne de Cbt. +2" , model = 28788} +models.sub[19589] = { name = "Naboot +2" , model = 28775} +models.sub[19590] = { name = "Hoeroa +2" , model = 28916} +models.sub[19591] = { name = "Makhila +2" , model = 28783} +models.sub[19614] = { name = "Yagrush" , model = 29087} +models.sub[19616] = { name = "Murgleis" , model = 29092} +models.sub[19617] = { name = "Vajra" , model = 29094} +models.sub[19618] = { name = "Burtgang" , model = 29098} +models.sub[19620] = { name = "Aymur" , model = 29085} +models.sub[19621] = { name = "Carnwenhan" , model = 29099} +models.sub[19624] = { name = "Nagi" , model = 29093} +models.sub[19627] = { name = "Tizona" , model = 29091} +models.sub[19630] = { name = "Terpsichore" , model = 29100} +models.sub[19633] = { name = "Twashtar" , model = 29137} +models.sub[19634] = { name = "Almace" , model = 29138} +models.sub[19636] = { name = "Farsha" , model = 29140} +models.sub[19640] = { name = "Kannagi" , model = 29185} +models.sub[19642] = { name = "Gambanteinn" , model = 29187} +models.sub[19650] = { name = "Daka +3" , model = 29051} +models.sub[19651] = { name = "Parazonium +3" , model = 28848} +models.sub[19652] = { name = "Kila +3" , model = 28852} +models.sub[19653] = { name = "Fusetto +3" , model = 28840} +models.sub[19654] = { name = "Badelaire +3" , model = 28949} +models.sub[19655] = { name = "Khanda +3" , model = 28955} +models.sub[19656] = { name = "Shamshir +3" , model = 28925} +models.sub[19657] = { name = "Machaera +3" , model = 29053} +models.sub[19662] = { name = "Alard's Axe +3" , model = 28754} +models.sub[19663] = { name = "Richard. Axe +3" , model = 28760} +models.sub[19664] = { name = "Guichard's Axe +3" , model = 28750} +models.sub[19665] = { name = "Renaud's Axe +3" , model = 28750} +models.sub[19678] = { name = "Tobi +3" , model = 28985} +models.sub[19679] = { name = "Enchu +3" , model = 29039} +models.sub[19680] = { name = "Sekka +3" , model = 28984} +models.sub[19681] = { name = "Uzura +3" , model = 28982} +models.sub[19686] = { name = "Canne de Cbt. +3" , model = 28788} +models.sub[19687] = { name = "Naboot +3" , model = 28775} +models.sub[19688] = { name = "Hoeroa +3" , model = 28916} +models.sub[19689] = { name = "Makhila +3" , model = 28783} +models.sub[19712] = { name = "Yagrush" , model = 29087} +models.sub[19714] = { name = "Murgleis" , model = 29092} +models.sub[19715] = { name = "Vajra" , model = 29094} +models.sub[19716] = { name = "Burtgang" , model = 29098} +models.sub[19718] = { name = "Aymur" , model = 29085} +models.sub[19719] = { name = "Carnwenhan" , model = 29099} +models.sub[19722] = { name = "Nagi" , model = 29093} +models.sub[19725] = { name = "Tizona" , model = 29091} +models.sub[19728] = { name = "Terpsichore" , model = 29100} +models.sub[19747] = { name = "Mandau" , model = 29006} +models.sub[19748] = { name = "Excalibur" , model = 28992} +models.sub[19750] = { name = "Guttler" , model = 29019} +models.sub[19754] = { name = "Kikoku" , model = 29016} +models.sub[19756] = { name = "Mjollnir" , model = 28979} +models.sub[19788] = { name = "Gorkhali Kukri" , model = 28844} +models.sub[19789] = { name = "Mahakali's Kukri" , model = 28844} +models.sub[19806] = { name = "Twashtar" , model = 29137} +models.sub[19807] = { name = "Almace" , model = 29138} +models.sub[19809] = { name = "Farsha" , model = 29140} +models.sub[19813] = { name = "Kannagi" , model = 29185} +models.sub[19815] = { name = "Gambanteinn" , model = 29187} +models.sub[19821] = { name = "Yagrush" , model = 29087} +models.sub[19823] = { name = "Murgleis" , model = 29092} +models.sub[19824] = { name = "Vajra" , model = 29094} +models.sub[19825] = { name = "Burtgang" , model = 29098} +models.sub[19827] = { name = "Aymur" , model = 29085} +models.sub[19828] = { name = "Carnwenhan" , model = 29099} +models.sub[19831] = { name = "Nagi" , model = 29093} +models.sub[19834] = { name = "Tizona" , model = 29091} +models.sub[19837] = { name = "Terpsichore" , model = 29100} +models.sub[19840] = { name = "Mandau" , model = 29216} +models.sub[19841] = { name = "Excalibur" , model = 29217} +models.sub[19843] = { name = "Guttler" , model = 29219} +models.sub[19847] = { name = "Kikoku" , model = 29223} +models.sub[19849] = { name = "Mjollnir" , model = 29225} +models.sub[19854] = { name = "Twashtar" , model = 29243} +models.sub[19855] = { name = "Almace" , model = 29244} +models.sub[19857] = { name = "Farsha" , model = 29246} +models.sub[19861] = { name = "Kannagi" , model = 29250} +models.sub[19863] = { name = "Gambanteinn" , model = 29252} +models.sub[19871] = { name = "Khandroma" , model = 29070} +models.sub[19872] = { name = "Praxidikai" , model = 28847} +models.sub[19873] = { name = "Thokcha" , model = 28852} +models.sub[19874] = { name = "Centovente" , model = 28840} +models.sub[19875] = { name = "Brunello" , model = 28947} +models.sub[19876] = { name = "Khadga" , model = 28955} +models.sub[19877] = { name = "Shikargar" , model = 28922} +models.sub[19878] = { name = "Thibron" , model = 29053} +models.sub[19883] = { name = "Sacripante" , model = 28753} +models.sub[19884] = { name = "Ganelon" , model = 28759} +models.sub[19885] = { name = "Astolfo" , model = 28756} +models.sub[19886] = { name = "Fernagu" , model = 28750} +models.sub[19899] = { name = "Kasasagi" , model = 29043} +models.sub[19900] = { name = "Majimun" , model = 29039} +models.sub[19901] = { name = "Arisui" , model = 28984} +models.sub[19902] = { name = "Hitaki" , model = 28982} +models.sub[19907] = { name = "Rose Couverte" , model = 28786} +models.sub[19908] = { name = "Tahtib" , model = 28774} +models.sub[19909] = { name = "Tutunui" , model = 28920} +models.sub[19910] = { name = "Ukaldi" , model = 28782} +models.sub[19950] = { name = "Yagrush" , model = 29228} +models.sub[19952] = { name = "Murgleis" , model = 29230} +models.sub[19953] = { name = "Vajra" , model = 29231} +models.sub[19954] = { name = "Burtgang" , model = 29232} +models.sub[19956] = { name = "Aymur" , model = 29234} +models.sub[19957] = { name = "Carnwenhan" , model = 29235} +models.sub[19960] = { name = "Nagi" , model = 29237} +models.sub[19963] = { name = "Tizona" , model = 29240} +models.sub[19966] = { name = "Terpsichore" , model = 29241} +models.sub[20555] = { name = "Mandau" , model = 29006} +models.sub[20556] = { name = "Mandau" , model = 29216} +models.sub[20557] = { name = "Terpsichore" , model = 29100} +models.sub[20558] = { name = "Terpsichore" , model = 29241} +models.sub[20559] = { name = "Vajra" , model = 29094} +models.sub[20560] = { name = "Vajra" , model = 29231} +models.sub[20561] = { name = "Carnwenhan" , model = 29099} +models.sub[20562] = { name = "Carnwenhan" , model = 29235} +models.sub[20563] = { name = "Twashtar" , model = 29137} +models.sub[20564] = { name = "Twashtar" , model = 29243} +models.sub[20573] = { name = "Aern Dagger" , model = 29498} +models.sub[20576] = { name = "Qutrub Knife" , model = 29503} +models.sub[20577] = { name = "Chicken Knife II" , model = 29456} +models.sub[20579] = { name = "Skinflayer" , model = 29102} +models.sub[20580] = { name = "Kustawi" , model = 28829} +models.sub[20581] = { name = "Kustawi +1" , model = 28829} +models.sub[20583] = { name = "Mandau" , model = 29216} +models.sub[20584] = { name = "Terpsichore" , model = 29241} +models.sub[20585] = { name = "Vajra" , model = 29231} +models.sub[20586] = { name = "Carnwenhan" , model = 29235} +models.sub[20587] = { name = "Twashtar" , model = 29243} +models.sub[20592] = { name = "Sangoma" , model = 29430} +models.sub[20594] = { name = "Aeneas" , model = 29432} +models.sub[20595] = { name = "Malevolence" , model = 29213} +models.sub[20596] = { name = "Taming Sari" , model = 29300} +models.sub[20597] = { name = "Enchufla" , model = 29122} +models.sub[20598] = { name = "Shijo" , model = 29068} +models.sub[20599] = { name = "Kali" , model = 29189} +models.sub[20600] = { name = "Nibiru Knife" , model = 29404} +models.sub[20601] = { name = "Blurred Knife" , model = 29131} +models.sub[20602] = { name = "Blurred Knife +1" , model = 29131} +models.sub[20603] = { name = "Ternion Dagger" , model = 28840} +models.sub[20604] = { name = "Ternion Dagger +1" , model = 28840} +models.sub[20605] = { name = "Odium" , model = 29403} +models.sub[20606] = { name = "Anathema Harpe" , model = 29205} +models.sub[20607] = { name = "Anathema Harpe +1" , model = 29205} +models.sub[20608] = { name = "Jugo Kukri" , model = 28843} +models.sub[20609] = { name = "Jugo Kukri +1" , model = 28843} +models.sub[20610] = { name = "Rhadamanthus" , model = 29396} +models.sub[20611] = { name = "Sangarius" , model = 28959} +models.sub[20612] = { name = "Sangarius +1" , model = 28959} +models.sub[20613] = { name = "Pukulatmuj" , model = 28940} +models.sub[20614] = { name = "Pukulatmuj +1" , model = 28940} +models.sub[20615] = { name = "Levante Dagger" , model = 28838} +models.sub[20616] = { name = "Ipetam" , model = 29382} +models.sub[20617] = { name = "Homestead Dagger" , model = 28838} +models.sub[20618] = { name = "Sandung" , model = 29269} +models.sub[20619] = { name = "Polyhymnia" , model = 29122} +models.sub[20620] = { name = "Sabebus" , model = 28848} +models.sub[20621] = { name = "Nanti Knife" , model = 28852} +models.sub[20622] = { name = "Nanti Knife +1" , model = 28852} +models.sub[20623] = { name = "Leisilonu +2" , model = 28851} +models.sub[20624] = { name = "Eminent Dagger" , model = 28835} +models.sub[20625] = { name = "Secespita" , model = 28847} +models.sub[20626] = { name = "Blitto Needle" , model = 28835} +models.sub[20627] = { name = "Surcouf's Jambiya" , model = 29051} +models.sub[20628] = { name = "Mindmeld Kris" , model = 29018} +models.sub[20629] = { name = "Legato Dagger" , model = 29213} +models.sub[20630] = { name = "Atoyac" , model = 29287} +models.sub[20631] = { name = "Khandroma -1" , model = 29070} +models.sub[20632] = { name = "Vanir Knife" , model = 28830} +models.sub[20633] = { name = "Cama. Dagger" , model = 29300} +models.sub[20634] = { name = "Leisilonu +1" , model = 28851} +models.sub[20635] = { name = "Forefront Dagger" , model = 28838} +models.sub[20636] = { name = "Izhiikoh" , model = 29287} +models.sub[20637] = { name = "Aphotic Kukri" , model = 28843} +models.sub[20638] = { name = "Coalition Dirk" , model = 29278} +models.sub[20639] = { name = "Oxidant Baselard" , model = 28842} +models.sub[20640] = { name = "Nitric Baselard" , model = 28842} +models.sub[20641] = { name = "Leisilonu" , model = 28851} +models.sub[20642] = { name = "Tzustes Knife +1" , model = 28832} +models.sub[20643] = { name = "Macoquetza" , model = 29287} +models.sub[20644] = { name = "Tzustes Knife" , model = 28832} +models.sub[20645] = { name = "Excalibur" , model = 28992} +models.sub[20646] = { name = "Excalibur" , model = 29217} +models.sub[20647] = { name = "Murgleis" , model = 29092} +models.sub[20648] = { name = "Murgleis" , model = 29230} +models.sub[20649] = { name = "Burtgang" , model = 29098} +models.sub[20650] = { name = "Burtgang" , model = 29232} +models.sub[20651] = { name = "Tizona" , model = 29091} +models.sub[20652] = { name = "Tizona" , model = 29240} +models.sub[20653] = { name = "Almace" , model = 29138} +models.sub[20654] = { name = "Almace" , model = 29244} +models.sub[20665] = { name = "Kam'lanaut's Sword" , model = 29479} +models.sub[20666] = { name = "Blizzard Brand" , model = 29454} +models.sub[20667] = { name = "Blizzard Brand +1" , model = 29454} +models.sub[20668] = { name = "Firetongue" , model = 29455} +models.sub[20669] = { name = "Firetongue +1" , model = 29455} +models.sub[20674] = { name = "Aern Sword" , model = 29497} +models.sub[20677] = { name = "Colada" , model = 29062} +models.sub[20678] = { name = "Firangi" , model = 29117} +models.sub[20679] = { name = "Tanmogayi" , model = 29030} +models.sub[20680] = { name = "Tanmogayi +1" , model = 29030} +models.sub[20681] = { name = "Flyssa" , model = 29071} +models.sub[20682] = { name = "Flyssa +1" , model = 29071} +models.sub[20683] = { name = "Zantetsuken" , model = 29076} +models.sub[20685] = { name = "Excalibur" , model = 29217} +models.sub[20686] = { name = "Murgleis" , model = 29230} +models.sub[20687] = { name = "Burtgang" , model = 29232} +models.sub[20688] = { name = "Tizona" , model = 29240} +models.sub[20689] = { name = "Almace" , model = 29244} +models.sub[20690] = { name = "Reikiko" , model = 29443} +models.sub[20694] = { name = "Fermion Sword" , model = 29428} +models.sub[20695] = { name = "Sequence" , model = 29433} +models.sub[20696] = { name = "Combuster" , model = 28950} +models.sub[20697] = { name = "Combuster +1" , model = 28950} +models.sub[20698] = { name = "Fettering Blade" , model = 29429} +models.sub[20699] = { name = "Koboto" , model = 28931} +models.sub[20700] = { name = "Nixxer" , model = 29071} +models.sub[20701] = { name = "Iris" , model = 29103} +models.sub[20702] = { name = "Emissary" , model = 28922} +models.sub[20703] = { name = "Deacon Saber" , model = 29256} +models.sub[20704] = { name = "Deacon Sword" , model = 29257} +models.sub[20705] = { name = "Brilliance" , model = 29422} +models.sub[20706] = { name = "Vampirism" , model = 29424} +models.sub[20707] = { name = "Medeina Kilij" , model = 29074} +models.sub[20708] = { name = "Demersal Degen" , model = 28857} +models.sub[20709] = { name = "Demers. Degen +1" , model = 28857} +models.sub[20710] = { name = "Nibiru Blade" , model = 29405} +models.sub[20711] = { name = "Blurred Sword" , model = 29132} +models.sub[20712] = { name = "Blurred Sword +1" , model = 29132} +models.sub[20713] = { name = "Excalipoor" , model = 29401} +models.sub[20714] = { name = "Excalipoor II" , model = 29401} +models.sub[20715] = { name = "Acclimator" , model = 29397} +models.sub[20716] = { name = "Perfervid Sword" , model = 28927} +models.sub[20717] = { name = "Arendsi Fleuret" , model = 28864} +models.sub[20718] = { name = "Claidheamh Soluis" , model = 29383} +models.sub[20719] = { name = "Homestead Blade" , model = 28934} +models.sub[20720] = { name = "Egeking" , model = 28926} +models.sub[20721] = { name = "Mimesis" , model = 28954} +models.sub[20722] = { name = "Usonmunku" , model = 28939} +models.sub[20723] = { name = "Dija Sword" , model = 28939} +models.sub[20724] = { name = "Dija Sword +1" , model = 28939} +models.sub[20725] = { name = "Iztaasu +2" , model = 29190} +models.sub[20726] = { name = "Eminent Scimitar" , model = 28930} +models.sub[20727] = { name = "Tabahi Fleuret" , model = 28864} +models.sub[20728] = { name = "Kheshig Blade" , model = 28953} +models.sub[20729] = { name = "Vivifiante" , model = 28958} +models.sub[20730] = { name = "Predatrice" , model = 29056} +models.sub[20731] = { name = "Xiutleato" , model = 29288} +models.sub[20732] = { name = "Brunello -1" , model = 28947} +models.sub[20733] = { name = "Anahera Saber" , model = 29256} +models.sub[20734] = { name = "Anahera Sword" , model = 29257} +models.sub[20735] = { name = "Cama. Blade" , model = 29301} +models.sub[20736] = { name = "Iztaasu +1" , model = 29190} +models.sub[20737] = { name = "Forefront Blade" , model = 28934} +models.sub[20738] = { name = "Buramenk'ah" , model = 29288} +models.sub[20739] = { name = "Halachuinic Sword" , model = 28956} +models.sub[20740] = { name = "Camatlatia" , model = 29288} +models.sub[20741] = { name = "Coalition Blade" , model = 29279} +models.sub[20742] = { name = "Iztaasu" , model = 29190} +models.sub[20743] = { name = "Bihkah Sword +1" , model = 28942} +models.sub[20744] = { name = "Bihkah Sword" , model = 28942} +models.sub[20790] = { name = "Guttler" , model = 29019} +models.sub[20791] = { name = "Guttler" , model = 29219} +models.sub[20792] = { name = "Aymur" , model = 29085} +models.sub[20793] = { name = "Aymur" , model = 29234} +models.sub[20794] = { name = "Farsha" , model = 29140} +models.sub[20795] = { name = "Farsha" , model = 29246} +models.sub[20796] = { name = "Purgation" , model = 29059} +models.sub[20797] = { name = "Skullrender" , model = 29263} +models.sub[20798] = { name = "Deacon Tabar" , model = 29259} +models.sub[20799] = { name = "Mdomo Axe" , model = 29025} +models.sub[20800] = { name = "Mdomo Axe +1" , model = 29025} +models.sub[20801] = { name = "Nibiru Tabar" , model = 29407} +models.sub[20802] = { name = "Blurred Axe" , model = 29415} +models.sub[20803] = { name = "Blurred Axe +1" , model = 29415} +models.sub[20804] = { name = "Perun" , model = 28763} +models.sub[20805] = { name = "Perun +1" , model = 28763} +models.sub[20806] = { name = "Buramgh" , model = 28755} +models.sub[20807] = { name = "Buramgh +1" , model = 28755} +models.sub[20808] = { name = "Tramontane Axe" , model = 28753} +models.sub[20809] = { name = "Kumbhakarna" , model = 29385} +models.sub[20810] = { name = "Homestead Axe" , model = 28755} +models.sub[20811] = { name = "Arktoi" , model = 29272} +models.sub[20812] = { name = "Izizoeksi" , model = 29293} +models.sub[20813] = { name = "Emxgha" , model = 28759} +models.sub[20814] = { name = "Budliqa" , model = 28762} +models.sub[20815] = { name = "Budliqa +1" , model = 28762} +models.sub[20816] = { name = "Faizzeer +2" , model = 29059} +models.sub[20817] = { name = "Eminent Axe" , model = 28754} +models.sub[20818] = { name = "Hurlbat" , model = 28763} +models.sub[20819] = { name = "Antican Axe" , model = 28754} +models.sub[20820] = { name = "Hatxiik" , model = 29289} +models.sub[20821] = { name = "Sacripante -1" , model = 28753} +models.sub[20822] = { name = "Anahera Tabar" , model = 29259} +models.sub[20823] = { name = "Cama. Axe" , model = 29303} +models.sub[20824] = { name = "Faizzeer +1" , model = 29059} +models.sub[20825] = { name = "Forefront Axe" , model = 28755} +models.sub[20826] = { name = "Hunahpu" , model = 29293} +models.sub[20827] = { name = "Kerehcatl" , model = 29289} +models.sub[20828] = { name = "Brethren Axe" , model = 28763} +models.sub[20829] = { name = "Icoyoca" , model = 29289} +models.sub[20830] = { name = "Coalition Axe" , model = 29281} +models.sub[20831] = { name = "Aalak' Axe" , model = 28756} +models.sub[20832] = { name = "Aalak' Axe +1" , model = 28756} +models.sub[20833] = { name = "Faizzeer" , model = 29059} +models.sub[20970] = { name = "Kikoku" , model = 29016} +models.sub[20971] = { name = "Kikoku" , model = 29223} +models.sub[20972] = { name = "Nagi" , model = 29093} +models.sub[20973] = { name = "Nagi" , model = 29237} +models.sub[20974] = { name = "Kannagi" , model = 29185} +models.sub[20975] = { name = "Kannagi" , model = 29250} +models.sub[20977] = { name = "Heishi Shorinken" , model = 29439} +models.sub[20978] = { name = "Ochu" , model = 29285} +models.sub[20979] = { name = "Aizushintogo" , model = 29111} +models.sub[20980] = { name = "Raicho" , model = 29072} +models.sub[20981] = { name = "Raicho +1" , model = 29072} +models.sub[20982] = { name = "Shuhansadamune" , model = 29194} +models.sub[20983] = { name = "Mijin" , model = 29404} +models.sub[20984] = { name = "Kujaku" , model = 29418} +models.sub[20985] = { name = "Kujaku +1" , model = 29418} +models.sub[20986] = { name = "Achiuchikapu" , model = 29399} +models.sub[20987] = { name = "Tancho" , model = 28984} +models.sub[20988] = { name = "Tancho +1" , model = 28984} +models.sub[20989] = { name = "Izuna" , model = 29389} +models.sub[20990] = { name = "Jushimatsu" , model = 29381} +models.sub[20991] = { name = "Chidori" , model = 28981} +models.sub[20992] = { name = "Taikogane" , model = 29381} +models.sub[20993] = { name = "Senkutanto" , model = 29285} +models.sub[20994] = { name = "Shigi" , model = 29277} +models.sub[20995] = { name = "Isuka" , model = 28984} +models.sub[20996] = { name = "Kannakiri +2" , model = 29119} +models.sub[20997] = { name = "Raimitsukane" , model = 28985} +models.sub[20998] = { name = "Kaitsuburi" , model = 29066} +models.sub[20999] = { name = "Habukatana" , model = 28982} +models.sub[21000] = { name = "Magorokuhocho" , model = 28981} +models.sub[21001] = { name = "Kasasagi -1" , model = 28985} +models.sub[21003] = { name = "Cama. Katana" , model = 28982} +models.sub[21004] = { name = "Kannakiri +1" , model = 29119} +models.sub[21005] = { name = "Kiji" , model = 28986} +models.sub[21006] = { name = "Pamun" , model = 29039} +models.sub[21007] = { name = "Pamun +1" , model = 29039} +models.sub[21008] = { name = "Kotekirigo" , model = 28984} +models.sub[21009] = { name = "Nakajimarai" , model = 28982} +models.sub[21010] = { name = "Nakajimarai +1" , model = 28982} +models.sub[21011] = { name = "Enju" , model = 28985} +models.sub[21012] = { name = "Enju +1" , model = 28985} +models.sub[21013] = { name = "Kannakiri" , model = 29119} +models.sub[21014] = { name = "Ichijintanto" , model = 29285} +models.sub[21060] = { name = "Mjollnir" , model = 28979} +models.sub[21061] = { name = "Mjollnir" , model = 29225} +models.sub[21062] = { name = "Yagrush" , model = 29087} +models.sub[21063] = { name = "Yagrush" , model = 29228} +models.sub[21064] = { name = "Gambanteinn" , model = 29187} +models.sub[21065] = { name = "Gambanteinn" , model = 29252} +models.sub[21066] = { name = "Trial Wand" , model = 29305} +models.sub[21067] = { name = "Nodal Wand" , model = 29305} +models.sub[21068] = { name = "Nodal Wand" , model = 29305} +models.sub[21069] = { name = "Nodal Wand" , model = 29305} +models.sub[21070] = { name = "Idris" , model = 29379} +models.sub[21072] = { name = "Gada" , model = 29109} +models.sub[21073] = { name = "Izcalli" , model = 28787} +models.sub[21074] = { name = "Kupo Rod" , model = 29046} +models.sub[21075] = { name = "Septoptic" , model = 29031} +models.sub[21076] = { name = "Septoptic +1" , model = 29031} +models.sub[21077] = { name = "Mjollnir" , model = 29225} +models.sub[21078] = { name = "Yagrush" , model = 29228} +models.sub[21079] = { name = "Gambanteinn" , model = 29252} +models.sub[21080] = { name = "Idris" , model = 29379} +models.sub[21082] = { name = "Tishtrya" , model = 29441} +models.sub[21083] = { name = "Sucellus" , model = 29008} +models.sub[21084] = { name = "Queller Rod" , model = 28912} +models.sub[21085] = { name = "Solstice" , model = 29271} +models.sub[21086] = { name = "Heartstopper" , model = 29427} +models.sub[21087] = { name = "Heartstopper +1" , model = 29427} +models.sub[21088] = { name = "Divinity" , model = 29423} +models.sub[21089] = { name = "Rubicundity" , model = 29425} +models.sub[21090] = { name = "Loxotic Mace" , model = 28775} +models.sub[21091] = { name = "Loxotic Mace +1" , model = 28775} +models.sub[21092] = { name = "Nibiru Cudgel" , model = 29413} +models.sub[21093] = { name = "Blurred Rod" , model = 29420} +models.sub[21094] = { name = "Blurred Rod +1" , model = 29420} +models.sub[21095] = { name = "Heartbeater" , model = 29400} +models.sub[21096] = { name = "Heartbeater +1" , model = 29400} +models.sub[21097] = { name = "Leafkin Bopper" , model = 29395} +models.sub[21098] = { name = "Leafkin Bopper +1" , model = 29395} +models.sub[21099] = { name = "Magesmasher" , model = 28785} +models.sub[21100] = { name = "Magesmasher +1" , model = 28785} +models.sub[21101] = { name = "Herkuleskeule" , model = 29032} +models.sub[21102] = { name = "Mafic Cudgel" , model = 28772} +models.sub[21103] = { name = "Vadose Rod" , model = 28893} +models.sub[21104] = { name = "Eosuchus Club" , model = 28782} +models.sub[21105] = { name = "Nehushtan" , model = 29391} +models.sub[21107] = { name = "Kyuka Uchiwa" , model = 29380} +models.sub[21108] = { name = "Kyuka Uchiwa +1" , model = 29380} +models.sub[21109] = { name = "Homestead Wand" , model = 28904} +models.sub[21110] = { name = "Sindri" , model = 28784} +models.sub[21111] = { name = "Bolelabunga" , model = 29299} +models.sub[21112] = { name = "Gabaxorea" , model = 28898} +models.sub[21113] = { name = "P. Sprig. Club" , model = 29309} +models.sub[21114] = { name = "R. Sprig. Club" , model = 29307} +models.sub[21115] = { name = "Aedold +2" , model = 29118} +models.sub[21116] = { name = "Cagliostro's Rod" , model = 28912} +models.sub[21117] = { name = "Hagoita" , model = 29069} +models.sub[21118] = { name = "G. Spriggan Club" , model = 29308} +models.sub[21119] = { name = "Eminent Wand" , model = 28900} +models.sub[21120] = { name = "Patriarch Cane" , model = 28913} +models.sub[21121] = { name = "Rose Couverte -1" , model = 28786} +models.sub[21122] = { name = "Mes'yohi Rod" , model = 28892} +models.sub[21123] = { name = "Cama. Wand" , model = 29283} +models.sub[21124] = { name = "Dowser's Wand" , model = 28920} +models.sub[21125] = { name = "Tamaxchi" , model = 29299} +models.sub[21126] = { name = "Aedold +1" , model = 29118} +models.sub[21127] = { name = "Forefront Wand" , model = 28904} +models.sub[21128] = { name = "Mondaha Cudgel" , model = 28773} +models.sub[21129] = { name = "Sharur" , model = 29032} +models.sub[21130] = { name = "Sharur +1" , model = 29032} +models.sub[21131] = { name = "Coalition Rod" , model = 29283} +models.sub[21132] = { name = "Aedold" , model = 29118} +models.sub[21133] = { name = "Sasah Wand +1" , model = 29051} +models.sub[21134] = { name = "Sasah Wand" , model = 29051} +models.sub[21554] = { name = "Arasy Knife" , model = 28829} +models.sub[21555] = { name = "Arasy Knife +1" , model = 28829} +models.sub[21556] = { name = "Beryllium Kris" , model = 29018} +models.sub[21557] = { name = "Beryllium Kris +1" , model = 29018} +models.sub[21558] = { name = "Rune Kris" , model = 29018} +models.sub[21559] = { name = "Raetic Kris" , model = 29018} +models.sub[21560] = { name = "Raetic Kris +1" , model = 29018} +models.sub[21561] = { name = "Tokko Knife" , model = 28830} +models.sub[21562] = { name = "Ajja Knife" , model = 28829} +models.sub[21563] = { name = "Eletta Knife" , model = 29396} +models.sub[21564] = { name = "Kaja Knife" , model = 29508} +models.sub[21565] = { name = "Tauret" , model = 29519} +models.sub[21566] = { name = "Voluspa Knife" , model = 28830} +models.sub[21573] = { name = "Assassin's Knife" , model = 28829} +models.sub[21574] = { name = "Plun. Knife" , model = 28829} +models.sub[21575] = { name = "Gandring" , model = 29486} +models.sub[21576] = { name = "Bard's Knife" , model = 28829} +models.sub[21577] = { name = "Bihu Knife" , model = 28829} +models.sub[21578] = { name = "Barfawc" , model = 29486} +models.sub[21579] = { name = "Comm. Knife" , model = 28829} +models.sub[21580] = { name = "Lanun Knife" , model = 28829} +models.sub[21581] = { name = "Rostam" , model = 29486} +models.sub[21582] = { name = "Etoile Knife" , model = 28829} +models.sub[21583] = { name = "Horos Knife" , model = 28829} +models.sub[21584] = { name = "Setan Kober" , model = 29486} +models.sub[21604] = { name = "Arasy Sword" , model = 28950} +models.sub[21605] = { name = "Arasy Sword +1" , model = 28950} +models.sub[21606] = { name = "Enriching Sword" , model = 28922} +models.sub[21607] = { name = "Enr. Sword +1" , model = 28922} +models.sub[21608] = { name = "Onion Sword II" , model = 29459} +models.sub[21609] = { name = "Save the Queen II" , model = 29462} +models.sub[21610] = { name = "Hepatizon Rapier" , model = 28859} +models.sub[21611] = { name = "Hep. Rapier +1" , model = 28859} +models.sub[21612] = { name = "Raetic Blade" , model = 28926} +models.sub[21613] = { name = "Raetic Blade +1" , model = 28926} +models.sub[21614] = { name = "Hepatizon Sapara" , model = 28927} +models.sub[21615] = { name = "Hep. Sapara +1" , model = 28927} +models.sub[21617] = { name = "Tokko Sword" , model = 28939} +models.sub[21618] = { name = "Ajja Sword" , model = 28944} +models.sub[21619] = { name = "Eletta Sword" , model = 28960} +models.sub[21620] = { name = "Kaja Sword" , model = 29509} +models.sub[21621] = { name = "Naegling" , model = 29520} +models.sub[21622] = { name = "Voluspa Sword" , model = 28947} +models.sub[21625] = { name = "Duelist's Sword" , model = 28950} +models.sub[21626] = { name = "Vitiation Sword" , model = 28950} +models.sub[21627] = { name = "Crocea Mors" , model = 29491} +models.sub[21628] = { name = "Valor Sword" , model = 28950} +models.sub[21629] = { name = "Cabal. Sword" , model = 28950} +models.sub[21630] = { name = "Moralltach" , model = 29491} +models.sub[21631] = { name = "Mirage Sword" , model = 28950} +models.sub[21632] = { name = "Luhlaza Sword" , model = 28950} +models.sub[21633] = { name = "Zomorrodnegar" , model = 29491} +models.sub[21635] = { name = "Malignance Sword" , model = 28952} +models.sub[21704] = { name = "Arasy Tabar" , model = 28753} +models.sub[21705] = { name = "Arasy Tabar +1" , model = 28753} +models.sub[21706] = { name = "Barbarity" , model = 28763} +models.sub[21707] = { name = "Barbarity +1" , model = 28763} +models.sub[21708] = { name = "Beryllium Pick" , model = 28759} +models.sub[21709] = { name = "Beryllium Pick +1" , model = 28759} +models.sub[21710] = { name = "Raetic Axe" , model = 28757} +models.sub[21711] = { name = "Raetic Axe +1" , model = 28757} +models.sub[21712] = { name = "Voluspa Axe" , model = 28759} +models.sub[21715] = { name = "Monster Axe" , model = 28753} +models.sub[21716] = { name = "Ankusa Axe" , model = 28753} +models.sub[21717] = { name = "Pangu" , model = 29483} +models.sub[21718] = { name = "Tokko Axe" , model = 28754} +models.sub[21719] = { name = "Ajja Axe" , model = 28753} +models.sub[21720] = { name = "Eletta Axe" , model = 29263} +models.sub[21721] = { name = "Kaja Axe" , model = 29522} +models.sub[21722] = { name = "Dolichenus" , model = 29522} +models.sub[21741] = { name = "Demonic Axe" , model = 29465} +models.sub[21742] = { name = "Aern Axe" , model = 29499} +models.sub[21744] = { name = "Gramk's Axe" , model = 29502} +models.sub[21746] = { name = "Digirbalag" , model = 28754} +models.sub[21747] = { name = "Freydis" , model = 29191} +models.sub[21748] = { name = "Habilitator" , model = 29059} +models.sub[21749] = { name = "Habilitator +1" , model = 29059} +models.sub[21750] = { name = "Guttler" , model = 29219} +models.sub[21751] = { name = "Aymur" , model = 29234} +models.sub[21752] = { name = "Farsha" , model = 29246} +models.sub[21753] = { name = "Tri-edge" , model = 29435} +models.sub[21904] = { name = "Kanaria" , model = 29043} +models.sub[21905] = { name = "Taka" , model = 29277} +models.sub[21906] = { name = "Kikoku" , model = 29223} +models.sub[21907] = { name = "Nagi" , model = 29237} +models.sub[21908] = { name = "Kannagi" , model = 29250} +models.sub[21909] = { name = "Yoshikiri" , model = 29072} +models.sub[21910] = { name = "Yoshikiri +1" , model = 29072} +models.sub[21912] = { name = "Voluspa Katana" , model = 28985} +models.sub[21915] = { name = "Koga Shin." , model = 28985} +models.sub[21916] = { name = "Mochi. Shin." , model = 28985} +models.sub[21917] = { name = "Fudo Masamune" , model = 29488} +models.sub[21918] = { name = "Tokko Katana" , model = 28985} +models.sub[21919] = { name = "Ajja Katana" , model = 28981} +models.sub[21920] = { name = "Eletta Katana" , model = 29072} +models.sub[21921] = { name = "Kaja Katana" , model = 29515} +models.sub[21922] = { name = "Gokotai" , model = 29515} +models.sub[21923] = { name = "Debahocho" , model = 28984} +models.sub[21924] = { name = "Debahocho +1" , model = 28984} +models.sub[22004] = { name = "Soulflayer's Wand" , model = 29495} +models.sub[22006] = { name = "Voluspa Hammer" , model = 28784} +models.sub[22015] = { name = "Arasy Rod" , model = 28890} +models.sub[22016] = { name = "Arasy Rod +1" , model = 28890} +models.sub[22017] = { name = "Seika Uchiwa" , model = 29470} +models.sub[22018] = { name = "Seika Uchiwa +1" , model = 29470} +models.sub[22019] = { name = "Jingly Rod" , model = 29473} +models.sub[22020] = { name = "Jingly Rod +1" , model = 29473} +models.sub[22021] = { name = "Ames" , model = 28901} +models.sub[22022] = { name = "Ames +1" , model = 28901} +models.sub[22023] = { name = "Beryllium Mace" , model = 28775} +models.sub[22024] = { name = "Beryllium Mace +1" , model = 28775} +models.sub[22025] = { name = "Raetic Rod" , model = 29008} +models.sub[22026] = { name = "Raetic Rod +1" , model = 29008} +models.sub[22027] = { name = "Tokko Rod" , model = 28891} +models.sub[22028] = { name = "Ajja Rod" , model = 28890} +models.sub[22029] = { name = "Eletta Rod" , model = 28912} +models.sub[22030] = { name = "Kaja Rod" , model = 29517} +models.sub[22031] = { name = "Maxentius" , model = 29517} +models.sub[22033] = { name = "Cleric's Wand" , model = 28890} +models.sub[22034] = { name = "Piety Wand" , model = 28890} +models.sub[22035] = { name = "Asclepius" , model = 29490} +models.sub[22036] = { name = "Bagua Wand" , model = 28890} +models.sub[22037] = { name = "Sifang Wand" , model = 28890} +models.sub[22038] = { name = "Bhima" , model = 29490} +models.sub[22039] = { name = "Floral Hagoita" , model = 29507} \ No newline at end of file diff --git a/addons/EasyNuke/EasyNuke.lua b/addons/EasyNuke/EasyNuke.lua new file mode 100644 index 0000000000..055bcfe9d0 --- /dev/null +++ b/addons/EasyNuke/EasyNuke.lua @@ -0,0 +1,253 @@ +--[[ +Copyright © 2018, Nyarlko +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 EasyNuke 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 Nyarlko, or it's members, 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 = 'EasyNuke' +_addon.author = 'Nyarlko' +_addon.version = '1.0.8' +_addon.command = "ez" + +require('sets') +require('tables') +require('strings') + +config = require('config') + +local defaults = T{} +defaults.current_element = "fire" +defaults.target_mode = "t" +settings = config.load(defaults) + +current_element = "fire" +target_mode = "t" + +elements = T{"fire","wind","thunder","light","ice","water","earth","dark"} +elements_dark = T{"ice","water","earth","dark"} +elements_light = T{"fire","wind","thunder","light"} +elements_index = 1 +other_modes = S{"drain","aspir","absorb","cure"} + +targets = T{"t","bt","stnpc",} +targets_index = 1 + +spell_tables = {} +spell_tables["fire"] = {"Fire","Fire II","Fire III","Fire IV","Fire V","Fire VI",} +spell_tables["fire"]["ga"] = {"Firaga","Firaga II","Firaga III","Firaja",} +spell_tables["fire"]["ra"] = {"Fira","Fira II","Fira III"} +spell_tables["fire"]["helix"] = {"Pyrohelix","Pyrohelix II"} +spell_tables["fire"]["am"] = {"Flare","Flare II"} +spell_tables["earth"] = {"Stone","Stone II","Stone III","Stone IV","Stone V","Stone VI",} +spell_tables["earth"]["ga"] = {"Stonega","Stonega II","Stonega III","Stoneja",} +spell_tables["earth"]["ra"] = {"Stonera","Stonera II","Stonera III"} +spell_tables["earth"]["helix"] = {"Geohelix","Geohelix II"} +spell_tables["earth"]["am"] = {"Quake","Quake II"} +spell_tables["wind"] = {"Aero","Aero II","Aero III","Aero IV","Aero V","Aero VI",} +spell_tables["wind"]["ga"] = {"Aeroga","Aeroga II","Aeroga III","Aeroja",} +spell_tables["wind"]["ra"] = {"Aerora","Aerora II","Aerora III"} +spell_tables["wind"]["helix"] = {"Anemohelix","Anemohelix II"} +spell_tables["wind"]["am"] = {"Tornado","Tornado II"} +spell_tables["water"] = {"Water","Water II","Water III","Water IV","Water V","Water VI",} +spell_tables["water"]["ga"] = {"Waterga","Waterga II","Waterga III","Waterja",} +spell_tables["water"]["ra"] = {"Watera","Watera II","Watera III"} +spell_tables["water"]["helix"] = {"Hydrohelix","Hydrohelix II"} +spell_tables["water"]["am"] = {"Flood","Flood II"} +spell_tables["ice"] = {"Blizzard","Blizzard II","Blizzard III","Blizzard IV","Blizzard V","Blizzard VI",} +spell_tables["ice"]["ga"] = {"Blizzaga","Blizzaga II","Blizzaga III","Blizzaja",} +spell_tables["ice"]["ra"] = {"Blizzara","Blizzara II","Blizzara III"} +spell_tables["ice"]["helix"] = {"Cryohelix","Cryohelix II"} +spell_tables["ice"]["am"] = {"Freeze","Freeze II"} +spell_tables["thunder"] = {"Thunder","Thunder II","Thunder III","Thunder IV","Thunder V","Thunder VI",} +spell_tables["thunder"]["ga"] = {"Thundaga","Thundaga II","Thundaga III","Thundaja",} +spell_tables["thunder"]["ra"] = {"Thundara","Thundara II","Thundara III"} +spell_tables["thunder"]["helix"] = {"Ionohelix","Ionohelix II"} +spell_tables["thunder"]["am"] = {"Burst","Burst II"} +spell_tables["light"] = {"Banish","Banish II","Holy","Banish III",} +spell_tables["light"]["ga"] = {"Banishga","Banishga II"} +spell_tables["light"]["helix"] = {"Luminohelix","Luminohelix II"} +spell_tables["dark"] = {"Impact"} +spell_tables["dark"]["ga"] = {"Comet"} +spell_tables["dark"]["helix"] = {"Noctohelix", "Noctohelix II"} +spell_tables["cure"] = {"Cure","Cure II","Cure III","Cure IV","Cure V","Cure VI"} +spell_tables["cure"]["ga"] = {"Curaga","Curaga II","Curaga III","Curaga IV","Curaga V",} +spell_tables["cure"]["ra"] = {"Cura","Cura II","Cura III"} +spell_tables["drain"] = {"Aspir","Aspir II","Aspir III","Drain","Drain II","Drain III"} +spell_tables["drain"]["ga"] = spell_tables["drain"] +spell_tables["drain"]["ra"] = spell_tables["drain"] +spell_tables["aspir"] = spell_tables["drain"] +spell_tables["aspir"]["ga"] = spell_tables["drain"] +spell_tables["aspir"]["ra"] = spell_tables["drain"] +spell_tables["absorb"] = {"Absorb-Acc","Absorb-TP","Absorb-Attri","Absorb-STR","Absorb-DEX","Absorb-VIT","Absorb-AGI","Absorb-INT","Absorb-MND","Absorb-CHR"} +spell_tables["absorb"]["ga"] = spell_tables["absorb"] +spell_tables["absorb"]["ra"] = spell_tables["absorb"] + +local indices = { + fire = 1, + wind = 2, + thunder = 3, + light = 4, + ice = 5, + water = 6, + earth = 7, + dark = 8, +} + +function execute_spell_cast(spell_type, arg) + local current_spell_table = nil + if spell_type == nil then + current_spell_table = spell_tables[current_element] + else + current_spell_table = spell_tables[current_element][spell_type] + end + if arg == nil then arg = 1 end + arg = tonumber(arg) + if current_spell_table == nil or arg > #current_spell_table then + windower.add_to_chat(206,"Invalid Spell.") return + end + windower.chat.input("/ma \""..current_spell_table[arg].."\" <"..target_mode..">") +end + +windower.register_event("unhandled command", function (command, arg) + if command == "boom" or command == "nuke" then + execute_spell_cast(nil, arg) + elseif command == "boomga" or command == "bga" then + execute_spell_cast("ga", arg) + elseif command == "boomra" or command == "bra" then + execute_spell_cast("ra", arg) + elseif command == "boomhelix" or command == "bhelix" then + execute_spell_cast("helix", arg) + elseif command == "boomam" or command == "bam" then + execute_spell_cast("am", arg) + end +end) + +windower.register_event('addon command', function (command, arg) + + if command == "boom" or command == "nuke" then + execute_spell_cast(nil, arg) + elseif command == "boomga" or command == "bga" then + execute_spell_cast("ga", arg) + elseif command == "boomra" or command == "bra" then + execute_spell_cast("ra", arg) + elseif command == "boomhelix" or command == "bhelix" then + execute_spell_cast("helix", arg) + elseif command == "boomam" or command == "bam" then + execute_spell_cast("am", arg) + + elseif command == "target" then + if arg then + arg = string.lower(arg) + target_mode = arg + else + targets_index = targets_index % #targets + 1 + target_mode = targets[targets_index] + end + windower.add_to_chat(206,"Target Mode is now: "..target_mode) + + elseif command == "element" or command == "mode" then + arg = string.lower(arg) + if elements:contains(arg) or other_modes:contains(arg) then + current_element = arg + windower.add_to_chat(206,"Element Mode is now: "..string.ucfirst(current_element)) + else + windower.add_to_chat(206,"Invalid element") + end + + elseif command == "cycle" then + if arg then + arg = string.lower(arg) + end + if arg == nil then + if not elements:contains(current_element) then + elements_index = 1 + else + elements_index = indices[current_element] + elements_index = elements_index % 8 + 1 + end + current_element = elements[elements_index] + elseif arg == "back" then + if not elements:contains(current_element) then + elements_index = 1 + else + elements_index = indices[current_element] + elements_index = elements_index - 1 + end + if elements_index < 1 then + elements_index = 8 + end + current_element = elements[elements_index] + elseif arg == "dark" then + if not elements_dark:contains(current_element) then + elements_index = 1 + else + elements_index = elements_index % 4 + 1 + end + current_element = elements_dark[elements_index] + elseif arg == "light" then + if not elements_light:contains(current_element) then + elements_index = 1 + else + elements_index = elements_index % 4 + 1 + end + current_element = elements_light[elements_index] + elseif arg == "fusion" or "fus" then + if current_element ~= "fire" and current_element ~= "light" then + current_element = "fire" + elseif current_element == "fire" then + current_element = "light" + elseif current_element == "light" then + current_element = "fire" + end + elseif arg == "distortion" or arg == "dist" then + if current_element ~= "ice" and current_element ~= "water" then + current_element = "ice" + elseif current_element == "ice" then + current_element = "water" + elseif current_element == "water" then + current_element = "ice" + end + elseif arg == "gravitation" or arg == "grav" then + if current_element ~= "earth" and current_element ~= "dark" then + current_element = "earth" + elseif current_element == "earth" then + current_element = "dark" + elseif current_element == "dark" then + current_element = "earth" + end + elseif arg == "fragmentation" or arg == "frag" then + if current_element ~= "thunder" and current_element ~= "wind" then + current_element = "thunder" + elseif current_element == "thunder" then + current_element = "wind" + elseif current_element == "wind" then + current_element = "thunder" + end + end + windower.add_to_chat(206, "Element Mode is now: "..string.ucfirst(current_element)) + elseif command == "show" or command == "current" or command == "showcurrent" then + windower.add_to_chat(206, "----- Element Mode: "..string.ucfirst(current_element).." --- Target Mode: < "..target_mode.." > -----") + end +end) diff --git a/addons/EasyNuke/readme.md b/addons/EasyNuke/readme.md new file mode 100644 index 0000000000..1d92b7bff5 --- /dev/null +++ b/addons/EasyNuke/readme.md @@ -0,0 +1,81 @@ +EasyNuke provides universal commands for casting single target and area of effect BLM and GEO nukes, and WHM cures. + +Commands: + +#### element XXX +* Changes current element mode to XXX. + * EX: //ez element ice <<<< Sets mode to ice. + * Macro usage: /con ez element XXX + * Valid arguments: Fire, Wind, Thunder, Light, Ice, Water, Earth, Dark, Drain, Aspir, Absorb, Cure + * Cure Mode: Follows standard single/ga/ra pattern and usage + * Drain and Aspir Mode: Aspir, Aspir II, Aspir III, Drain, Drain II, Drain III + * Absorb Mode: Absorb-Acc, Absorb-TP, Absorb-Attri, Absorb-STR, Absorb-DEX, Absorb-VIT, Absorb-AGI, Absorb-INT, Absorb-MND, Absorb-CHR + * EX: //ez element absorb >>> //ez boom 4 <<<< Casts Absorb-STR + * Macro usage: /con ez element XXX + +#### cycle +* Cycles through element modes in the following left-to-right order: Fire, Wind, Thunder, Light, Ice, Water, Earth, Dark + * EX: //ez cycle <<<< If you were in Light mode, then you will change to Ice mode. + * Macro usage: /con ez cycle + +#### cycle back +* Same as "cycle", but goes in right-to-left order. + * EX: //ez cycle back <<<< If you were in Light mode, then you will change to Thunder mode. + * Macro usage: /con ez cycle back + +#### cycle dark +* Cycles through element modes in the following order: Ice, Water, Earth, Dark + * EX: //ez cycle dark <<<< If you were in Dark mode, then you will change to Ice mode. + * Macro usage: /con ez cycle dark + +#### cycle light +* Cycles through element modes in the following order: Fire, Wind, Thunder, Light + * EX: //ez cycle light <<<< If you were in Light mode, then you will change to Fire mode. + * Macro usage: /con ez cycle light + +#### cycle XXX +* Cycles between the two elements of a T2 skillchain. + * Valid commands: Elements included + * Fusion, Fus: Fire, Light + * Fragmentation, Frag: Thunder, Wind + * Distortion, Dist: Ice, Water + * Gravitation, Grav: Earth, Dark + * EX: //ez cycle dist <<<< If you were in Ice mode, will change you to Water mode. If you were in any other mode, will change you to Ice mode. + * Macro usage: /con ez cycle fragmentation + +#### target XXX +* Changes targeting mode to #. This sets what's between the < > brackets used for targeting in macros. + * EX: //ez target bt <<<< Spells will be cast using . + * There are no failsafes for this. Any given argument will be accepted, even if it does not function as a targeting argument. + * If no argument is given, then will cycle through target modes in the following order: t, bt, stnpc + * Macro usage: /con ez target # OR /con ez target + +#### showcurrent / show / current +* Echoes the current elemental and targeting modes in the chat log. + * EX: //ez showcurrent + * Macro usage: /con ez show + +#### boom XXX +* Casts a single target tierXXX nuke of the current element, and using the current targeting mode. + * EX: //ez boom 4 <<<< If Element Mode is Fire, and targeting mode is "t", you will cast Fire IV on your current target. + * EX2: //boom 6 <<<< If Element Mode is Ice, and targeting mode is "bt", you will cast Blizzard VI on the current battle target. + * Macro usage: /con ez boom # /OR/ /con boom # + +#### boomga XXX +* Casts an area of effect tierXXX nuke of the current element: BLM: -ga, -ga II, -ga III, -ja. (Also works for Curaga's while in Cure mode.) + * EX: //ez boomga 4 <<<< If Element Mode is Ice, and targeting mode is "t", will cast Blizzaja on your current target. + * EX2: //boomga 3 <<<< If Element Mode is Ice, and targeting mode is "bt", you will cast Blizzaga III on the current battle target. + * Macro usage: /con ez boomga # /OR/ /con boomga # + +#### boomra XXX +* Casts an area of effect nuke of tier XXX. GEO's -ra AOE nukes and WHM's Cura line + * EX: //ez boomra 3 <<<< If Element Mode is Ice, and mode is "bt", will cast Blizzara III on your current battle target. + * EX2: //boomra 2 <<<< If Element Mode is Cure, and mode is "me", you will cast Cura II on yourself. + * Macro usage: /con ez boomra # /OR/ /con boomra # + +#### boomhelix +* Casts the appropriate SCH Helix spell of tier XXX. + * EX: //ez boomhelix 2 <<<< If Element Mode is Ice, and target mode is "t", will cast Cryohelix II on your current target. + * EX2: //boomhelix <<<< If Element Mode is Fire, and target mode is "bt", will cast Pyrohelix on your current battle target. + * Macro usage: /con ez boomhelix # /OR/ /con boomhelix # +* Also supports a short version //bhelix # or //ez bhelix \ No newline at end of file diff --git a/addons/EmpyPopTracker/EmpyPopTracker.lua b/addons/EmpyPopTracker/EmpyPopTracker.lua new file mode 100644 index 0000000000..2b5b431a8a --- /dev/null +++ b/addons/EmpyPopTracker/EmpyPopTracker.lua @@ -0,0 +1,388 @@ +--[[ +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.7.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 +defaults.colors = {} +defaults.colors.needed = {} +defaults.colors.needed.red = 255 +defaults.colors.needed.green = 50 +defaults.colors.needed.blue = 50 +defaults.colors.obtained = {} +defaults.colors.obtained.red = 100 +defaults.colors.obtained.green = 255 +defaults.colors.obtained.blue = 100 +defaults.colors.pool = {} +defaults.colors.pool.red = 255 +defaults.colors.pool.green = 170 +defaults.colors.pool.blue = 0 +defaults.colors.bg = {} +defaults.colors.bg.red = 0 +defaults.colors.bg.green = 0 +defaults.colors.bg.blue = 0 +defaults.colors.bgall = {} +defaults.colors.bgall.red = 0 +defaults.colors.bgall.green = 75 +defaults.colors.bgall.blue = 0 +defaults.collectables = true +defaults.expanded = true + +EmpyPopTracker.settings = config.load(defaults) +EmpyPopTracker.text = require('texts').new(EmpyPopTracker.settings.text, EmpyPopTracker.settings) + +function start_color(color) + return '\\cs(' .. EmpyPopTracker.settings.colors[color].red .. ',' .. EmpyPopTracker.settings.colors[color].green .. ',' .. EmpyPopTracker.settings.colors[color].blue .. ')' +end + +function owns_item(id, items) + for _, bag in pairs(items) do + if type(bag) == 'table' then + for _, item in ipairs(bag) do + if item.id == id then + return true + end + end + end + end + + return false +end + +function get_item_count(id, items) + local count = 0 + for _, bag in pairs(items) do + if type(bag) == 'table' then + for _, item in ipairs(bag) do + if item.id == id then + count = count + item.count + end + end + end + end + + return count +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 + + if depth == 1 and EmpyPopTracker.settings.expanded then + text = text .. '\n' + end + + local item_colour = start_color(owns_pop and 'obtained' or 'needed') + local pool_notification = '' + if in_pool_count > 0 then + pool_notification = start_color('pool') .. ' [' .. in_pool_count .. ']' .. '\\cr' + end + + local name_color = '' + local name_color_end = '' + if not EmpyPopTracker.settings.expanded and owns_pop then + name_color = item_colour + name_color_end = '\\cr' + end + + text = text .. '\n' .. get_indent(depth) .. name_color .. pop.dropped_from.name .. name_color_end + + if EmpyPopTracker.settings.expanded then + text = text .. '\n' .. get_indent(depth) .. ' >> ' .. item_colour .. item_identifier .. pop_name .. '\\cr' .. pool_notification + end + + if pop.dropped_from.pops then + text = text .. generate_text(pop.dropped_from, key_items, items, depth + 1) + end + end + + if data.collectable and EmpyPopTracker.settings.collectables then + local count = get_item_count(data.collectable, items) + local start = '' + local finish = '' + if count >= data.collectable_target_count then + start = start_color('obtained') + finish = '\\cr' + end + + text = text .. '\n\n' .. start .. res.items[data.collectable].name .. ': ' .. count .. '/' .. data.collectable_target_count .. finish + end + + return text +end + +EmpyPopTracker.generate_info = function(nm, key_items, items) + return { + has_all_pops = not nm.pops or T(nm.pops):all(function(item) + -- Avoids confusing item and key item IDs + if item.type == 'item' then + return owns_item(item.id, items) + end + + return owns_key_item(item.id, key_items) + end), + text = generate_text(nm, key_items, items, 1) + } +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 + commands[command](...) + else + commands.help() + end +end) + +commands = {} + +commands.track = function(...) + local nm_search_pattern = table.concat({...}, ' ') + 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() +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 mini - toggles mini/expanded mode') + windower.add_to_chat(EmpyPopTracker.settings.add_to_chat_mode, '//ept collectables - toggles the collectable item') + 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 + +commands.collectables = function() + EmpyPopTracker.settings.collectables = not EmpyPopTracker.settings.collectables + EmpyPopTracker.settings:save() + EmpyPopTracker.update() +end + +commands.mini = function() + EmpyPopTracker.settings.expanded = not EmpyPopTracker.settings.expanded + EmpyPopTracker.settings:save() + EmpyPopTracker.update() +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_pops then + EmpyPopTracker.text:bg_color(EmpyPopTracker.settings.colors.bgall.red, EmpyPopTracker.settings.colors.bgall.green, EmpyPopTracker.settings.colors.bgall.blue) + else + EmpyPopTracker.text:bg_color(EmpyPopTracker.settings.colors.bg.red, EmpyPopTracker.settings.colors.bg.green, EmpyPopTracker.settings.colors.bg.blue) + 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 diff --git a/addons/EmpyPopTracker/README.md b/addons/EmpyPopTracker/README.md new file mode 100644 index 0000000000..42a99a5b9d --- /dev/null +++ b/addons/EmpyPopTracker/README.md @@ -0,0 +1,69 @@ +# FFXI Empy Pop Tracker + +An FFXI Windower 4 addon that tracks items and key items for popping various NMs, such as Briareus, Apademak and Warder of Courage. + +![Example of Cirein-croin tracking](readme/demo.png) ![All KIs obtained](readme/demo-full.png) + +Originally developed to track Abyssea Empyrean weapon NMs, hence the name. 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). + +All text colours are configurable via the auto-generated settings.xml file. + +## Installation + +Empy Pop Tracker is now available via the Windower 4 addons list. + +## Load + +`//lua load empypoptracker` + +Note: You won't have to do this if you obtained this addon via Windower. + +## 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` + +### Toggle Mini Mode + +`//ept mini` + +### Toggle Collectable Item Display + +`//ept collectables` + +### 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 + +If there's an NM you want to have added, or if you notice something not quite right, please [raise an issue](https://github.com/xurion/ffxi-empy-pop-tracker/issues). + +Or better yet, [pull requests](https://github.com/xurion/ffxi-empy-pop-tracker/pulls) are welcome! diff --git a/addons/EmpyPopTracker/nms/README.md b/addons/EmpyPopTracker/nms/README.md new file mode 100644 index 0000000000..38b7f51c90 --- /dev/null +++ b/addons/EmpyPopTracker/nms/README.md @@ -0,0 +1,70 @@ +# NM data + +The data structure for each trackable NM uses a series of nested NM entities. A standard NM entity contains the following data: + +| Key | Type | Required? | Description | +| ------------------------ | --------- | --------- | ----------------------------------- | +| name | String | Required | Name of the NM | +| collectable | Number | Optional | The ID of the collectable item | +| collectable_target_count | Number | Optional | The target no. of collectable items | +| pops | Table | Optional | The pop information for the NM | +| pops{}.id | Number | Required | The ID of the item/key item | +| pops{}.type | String | Required | Either "key item" or "item" | +| pops{}.dropped_from | NM Entity | Required | A nested set of NM information | + +A simple example of the above would be: + +```lua +{ + name = 'Azdaja', + collectable = 3292, --Azdaja's Horn + collectable_target_count = 75, + pops = { { + id = 1531, --Vacant Bugard Eye + type = 'key item', + dropped_from = { name = 'Deelgeed, Timed (F-9/F-10)' } + } } +} +``` + +A larger example with multiple nested entities: + +```lua +{ + name = 'Bukhis', + collectable = 2966, --Bukhis's Wing + collectable_target_count = 50, + pops = { { + id = 1508, --Ingrown Taurus Nail + type = 'key item', + dropped_from = { + name = 'Khalkotaur, Forced (F-4)', + pops = { { + id = 3098, --Gnarled Taurus Horn + type = 'item', + dropped_from = { name = 'Aestutaur (G-9/G-10)' } + } } + } + }, { + id = 1509, --Ossified Gargouille Hand + type = 'key item', + dropped_from = { + name = 'Quasimodo, Forced (F-4)', + pops = { { + id = 3099, --Gargouille Stone + type = 'item', + dropped_from = { + name = 'Gruesome Gargouille (F-10/G-10)' + } + } } + } + }, { + id = 1510, --Imbrued Vampyr Fang + type = 'key item', + dropped_from = { name = 'Lord Varney, Timed (G-10/H-10)' } + } } +} + +``` + +The main addon file requires the index.lua file which in turn is responsible for requiring and returning data for each nm. diff --git a/addons/EmpyPopTracker/nms/alfard.lua b/addons/EmpyPopTracker/nms/alfard.lua new file mode 100644 index 0000000000..a88f6c9c3a --- /dev/null +++ b/addons/EmpyPopTracker/nms/alfard.lua @@ -0,0 +1,60 @@ +--[[ +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. +]] + +return { + name = 'Alfard', + collectable = 3291, --Alfard's Fang + collectable_target_count = 75, + pops = { { + id = 1530, --Venomous hydra fang + type = 'key item', + dropped_from = { + name = 'Ningishzida, Forced (I-7/I-8)', + pops = { { + id = 3262, --Jaculus Wing + type = 'item', + dropped_from = { name = 'Jaculus, Timed (I-8)' } + }, { + id = 3261, --Minaruja Skull + type = 'item', + dropped_from = { + name = 'Minaruja, Forced (I-10)', + pops = { { + id = 3267, --Pursuer's Wing + type = 'item', + dropped_from = { name = 'Faunus Wyvern (I-9)' } + } } + } + }, { + id = 3268, --High-Quality Wivre Hide + type = 'item', + dropped_from = { name = 'Glade Wivre (I-8)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/amphitrite.lua b/addons/EmpyPopTracker/nms/amphitrite.lua new file mode 100644 index 0000000000..f9209cc158 --- /dev/null +++ b/addons/EmpyPopTracker/nms/amphitrite.lua @@ -0,0 +1,38 @@ +--[[ +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. +]] + +return { + name = 'Amphitrite', + pops = { { + id = 1532, --Variegated Uragnite Shell + type = 'key item', + dropped_from = { + name = 'Melo Melo, Timed (F-11/G-11)', + } + } } +} diff --git a/addons/EmpyPopTracker/nms/apademak.lua b/addons/EmpyPopTracker/nms/apademak.lua new file mode 100644 index 0000000000..924545d3d0 --- /dev/null +++ b/addons/EmpyPopTracker/nms/apademak.lua @@ -0,0 +1,59 @@ +--[[ +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. +]] + +return { + name = 'Apademak', + collectable = 3289, --Apademak Horn + collectable_target_count = 75, + pops = { { + id = 1525, --Torn Khimaira Wing + type = 'key item', + dropped_from = { + name = 'Dhorme Khimaira, Forced (F-7)', + pops = { { + id = 3246, --Snow God Core + type = 'item', + dropped_from = { + name = 'Upas-Kamuy, Forced (G-5)', + pops = { { + id = 3252, --Gelid Arm + dropped_from = { name = 'Snowflake (G-5)' } + } } + } + }, { + id = 3247, --Sisyphus Fragment + type = 'item', + dropped_from = { name = 'Sisyphus, Timed (F-6/G-6)' } + }, { + id = 3253, --High-quality marid hide + type = 'item', + dropped_from = { name = 'Olyphant (F-6)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/arch dynamis lord.lua b/addons/EmpyPopTracker/nms/arch dynamis lord.lua new file mode 100644 index 0000000000..3e693c7f70 --- /dev/null +++ b/addons/EmpyPopTracker/nms/arch dynamis lord.lua @@ -0,0 +1,87 @@ +--[[ +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. +]] + +return { + name = 'Arch Dynamis Lord', + pops = { { + id = 3429, --Fiendish Tome (26) + type = 'item', + dropped_from = { + name = 'Dynamis Lord, Forced (E-8)', + pops = { { + id = 3358, --Shrouded Bijou + type = 'item', + dropped_from = { name = 'Various Demon lottery NMs' } + } } + } + }, { + id = 3430, --Fiendish Tome (27) + type = 'item', + dropped_from = { + name = 'Duke Haures, Forced (J-7)', + pops = { { + id = 3400, --Odious Skull + type = 'item', + dropped_from = { name = 'Kindred DRK, RDM & SAM' } + } } + } + }, { + id = 3431, --Fiendish Tome (28) + type = 'item', + dropped_from = { + name = 'Marquis Caim, Forced (J-6)', + pops = { { + id = 3401, --Odious Horn + type = 'item', + dropped_from = { name = 'Kindred BRD, NIN, SMN & WAR' } + } } + } + }, { + id = 3432, --Fiendish Tome (29) + type = 'item', + dropped_from = { + name = 'Baron Avnas, Forced (I-5)', + pops = { { + id = 3402, --Odious Blood + type = 'item', + dropped_from = { name = 'Kindred DRG, MNK, THF & WHM' } + } } + } + }, { + id = 3433, --Fiendish Tome (30) + type = 'item', + dropped_from = { + name = 'Count Haagenti, Forced (F-7)', + pops = { { + id = 3403, --Odious Pen + type = 'item', + dropped_from = { name = 'Kindred BLM, BST, PLD & RNG' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/azdaja.lua b/addons/EmpyPopTracker/nms/azdaja.lua new file mode 100644 index 0000000000..774304f6fb --- /dev/null +++ b/addons/EmpyPopTracker/nms/azdaja.lua @@ -0,0 +1,38 @@ +--[[ +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. +]] + +return { + name = 'Azdaja', + collectable = 3292, --Azdaja's Horn + collectable_target_count = 75, + pops = { { + id = 1531, --Vacant Bugard Eye + type = 'key item', + dropped_from = { name = 'Deelgeed, Timed (F-9/F-10)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/bennu.lua b/addons/EmpyPopTracker/nms/bennu.lua new file mode 100644 index 0000000000..f632bfafa3 --- /dev/null +++ b/addons/EmpyPopTracker/nms/bennu.lua @@ -0,0 +1,38 @@ +--[[ +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. +]] + +return { + name = 'Bennu', + pops = { { + id = 1522, --Resplendent roc quill + type = 'key item', + dropped_from = { + name = 'Ouzelum, Timed (I-8/J-9)', + } + } } +} diff --git a/addons/EmpyPopTracker/nms/briareus.lua b/addons/EmpyPopTracker/nms/briareus.lua new file mode 100644 index 0000000000..a7c8f9be9a --- /dev/null +++ b/addons/EmpyPopTracker/nms/briareus.lua @@ -0,0 +1,67 @@ +--[[ +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. +]] + +return { + name = 'Briareus', + collectable = 2929, --Helm of Briareus + collectable_target_count = 50, + pops = { { + id = 1482, --Dented Gigas Shield + type = 'key item', + dropped_from = { + name = 'Adamastor, Forced (C-4)', + pops = { { + id = 2894, --Trophy Shield + type = 'item', + dropped_from = { name = 'Bathyal Gigas (C-5/D-5)' } + } } + } + }, { + id = 1484, --Severed Gigas Collar + type = 'key item', + dropped_from = { + name = 'Grandgousier, Forced (F-10)', + pops = { { + id = 2896, --Massive Armband + type = 'item', + dropped_from = { name = 'Demersal Gigas (E-9/F-9)' } + } } + } + }, { + id = 1483, --Warped Gigas Armband + type = 'key item', + dropped_from = { + name = 'Pantagruel, Forced (F-7)', + pops = { { + id = 2895, --Oversized Sock + type = 'item', + dropped_from = { name = 'Hadal Gigas (F-6/F-7)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/brulo.lua b/addons/EmpyPopTracker/nms/brulo.lua new file mode 100644 index 0000000000..35317fa460 --- /dev/null +++ b/addons/EmpyPopTracker/nms/brulo.lua @@ -0,0 +1,52 @@ +--[[ +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. +]] + +return { + name = 'Brulo', + collectable = 3294, --Colorless Soul + collectable_target_count = 75, + pops = { { + id = 1652, --Emerald demilune abyssite + type = 'key item', + dropped_from = { + name = 'Koios (Conflux #5)', + pops = { { + id = 1565, --Colorful demilune abyssite + type = 'key item', + dropped_from = { + name = 'Fire/Earth Elemental', + pops = { { + id = 1564, --Clear demilune abyssite + type = 'key item', + dropped_from = { name = 'Any Cruor Prospector' } + } } + } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/bukhis.lua b/addons/EmpyPopTracker/nms/bukhis.lua new file mode 100644 index 0000000000..699b4c1781 --- /dev/null +++ b/addons/EmpyPopTracker/nms/bukhis.lua @@ -0,0 +1,62 @@ +--[[ +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. +]] + +return { + name = 'Bukhis', + collectable = 2966, --Bukhis's Wing + collectable_target_count = 50, + pops = { { + id = 1508, --Ingrown Taurus Nail + type = 'key item', + dropped_from = { + name = 'Khalkotaur, Forced (F-4)', + pops = { { + id = 3098, --Gnarled Taurus Horn + type = 'item', + dropped_from = { name = 'Aestutaur (G-9/G-10)' } + } } + } + }, { + id = 1509, --Ossified Gargouille Hand + type = 'key item', + dropped_from = { + name = 'Quasimodo, Forced (F-4)', + pops = { { + id = 3099, --Gargouille Stone + type = 'item', + dropped_from = { + name = 'Gruesome Gargouille (F-10/G-10)' + } + } } + } + }, { + id = 1510, --Imbrued Vampyr Fang + type = 'key item', + dropped_from = { name = 'Lord Varney, Timed (G-10/H-10)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/carabosse.lua b/addons/EmpyPopTracker/nms/carabosse.lua new file mode 100644 index 0000000000..88bec48e48 --- /dev/null +++ b/addons/EmpyPopTracker/nms/carabosse.lua @@ -0,0 +1,56 @@ +--[[ +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. +]] + +return { + name = 'Carabosse', + collectable = 2930, --Carabosse's Gem + collectable_target_count = 50, + pops = { { + id = 1485, --Pellucid Fly Eye + type = 'key item', + dropped_from = { + name = 'La Theine Liege, Forced (I-7)', + pops = { { + id = 2897, --Transparent Insect Wing + type = 'item', + dropped_from = { name = 'Plateau Glider (H-7)' } + } } + } + }, { + id = 1486, --Shimmering Pixie Pinion + type = 'key item', + dropped_from = { + name = 'Baba Yaga, Forced (H-7)', + pops = { { + id = 2898, --Piceous Scale + type = 'item', + dropped_from = { name = 'Farfadet (H-7)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/chloris.lua b/addons/EmpyPopTracker/nms/chloris.lua new file mode 100644 index 0000000000..ba64fc70a4 --- /dev/null +++ b/addons/EmpyPopTracker/nms/chloris.lua @@ -0,0 +1,115 @@ +--[[ +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. +]] + +return { + name = 'Chloris', + collectable = 2928, --2Lf. Chloris Bud + collectable_target_count = 50, + pops = { { + id = 1470, --Gory Scorpion Claw + type = 'key item', + dropped_from = { + name = 'Hedetet, Forced (F-7)', + pops = { { + id = 2921, --Venomous Scorpion Stinger + type = 'item', + dropped_from = { name = 'Canyon Scorpion (F-7)' } + }, { + id = 2948, --Acidic Humus + type = 'item', + dropped_from = { + name = 'Gancanagh, Forced (H-8)', + pops = { { + id = 2920, --Alkaline Humus + type = 'item', + dropped_from = { name = 'Pachypodium (H-8)' } + } } + } + } } + } + }, { + id = 1469, --Torn Bat Wing + type = 'key item', + dropped_from = { + name = 'Treble Noctules, Forced (I-9)', + pops = { { + id = 2919, --Bloody Fang + type = 'item', + dropped_from = { name = 'Blood Bat (I-9)' } + }, { + id = 2947, --Exorcised Skull + type = 'item', + dropped_from = { + name = 'Cannered Noz, Forced (F-6)', + pops = { { + id = 2918, --Baleful Skull + type = 'item', + dropped_from = { name = 'Caoineag (F-6)' } + } } + } + } } + } + }, { + id = 1468, --Veinous Hecteyes Eyelid + type = 'key item', + dropped_from = { + name = 'Ophanim, Forced (G-9)', + pops = { { + id = 2917, --Bloodshot Hecteye + type = 'item', + dropped_from = { name = 'Beholder (G-9)' } + }, { + id = 2946, --Tarnished Pincer + type = 'item', + dropped_from = { + name = 'Vetehinen, Forced (H-10)', + pops = { { + id = 2916, --High-quality Limule Pincer + type = 'item', + dropped_from = { name = 'Gulch Limule (H-10)' } + } } + } + }, { + id = 2945, --Shriveled Wing + type = 'item', + dropped_from = { + name = 'Halimede, Forced (G-12)', + pops = { { + id = 2915, --High-quality Clionid Wing + type = 'item', + dropped_from = { name = 'Gully Clionid (G-12)' } + } } + } + } } + } + }, { + id = 1471, --Mossy Adamantoise Shell + type = 'key item', + dropped_from = { name = 'Chukwa, Timed (F-5)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/cirein-croin.lua b/addons/EmpyPopTracker/nms/cirein-croin.lua new file mode 100644 index 0000000000..3f664e7de6 --- /dev/null +++ b/addons/EmpyPopTracker/nms/cirein-croin.lua @@ -0,0 +1,49 @@ +--[[ +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. +]] + +return { + name = 'Cirein-croin', + collectable = 2965, --Cirein. Lantern + collectable_target_count = 50, + pops = { { + id = 1504, --Glistening Orobon Liver + type = 'key item', + dropped_from = { + name = 'Cep-Kamuy, Forced (F-4)', + pops = { { + id = 3089, --Orobon Cheekmeat + type = 'item', + dropped_from = { name = 'Ancient Orobon (F-5)' } + } } + } + }, { + id = 1505, --Doffed Poroggo Hat + type = 'key item', + dropped_from = { name = 'Heqet, Timed (I-6)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/dragua.lua b/addons/EmpyPopTracker/nms/dragua.lua new file mode 100644 index 0000000000..0bb120c1d6 --- /dev/null +++ b/addons/EmpyPopTracker/nms/dragua.lua @@ -0,0 +1,38 @@ +--[[ +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. +]] + +return { + name = 'Dragua', + collectable = 3288, --Dragua's Scale + collectable_target_count = 75, + pops = { { + id = 1521, --Bloodied Dragon Ear + type = 'key item', + dropped_from = { name = 'Hazhdiha, Timed (H-10)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/glavoid.lua b/addons/EmpyPopTracker/nms/glavoid.lua new file mode 100644 index 0000000000..cb604bda3f --- /dev/null +++ b/addons/EmpyPopTracker/nms/glavoid.lua @@ -0,0 +1,84 @@ +--[[ +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. +]] + +return { + name = 'Glavoid', + collectable = 2927, --Glavoid Shell + collectable_target_count = 50, + pops = { { + id = 1473, --Sodden Sandworm Husk + type = 'key item', + dropped_from = { name = 'Minhocao, Timed (I-6)' } + }, { + id = 1475, --Sticky Gnat Wing + type = 'key item', + dropped_from = { name = 'Adze, Timed (G-5)' } + }, { + id = 1472, --Fat-lined Cockatrice Skin + type = 'key item', + dropped_from = { + name = 'Alectryon (H-8)', + pops = { { + id = 2923, --Cockatrice Tailmeat + type = 'item', + dropped_from = { name = 'Cluckatrice (H-8)' } + }, { + id = 2949, --Quivering Eft Egg + type = 'item', + dropped_from = { + name = 'Abas, Forced (K-10)', + pops = { { + id = 2922, --Eft Egg + dropped_from = { name = 'Canyon Eft (J-10/J-11)' } + } } + } + } } + } + }, { + id = 1474, --Luxuriant manticore mane + type = 'key item', + dropped_from = { + name = 'Muscaliet, Forced (J-6)', + pops = { { + id = 2925, --Resilient Mane + type = 'item', + dropped_from = { name = 'Hieracosphinx (J-6)' } + }, { + id = 2950, --Smooth Whisker + type = 'item', + dropped_from = { + name = 'Tefenet, Forced (G-6)', + pops = { { + id = 2924, --Shocking Whisker + dropped_from = { name = 'Jaguarundi (G-6)' } + } } + } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/index.lua b/addons/EmpyPopTracker/nms/index.lua new file mode 100644 index 0000000000..fd21e34556 --- /dev/null +++ b/addons/EmpyPopTracker/nms/index.lua @@ -0,0 +1,65 @@ +--[[ +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. +]] + +local nms = { + 'alfard', + 'amphitrite', + 'apademak', + 'arch dynamis lord', + 'azdaja', + 'bennu', + 'briareus', + 'brulo', + 'bukhis', + 'carabosse', + 'chloris', + 'cirein-croin', + 'dragua', + 'glavoid', + 'ironclad smiter', + 'ironclad sunderer', + 'ironclad triturator', + 'isgebind', + 'itzpapalotl', + 'kukulkan', + 'maere', + 'ogopogo', + 'orthrus', + 'resheph', + 'sedna', + 'sobek', + 'ulhuadshi', + 'warder of courage' +} + +nm_data = {} +for _, nm in pairs(nms) do + nm_data[nm] = require('nms/' .. nm) +end + +return nm_data diff --git a/addons/EmpyPopTracker/nms/ironclad smiter.lua b/addons/EmpyPopTracker/nms/ironclad smiter.lua new file mode 100644 index 0000000000..ef04bcda07 --- /dev/null +++ b/addons/EmpyPopTracker/nms/ironclad smiter.lua @@ -0,0 +1,49 @@ +--[[ +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. +]] + +return { + name = 'Ironclad Smiter', + collectable = 3293, --Iron Plate + collectable_target_count = 50, + pops = { { + id = 3230, --Tablilla Mercury + type = 'item', + dropped_from = { + name = 'Tablilla, Forced (C-11)', + pops = { { + id = 3235, --Sandy Shard + type = 'item', + dropped_from = { name = 'Sand Sweeper, (D-10)' } + } } + } + }, { + id = 3236, --Smoldering Arm + type = 'item', + dropped_from = { name = 'Bonfire, (D-11/E-11)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/ironclad sunderer.lua b/addons/EmpyPopTracker/nms/ironclad sunderer.lua new file mode 100644 index 0000000000..17382875d3 --- /dev/null +++ b/addons/EmpyPopTracker/nms/ironclad sunderer.lua @@ -0,0 +1,49 @@ +--[[ +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. +]] + +return { + name = 'Ironclad Sunderer', + collectable = 3293, --Iron Plate + collectable_target_count = 50, + pops = { { + id = 3260, --Teekesselchen Fragment + type = 'item', + dropped_from = { + name = 'Teekesselchen, Forced (I-5)', + pops = { { + id = 3265, --Bubbling Oil + type = 'item', + dropped_from = { name = 'Sinister Seidel, (J-5)' } + } } + } + }, { + id = 3266, --Darkflame Arm + type = 'item', + dropped_from = { name = 'Stygian Djinn, (K-7)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/ironclad triturator.lua b/addons/EmpyPopTracker/nms/ironclad triturator.lua new file mode 100644 index 0000000000..225ff88fff --- /dev/null +++ b/addons/EmpyPopTracker/nms/ironclad triturator.lua @@ -0,0 +1,49 @@ +--[[ +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. +]] + +return { + name = 'Ironclad Triturator', + collectable = 3293, --Iron Plate + collectable_target_count = 50, + pops = { { + id = 3245, --Bevel Gear + type = 'item', + dropped_from = { + name = 'Koghatu, Forced (G-8)', + pops = { { + id = 3250, --Helical Gear + type = 'item', + dropped_from = { name = 'Mechanical Menace, (G-8/H-8)' } + } } + } + }, { + id = 3251, --Gear Fluid + type = 'item', + dropped_from = { name = 'Sub-zero Gear, (F-8/F-9)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/isgebind.lua b/addons/EmpyPopTracker/nms/isgebind.lua new file mode 100644 index 0000000000..76f5aa7eee --- /dev/null +++ b/addons/EmpyPopTracker/nms/isgebind.lua @@ -0,0 +1,38 @@ +--[[ +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. +]] + +return { + name = 'Isgebind', + collectable = 3290, --Isgebind's Heart + collectable_target_count = 75, + pops = { { + id = 1526, --Begrimed Dragon Hide + type = 'key item', + dropped_from = { name = 'Kur, Timed (I-5/J-5)' } + } } +} diff --git a/addons/EmpyPopTracker/nms/itzpapalotl.lua b/addons/EmpyPopTracker/nms/itzpapalotl.lua new file mode 100644 index 0000000000..47d078a140 --- /dev/null +++ b/addons/EmpyPopTracker/nms/itzpapalotl.lua @@ -0,0 +1,60 @@ +--[[ +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. +]] + +return { + name = 'Itzpapalotl', + collectable = 2962, --Itzpapa. Scale + collectable_target_count = 50, + pops = { { + id = 1488, --Venomous Wamoura Feeler + type = 'key item', + dropped_from = { + name = 'Granite Borer, Forced (K-10)', + pops = { { + id = 3072, --Withered Cocoon + type = 'item', + dropped_from = { name = 'Gullycampa (K-10)' } + } } + } + }, { + id = 1490, --Distended Chigoe Abdomen + type = 'key item', + dropped_from = { name = 'Tunga, Timed (K-10)' } + }, { + id = 1489, --Bulbous crawler cocoon + type = 'key item', + dropped_from = { + name = 'Blazing Eruca, Forced (J-10)', + pops = { { + id = 3073, --Eruca Egg + type = 'item', + dropped_from = { name = 'Ignis Eruca (J-10)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/kukulkan.lua b/addons/EmpyPopTracker/nms/kukulkan.lua new file mode 100644 index 0000000000..4b1e896aed --- /dev/null +++ b/addons/EmpyPopTracker/nms/kukulkan.lua @@ -0,0 +1,67 @@ +--[[ +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. +]] + +return { + name = 'Kukulkan', + collectable = 2932, --Kukulkan's Fang + collectable_target_count = 50, + pops = { { + id = 1466, --Mucid Ahriman Eyeball + type = 'key item', + dropped_from = { + name = 'Arimaspi, Forced (K-6)', + pops = { { + id = 2913, --Clouded Lens + type = 'item', + dropped_from = { name = 'Deep Eye (K-6/K-7)' } + } } + } + }, { + id = 1464, --Tattered Hippogryph Wing + type = 'key item', + dropped_from = { + name = 'Alkonost, Forced (H-6)', + pops = { { + id = 2912, --Giant Bugard Tusk + type = 'item', + dropped_from = { name = 'Ypotryll (I-7)' } + } } + } + }, { + id = 1465, --Cracked Wivre Horn + type = 'key item', + dropped_from = { + name = 'Keratyrannos, Forced (G-6)', + pops = { { + id = 2910, --Armored Dragonhorn + type = 'item', + dropped_from = { name = 'Mesa Wivre (G-6)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/maere.lua b/addons/EmpyPopTracker/nms/maere.lua new file mode 100644 index 0000000000..3250818f8b --- /dev/null +++ b/addons/EmpyPopTracker/nms/maere.lua @@ -0,0 +1,52 @@ +--[[ +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. +]] + +return { + name = 'Maere', + collectable = 3294, --Colorless Soul + collectable_target_count = 75, + pops = { { + id = 1654, --Indigo demilune abyssite + type = 'key item', + dropped_from = { + name = 'Gamayun (Conflux #8)', + pops = { { + id = 1565, --Colorful demilune abyssite + type = 'key item', + dropped_from = { + name = 'Air/Dark Elemental', + pops = { { + id = 1564, --Clear demilune abyssite + type = 'key item', + dropped_from = { name = 'Any Cruor Prospector' } + } } + } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/ogopogo.lua b/addons/EmpyPopTracker/nms/ogopogo.lua new file mode 100644 index 0000000000..d4ca13ad94 --- /dev/null +++ b/addons/EmpyPopTracker/nms/ogopogo.lua @@ -0,0 +1,52 @@ +--[[ +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. +]] + +return { + name = 'Ogopogo', + collectable = 3294, --Colorless Soul + collectable_target_count = 75, + pops = { { + id = 1653, --Vermillion demilune abyssite + type = 'key item', + dropped_from = { + name = 'Chione (Conflux #7)', + pops = { { + id = 1565, --Colorful demilune abyssite + type = 'key item', + dropped_from = { + name = 'Ice/Water Elemental', + pops = { { + id = 1564, --Clear demilune abyssite + type = 'key item', + dropped_from = { name = 'Any Cruor Prospector' } + } } + } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/orthrus.lua b/addons/EmpyPopTracker/nms/orthrus.lua new file mode 100644 index 0000000000..59d13a8e13 --- /dev/null +++ b/addons/EmpyPopTracker/nms/orthrus.lua @@ -0,0 +1,59 @@ +--[[ +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. +]] + +return { + name = 'Orthrus', + collectable = 3287, --Orthrus's Claw + collectable_target_count = 75, + pops = { { + id = 1520, --Steaming cerberus tongue + type = 'key item', + dropped_from = { + name = 'Amarok, Forced (E-6)', + pops = { { + id = 3231, --Sharabha Hide + type = 'item', + dropped_from = { + name = 'Sharabha, Forced (G-5)', + pops = { { + id = 3237, + dropped_from = { name = 'Dune Manticore (F-5/F-6)' } + } } + } + }, { + id = 3232, --Tiger King Hide + type = 'item', + dropped_from = { name = 'Ansherekh, Timed (F-8/G-8)' } + }, { + id = 3238, --H.Q. Dhalmel Hide + type = 'item', + dropped_from = { name = 'Camelopardalis (F-7/G-7)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/resheph.lua b/addons/EmpyPopTracker/nms/resheph.lua new file mode 100644 index 0000000000..21080197ca --- /dev/null +++ b/addons/EmpyPopTracker/nms/resheph.lua @@ -0,0 +1,38 @@ +--[[ +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. +]] + +return { + name = 'Resheph', + pops = { { + id = 1527, --Decaying Diremite Fang + type = 'key item', + dropped_from = { + name = 'Awahondo, Timed (K-6/K-7)', + } + } } +} diff --git a/addons/EmpyPopTracker/nms/sedna.lua b/addons/EmpyPopTracker/nms/sedna.lua new file mode 100644 index 0000000000..c00d641d62 --- /dev/null +++ b/addons/EmpyPopTracker/nms/sedna.lua @@ -0,0 +1,49 @@ +--[[ +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. +]] + +return { + name = 'Sedna', + collectable = 2967, --Sedna's Tusk + collectable_target_count = 50, + pops = { { + id = 1512, --Shimmering Pugil Scale + type = 'key item', + dropped_from = { name = 'Hrosshvalur, Timed (J-6)' } + }, { + id = 1511, --Glossy Sea Monk Sucker + type = 'key item', + dropped_from = { + name = 'Iku-Turso, Forced (J-7)', + pops = { { + id = 3100, --Moonbeam Clam + type = 'item', + dropped_from = { name = 'Jasconius (I-7/J-7)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/sobek.lua b/addons/EmpyPopTracker/nms/sobek.lua new file mode 100644 index 0000000000..4aa9a80b11 --- /dev/null +++ b/addons/EmpyPopTracker/nms/sobek.lua @@ -0,0 +1,60 @@ +--[[ +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. +]] + +return { + name = 'Sobek', + collectable = 2964, --Sobek's Skin + collectable_target_count = 50, + pops = { { + id = 1500, --Molted Peiste Skin + type = 'key item', + dropped_from = { name = 'Gukumatz, Timed (J-11)' } + }, { + id = 1498, --Bloodstained Bugard Fang + type = 'key item', + dropped_from = { + name = 'Minax Bugard, Forced (K-10)', + pops = { { + id = 3085, --Bewitching Tusk + type = 'item', + dropped_from = { name = 'Abyssobugard (J-10/K-11)' } + } } + } + }, { + id = 1499, --Gnarled Lizard Nail + type = 'key item', + dropped_from = { + name = 'Sirrush, Forced (I-11)', + pops = { { + id = 3086, --Molt Scraps + type = 'item', + dropped_from = { name = 'Dusk Lizard (J-11)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/ulhuadshi.lua b/addons/EmpyPopTracker/nms/ulhuadshi.lua new file mode 100644 index 0000000000..2245791d3d --- /dev/null +++ b/addons/EmpyPopTracker/nms/ulhuadshi.lua @@ -0,0 +1,49 @@ +--[[ +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. +]] + +return { + name = 'Ulhuadshi', + collectable = 2963, --Ulhuadshi's Fang + collectable_target_count = 50, + pops = { { + id = 1492, --Shriveled Hecteyes Stalk + type = 'key item', + dropped_from = { name = 'Amun, Timed (H-8/I-9)' } + }, { + id = 1491, --Mucid Worm Segment + type = 'key item', + dropped_from = { + name = 'Pallid Percy, Forced (J-7)', + pops = { { + id = 3074, --Blanched Silver + type = 'item', + dropped_from = { name = 'Entozoon (J-7)' } + } } + } + } } +} diff --git a/addons/EmpyPopTracker/nms/warder of courage.lua b/addons/EmpyPopTracker/nms/warder of courage.lua new file mode 100644 index 0000000000..6534c62bb4 --- /dev/null +++ b/addons/EmpyPopTracker/nms/warder of courage.lua @@ -0,0 +1,79 @@ +--[[ +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. +]] + +return { + name = "Warder of Courage", + pops = { { + id = 2986, --Primal Nazar + type = 'key item', + dropped_from = { + name = 'Dremi (NPC)', + pops = { { + id = 2976, --Primary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Temperance (Zdei, portal #1)' } + }, { + id = 2977, --Secondary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Fortitude (Ghrah, portal #3)' } + }, { + id = 2978, --Tertiary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Faith (Euvhi, portal #12)' } + }, { + id = 2979, --Quaternary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Justice (Xzomit, portal #6)' } + }, { + id = 2980, --Quinary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Hope (Phuabo, portal #1)' } + }, { + id = 2981, --Senary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Prudence (Hpemde, portal #9)' } + }, { + id = 2982, --Septenary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Love (Yovra)' } + }, { + id = 2983, --Octonary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Dignity (Limule, portal #4)' } + }, { + id = 2984, --Nonary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Loyalty (Clionid, portal #13)' } + }, { + id = 2985, --Denary Nazar + type = 'key item', + dropped_from = { name = 'Warder of Mercy (Murex, portal #7)' } + }} + } + } } +} diff --git a/addons/EmpyPopTracker/readme/demo-full.png b/addons/EmpyPopTracker/readme/demo-full.png new file mode 100644 index 0000000000..02df409dab Binary files /dev/null and b/addons/EmpyPopTracker/readme/demo-full.png differ diff --git a/addons/EmpyPopTracker/readme/demo.png b/addons/EmpyPopTracker/readme/demo.png new file mode 100644 index 0000000000..db24c678e8 Binary files /dev/null and b/addons/EmpyPopTracker/readme/demo.png differ diff --git a/addons/FastCS/FastCS.lua b/addons/FastCS/FastCS.lua index 082d82342b..899937255a 100644 --- a/addons/FastCS/FastCS.lua +++ b/addons/FastCS/FastCS.lua @@ -1,6 +1,6 @@ _addon.name = "FastCS" _addon.author = "Cairthenn" -_addon.version = "1.2" +_addon.version = "1.3" _addon.commands = {"FastCS","FCS"} --Requires: @@ -11,7 +11,7 @@ require("luau") defaults = {} defaults.frame_rate_divisor = 2 -defaults.exclusions = S{"home point #1", "home point #2", "home point #3", "home point #4", "home point #5", "survival guide", "waypoint"} +defaults.exclusions = S{"home point #1", "home point #2", "home point #3", "home point #4", "home point #5", "igsli", "urbiolaine", "teldro-kesdrodo", "nunaarl bthtrogg", "survival guide", "waypoint"} settings = config.load(defaults) -- Globals: @@ -73,6 +73,8 @@ windower.register_event('load',function() if player and player.status == 4 then windower.send_command("config FrameRateDivisor 0") + else + disable() end end) diff --git a/addons/GearSwap/README.md b/addons/GearSwap/README.md index ea93e35a18..650af8511d 100644 --- a/addons/GearSwap/README.md +++ b/addons/GearSwap/README.md @@ -1,8 +1,8 @@ Author: Byrth -Version: 0.910 +Version: 0.930 -Date: 12/08/2015 +Date: 06/13/2017 GearSwap @@ -26,7 +26,7 @@ Commands (<> indicates a field. You do not actually have to use <>s): ** APPDATA/Windower/GearSwap/ ** ..Windower/addons/libs/ * gs reload : Reloads the current user file. -* gs export : Exports your currently equipped gear, inventory, or all the items in your current Lua files' sets into GearSwap .lua or spellcast .xml format. Takes options "inventory", "sets", and "xml." Defaults to currently equipped gear and lua otherwise. Also exports appropriate advanced set tables with augments for currently equipped gear and inventory. +* gs export : Exports your currently equipped gear, inventory, or all the items in your current Lua files' sets into GearSwap .lua or spellcast .xml format. Takes options "inventory", "all", "wearable", "sets", and "xml." Defaults to currently equipped gear and lua otherwise. Also exports appropriate advanced set tables with augments for currently equipped gear and inventory. * gs enable : Enables equip commands targeting a specified slot. "All" will allow all equip commands. Providing no slot argument will enable user GearSwap file execution, if it was disabled. * gs disable : Disables equip commands targeting a given slot. "All" will prevent all equip commands. Providing no second argument will disable user GearSwap file execution, although registered events will still run. * gs validate : This command checks to see whether the equipment in the sets table also exists in your inventory (default), or (by passing "inv") whether the equipment in your inventory exists in your sets table. is an optional list of words that restricts the output to only those items that contain text from one of the filter's words. @@ -37,4 +37,4 @@ Settings Files: There is no settings file for GearSwap. Additional Assistance: -The Windower/addons/GearSwap/beta_examples_and_information folder has a file in it named Variables.xlsx that gives more specific information. If that is insufficient, you can go to BlueGartr's FFXI section or FFXIAH and ask for more assistance. \ No newline at end of file +The Windower/addons/GearSwap/beta_examples_and_information folder has a file in it named Variables.xlsx that gives more specific information. If that is insufficient, you can go to BlueGartr's FFXI section or FFXIAH and ask for more assistance. diff --git a/addons/GearSwap/beta_examples_and_information/Variables.xlsx b/addons/GearSwap/beta_examples_and_information/Variables.xlsx index 4fca72acaf..e5846c1208 100644 Binary files a/addons/GearSwap/beta_examples_and_information/Variables.xlsx and b/addons/GearSwap/beta_examples_and_information/Variables.xlsx differ diff --git a/addons/GearSwap/equip_processing.lua b/addons/GearSwap/equip_processing.lua index 39c75beb70..bb6b861559 100644 --- a/addons/GearSwap/equip_processing.lua +++ b/addons/GearSwap/equip_processing.lua @@ -126,7 +126,7 @@ function unpack_equip_list(equip_list,cur_equip) local item_tab = items[to_windower_bag_api(res.bags[cur_equip[slot_name].bag_id].en)][cur_equip[slot_name].slot] if name_match(item_tab.id,name) and (not augments or (#augments ~= 0 and extdata.compare_augments(augments,extdata.decode(item_tab).augments))) and - (not bag or bag == cur_equip[slot_name].bag_id) then + (not designated_bag or designated_bag == cur_equip[slot_name].bag_id) then equip_list[slot_name] = nil used_list[slot_id] = {bag_id=cur_equip[slot_name].bag_id,slot=cur_equip[slot_name].slot} end @@ -154,7 +154,7 @@ function unpack_equip_list(equip_list,cur_equip) local name,priority,augments,designated_bag = expand_entry(equip_list[slot_name]) if (not designated_bag or designated_bag == bag.id) and name and name_match(item_tab.id,name) then - if augments and #augments ~=0 then + if augments and #augments ~= 0 then if res.items[item_tab.id].flags.Rare or extdata.compare_augments(augments,extdata.decode(item_tab).augments) then -- Check if the augments are right -- If the item is Rare, then even if the augments are wrong try to equip it anyway because you only have one diff --git a/addons/GearSwap/export.lua b/addons/GearSwap/export.lua index faccde247d..454bab4c77 100644 --- a/addons/GearSwap/export.lua +++ b/addons/GearSwap/export.lua @@ -26,13 +26,15 @@ function export_set(options) local item_list = T{} - local targinv,all_items,xml,all_sets,use_job_in_filename,use_subjob_in_filename,overwrite_existing + local targinv,all_items,xml,all_sets,use_job_in_filename,use_subjob_in_filename,overwrite_existing,named_file if #options > 0 then for _,v in ipairs(options) do if S{'inventory','inv','i'}:contains(v:lower()) then targinv = true elseif v:lower() == 'all' then all_items = true + elseif v:lower() == 'wearable' then + wearable = true elseif S{'xml'}:contains(v:lower()) then xml = true elseif S{'sets','set','s'}:contains(v:lower()) then @@ -47,13 +49,21 @@ function export_set(options) use_subjob_in_filename = true elseif v:lower() == 'overwrite' then overwrite_existing = true + elseif S{'filename','file','f'}:contains(v:lower()) then + named_file = true + else + if named_file then + filename = v + end end end end local buildmsg = 'Exporting ' if all_items then - buildmsg = buildmsg..'your all items' + buildmsg = buildmsg..'all your items' + elseif wearable then + buildmsg = buildmsg..'all your items in inventory and wardrobes' elseif targinv then buildmsg = buildmsg..'your current inventory' elseif all_sets then @@ -61,6 +71,7 @@ function export_set(options) else buildmsg = buildmsg..'your currently equipped gear' end + if xml then buildmsg = buildmsg..' as an xml file.' else @@ -71,6 +82,8 @@ function export_set(options) buildmsg = buildmsg..' (Naming format: Character_JOB)' elseif use_subjob_in_filename then buildmsg = buildmsg..' (Naming format: Character_JOB_SUB)' + elseif named_file then + buildmsg = buildmsg..' (Named: Character_'..filename..')' end if overwrite_existing then @@ -87,6 +100,10 @@ function export_set(options) for i = 0, #res.bags do item_list:extend(get_item_list(items[res.bags[i].english:gsub(' ', ''):lower()])) end + elseif wearable then + for _, v in pairs(equippable_item_bags) do + item_list:extend(get_item_list(items[v.english:gsub(' ', ''):lower()])) + end elseif targinv then item_list:extend(get_item_list(items.inventory)) elseif all_sets then @@ -158,6 +175,8 @@ function export_set(options) path = path..'_'..windower.ffxi.get_player().main_job elseif use_subjob_in_filename then path = path..'_'..windower.ffxi.get_player().main_job..'_'..windower.ffxi.get_player().sub_job + elseif named_file then + path = path..'_'..filename else path = path..os.date(' %Y-%m-%d %H-%M-%S') end diff --git a/addons/GearSwap/flow.lua b/addons/GearSwap/flow.lua index 033e16adf9..dcc3459b33 100644 --- a/addons/GearSwap/flow.lua +++ b/addons/GearSwap/flow.lua @@ -47,16 +47,16 @@ function equip_sets(swap_type,ts,...) local val2 = var_inps[2] table.reassign(_global,command_registry[ts] or {pretarget_cast_delay = 0,precast_cast_delay=0,cancel_spell = false, new_target=false,target_arrow={x=0,y=0,z=0}}) _global.current_event = tostring(swap_type) - + if _global.current_event == 'precast' and val1 and val1.english and val1.english:find('Geo-') then _global.target_arrow = initialize_arrow_offset(val1.target) end - + windower.debug(tostring(swap_type)..' enter') if showphase or debugging.general then msg.debugging(8,windower.to_shift_jis(tostring(swap_type))..' enter') end - + local cur_equip = table.reassign({},update_equipment()) - + table.reassign(equip_list,{}) table.reassign(player.equipment,to_names_set(cur_equip)) for i,v in pairs(slot_map) do @@ -64,7 +64,7 @@ function equip_sets(swap_type,ts,...) player.equipment[i] = player.equipment[toslotname(v)] end end - + logit('\n\n'..tostring(os.clock)..'(15) equip_sets: '..tostring(swap_type)) if val1 then if type(val1) == 'table' and val1.english then @@ -83,20 +83,20 @@ function equip_sets(swap_type,ts,...) else logit(' : nil-or-false') end - + if type(swap_type) == 'string' then msg.debugging("Entering "..swap_type) else msg.debugging("Entering User Event "..tostring(swap_type)) end - + if not val1 then val1 = {} if debugging.general then msg.debugging(8,'val1 error') end end - + if type(swap_type) == 'function' then results = { pcall(swap_type,...) } if not table.remove(results,1) then error('\nUser Event Error: '..results[1]) end @@ -105,48 +105,15 @@ function equip_sets(swap_type,ts,...) else user_pcall(swap_type,...) end - ---[[ local c - if type(swap_type) == 'function' then - c = coroutine.create(swap_type) - elseif swap_type == 'equip_command' then - equip(val1) - elseif type(swap_type) == 'string' and user_env[swap_type] and type(user_env[swap_type]) == 'function' then - c = coroutine.create(user_env[swap_type]) - elseif type(swap_type) == 'string' and user_env[swap_type] then - msg.addon_msg(123,windower.to_shift_jis(tostring(str))..'() exists but is not a function') - end - - if c then - while coroutine.status(c) == 'suspended' do - local err, typ, val = coroutine.resume(c,unpack(var_inputs)) - if not err then - error('\nGearSwap has detected an error in the user function '..tostring(swap_type)..':\n'..typ) - elseif typ then - if typ == 'sleep' and type(val) == 'number' and val >= 0 then - -- coroutine slept - err, typ, val = coroutine.schedule(c,val) - else - -- Someone yielded or slept with a nonsensical argument. - err, typ, val = coroutine.resume(c) - end - else - -- coroutine finished - end - end - end]] - - + if type(swap_type) == 'string' and (swap_type == 'pretarget' or swap_type == 'filtered_action') then -- Target may just have been changed, so make the ind now. ts = command_registry:new_entry(val1) --- elseif type(swap_type) == 'string' and swap_type == 'precast' and not command_registry[ts] and debugging.command_registry then --- print_set(spell,'precast nil error') -- spell's scope changed to local end - + if player.race ~= 'Precomposed NPC' then - -- Short circuits the routine and gets out before equip processing + -- Short circuits the routine and gets out before equip processing -- if there's no swapping to be done because the user is a monster. - + for v,i in pairs(default_slot_map) do if equip_list[i] and encumbrance_table[v] then not_sent_out_equip[i] = equip_list[i] @@ -154,19 +121,19 @@ function equip_sets(swap_type,ts,...) msg.debugging(i..' slot was not equipped because you are encumbered.') end end - + table.update(equip_list_history,equip_list) - + -- Attempts to identify the player-specified item in inventory -- Starts with (i=slot name, v=item name) -- Ends with (i=slot id and v={bag_id=bag_id, slot=inventory slot}). local equip_next,priorities = unpack_equip_list(equip_list,cur_equip) - + if (_settings.show_swaps and table.length(equip_next) > 0) or _settings.demo_mode then --and table.length(equip_next)>0 then local tempset = to_names_set(equip_next) print_set(tempset,tostring(swap_type)) end - + if (buffactive.charm or player.charmed) or (player.status == 2 or player.status == 3) then -- dead or engaged dead statuses local failure_reason if (buffactive.charm or player.charmed) then @@ -184,6 +151,11 @@ function equip_sets(swap_type,ts,...) chunk_table:append(minichunk) end end + + if swap_type == 'midcast' and command_registry[ts] and command_registry[ts].proposed_packet and not _settings.demo_mode then + windower.packets.inject_outgoing(command_registry[ts].proposed_packet:byte(1),command_registry[ts].proposed_packet) + end + if chunk_table.n >= 3 then local big_chunk = string.char(0x51,0x24,0,0,chunk_table.n,0,0,0) for i=1,chunk_table.n do @@ -198,14 +170,18 @@ function equip_sets(swap_type,ts,...) end end end + else + if swap_type == 'midcast' and command_registry[ts] and command_registry[ts].proposed_packet and not _settings.demo_mode then + windower.packets.inject_outgoing(command_registry[ts].proposed_packet:byte(1),command_registry[ts].proposed_packet) + end end - + windower.debug(tostring(swap_type)..' exit') - + if type(swap_type) == 'function' then return unpack(results) end - + return equip_sets_exit(swap_type,ts,val1) end @@ -227,7 +203,7 @@ function equip_sets_exit(swap_type,ts,val1) end if type(swap_type) == 'string' then if swap_type == 'pretarget' then - + if command_registry[ts].cancel_spell then msg.debugging("Action canceled ("..storedcommand..' '..val1.target.raw..")") storedcommand = nil @@ -237,22 +213,26 @@ function equip_sets_exit(swap_type,ts,val1) msg.debugging('This case should not be hittable - 1') return true end - + if command_registry[ts].new_target then val1.target = command_registry[ts].new_target -- Switch target, if it is requested. end - + -- Compose a proposed packet for the given action (this should be possible after pretarget) command_registry[ts].spell = val1 if val1.target and val1.target.id and val1.target.index and val1.prefix and unify_prefix[val1.prefix] then if val1.prefix == '/item' then -- Item use packet handling here - if find_usable_item(val1.id,true) then --val1.target.id == player.id then - --0x37 packet + if bit.band(val1.target.spawn_type, 2) == 2 and find_inventory_item(val1.id) then + -- 0x36 packet + if val1.target.distance <= 6 then + command_registry[ts].proposed_packet = assemble_menu_item_packet(val1.target.id,val1.target.index,val1.id) + else + windower.add_to_chat(67, "Target out of range.") + end + elseif find_usable_item(val1.id) then + -- 0x37 packet command_registry[ts].proposed_packet = assemble_use_item_packet(val1.target.id,val1.target.index,val1.id) - else - --0x36 packet - command_registry[ts].proposed_packet = assemble_menu_item_packet(val1.target.id,val1.target.index,val1.id) end if not command_registry[ts].proposed_packet then command_registry:delete_entry(ts) @@ -262,7 +242,7 @@ function equip_sets_exit(swap_type,ts,val1) command_registry[ts].proposed_packet = assemble_action_packet(val1.target.id,val1.target.index,outgoing_action_category_table[unify_prefix[val1.prefix]],val1.id,command_registry[ts].target_arrow) if not command_registry[ts].proposed_packet then command_registry:delete_entry(ts) - + msg.debugging("Unable to create a packet for this command because the target is still invalid after pretarget ("..storedcommand..' '..val1.target.raw..")") storedcommand = nil return storedcommand..' '..val1.target.raw @@ -272,7 +252,7 @@ function equip_sets_exit(swap_type,ts,val1) msg.debugging(8,"Hark, what weird prefix through yonder window breaks? "..tostring(val1.prefix)) end end - + if ts and command_registry[ts] and val1.target then if st_targs[val1.target.raw] then -- st targets @@ -424,9 +404,6 @@ end ---- none ----------------------------------------------------------------------------------- function send_action(ts) - if command_registry[ts].proposed_packet then - if not _settings.demo_mode then windower.packets.inject_outgoing(command_registry[ts].proposed_packet:byte(1),command_registry[ts].proposed_packet) end - command_registry[ts].midaction = true - equip_sets('midcast',ts,command_registry[ts].spell) - end -end \ No newline at end of file + command_registry[ts].midaction = true + equip_sets('midcast',ts,command_registry[ts].spell) +end diff --git a/addons/GearSwap/gearswap.lua b/addons/GearSwap/gearswap.lua index a26e05b5fe..4d23192210 100644 --- a/addons/GearSwap/gearswap.lua +++ b/addons/GearSwap/gearswap.lua @@ -25,7 +25,7 @@ --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'GearSwap' -_addon.version = '0.929' +_addon.version = '0.937' _addon.author = 'Byrth' _addon.commands = {'gs','gearswap'} @@ -48,6 +48,7 @@ require 'logger' error = _raw.error require 'lists' +require 'queues' require 'sets' @@ -113,7 +114,7 @@ require 'actions' packets = require 'packets' -- Resources Checks -if res.items and res.bags and res.slots and res.statuses and res.jobs and res.elements and res.skills and res.buffs and res.spells and res.job_abilities and res.weapon_skills and res.monster_abilities and res.action_messages and res.skills and res.monstrosity and res.weather and res.moon_phases and res.races then +if res.items and res.bags and res.slots and res.statuses and res.jobs and res.elements and res.skills and res.buffs and res.spells and res.job_abilities and res.weapon_skills and res.monster_skills and res.action_messages and res.skills and res.monstrosity and res.weather and res.moon_phases and res.races and res.monster_abilities then else error('Missing resources!') end @@ -130,12 +131,11 @@ require 'flow' require 'triggers' initialize_packet_parsing() -gearswap_disabled = false windower.register_event('load',function() windower.debug('load') refresh_globals() - + if world.logged_in then refresh_user_env() if debugging.general then windower.send_command('@unload spellcast;') end @@ -153,11 +153,11 @@ windower.register_event('addon command',function (...) logit('\n\n'..tostring(os.clock)..table.concat({...},' ')) local splitup = {...} if not splitup[1] then return end -- handles //gs - + for i,v in pairs(splitup) do splitup[i] = windower.from_shift_jis(windower.convert_auto_trans(v)) end local cmd = table.remove(splitup,1):lower() - + if cmd == 'c' then if gearswap_disabled then return end if splitup[1] then @@ -279,21 +279,21 @@ end function incoming_chunk(id,data,modified,injected,blocked) windower.debug('incoming chunk '..id) - + if next_packet_events and next_packet_events.sequence_id ~= data:unpack('H',3) then if not next_packet_events.globals_update or next_packet_events.globals_update ~= data:unpack('H',3) then refresh_globals() next_packet_events.globals_update = data:unpack('H',3) end - if next_packet_events.pet_status_change then + if next_packet_events.pet_status_change and not gearswap_disabled then equip_sets('pet_status_change',nil,next_packet_events.pet_status_change.newstatus,next_packet_events.pet_status_change.oldstatus) next_packet_events.pet_status_change = nil end if next_packet_events.pet_change then - if next_packet_events.pet_change.pet then -- Losing a pet + if next_packet_events.pet_change.pet and not gearswap_disabled then -- Losing a pet equip_sets('pet_change',nil,next_packet_events.pet_change.pet,false) next_packet_events.pet_change = nil - elseif pet.isvalid then -- Gaining a pet + elseif pet.isvalid and not gearswap_disabled then -- Gaining a pet equip_sets('pet_change',nil,pet,true) next_packet_events.pet_change = nil end @@ -302,7 +302,7 @@ function incoming_chunk(id,data,modified,injected,blocked) next_packet_events = nil end end - + if not injected and parse.i[id] then parse.i[id](data,blocked) end @@ -310,7 +310,7 @@ end function outgoing_chunk(id,original,data,injected,blocked) windower.debug('outgoing chunk '..id) - + if not blocked and parse.o[id] then parse.o[id](data,injected) end @@ -322,7 +322,7 @@ windower.register_event('outgoing chunk',outgoing_chunk) windower.register_event('status change',function(new,old) windower.debug('status change '..new) if gearswap_disabled or T{2,3,4}:contains(old) or T{2,3,4}:contains(new) then return end - + refresh_globals() equip_sets('status_change',nil,res.statuses[new].english,res.statuses[old].english) end) @@ -331,4 +331,4 @@ windower.register_event('login',function(name) windower.debug('login '..name) initialize_globals() windower.send_command('@wait 2;lua i gearswap refresh_user_env;') -end) \ No newline at end of file +end) diff --git a/addons/GearSwap/helper_functions.lua b/addons/GearSwap/helper_functions.lua index 6eadf7ad52..9732048843 100644 --- a/addons/GearSwap/helper_functions.lua +++ b/addons/GearSwap/helper_functions.lua @@ -42,6 +42,7 @@ function string.lower(message) end end + ----------------------------------------------------------------------------------- --Name: string.upper() --Args: @@ -100,10 +101,7 @@ end ---- Filtered key ----------------------------------------------------------------------------------- function user_key_filter(val) - if type(val) == 'string' then - val = string.lower(val) - end - return val + return type(val) == 'string' and string.lower(val) or val end @@ -150,7 +148,7 @@ end function is_slot_key(k) return slot_map[k] end - + ----------------------------------------------------------------------------------- ----Name: make_empty_item_table(slot) @@ -275,7 +273,7 @@ function update_job_names() player.job = player.main_job..'/'..player.sub_job end - + ----------------------------------------------------------------------------------- ----Name: get_default_slot(k) -- Given a generally known slot key, return the default version of that key. @@ -327,7 +325,7 @@ function set_merge(respect_disable, baseSet, ...) end end end - + return baseSet end @@ -351,7 +349,7 @@ function parse_set_to_keys(str) if type(str) == 'table' then str = table.concat(str, ' ') end - + -- Parsing results get pushed into the result list. local result = L{} @@ -360,9 +358,9 @@ function parse_set_to_keys(str) local stop local sep = '.' local count = 0 - + -- Loop as long as remainder hasn't been nil'd or reduced to 0 characters, but only to a maximum of 30 tries. - while remainder and #remainder and count < 30 do + while remainder ~= "" and count < 30 do -- Try aaa.bbb set names first while sep == '.' do _,_,key,sep,remainder = remainder:find("^([^%.%[]*)(%.?%[?)(.*)") @@ -371,7 +369,7 @@ function parse_set_to_keys(str) -- "remainder" is everything after that result:append(key) end - + -- Then try aaa['bbb'] set names. -- Be sure to account for both single and double quote enclosures. -- Ignore periods contained within quote strings. @@ -383,7 +381,8 @@ function parse_set_to_keys(str) _,_,key,stop,sep,remainder = remainder:find("^([^']+)('])(%.?%[?)(.*)") elseif sep == '"' then _,_,key,stop,sep,remainder = remainder:find('^([^"]+)("])(%.?%[?)(.*)') - elseif not sep or #sep == 0 then + end + if not sep or #sep == 0 then -- If there is no single or double quote detected, attempt to treat the index as a number or boolean local _,_,pot_key,pot_stop,pot_sep,pot_remainder = remainder:find('^([^%]]+)(])(%.?%[?)(.*)') if tonumber(pot_key) then @@ -392,17 +391,20 @@ function parse_set_to_keys(str) key,stop,sep,remainder = true,pot_stop,pot_sep,pot_remainder elseif pot_key == 'false' then key,stop,sep,remainder = false,pot_stop,pot_sep,pot_remainder + elseif pot_key and pot_key ~= "" then + key,stop,sep,remainder = pot_key,pot_stop,pot_sep,pot_remainder end end result:append(key) end - + count = count +1 end return result end + ----------------------------------------------------------------------------------- ----Name: get_set_from_keys(keys) -- Function to take a list of keys select the set they point to, if possible. @@ -430,7 +432,6 @@ function get_set_from_keys(keys) end - ----------------------------------------------------------------------------------- --Name: initialize_arrow_offset(mob_table) --Desc: Returns the current target arrow offset. @@ -443,11 +444,11 @@ end function initialize_arrow_offset(mob_table) local backtab = {} local arrow = windower.ffxi.get_info().target_arrow - + if arrow.x == 0 and arrow.y == 0 and arrow.z == 0 then return arrow end - + backtab.x = arrow.x-mob_table.x backtab.y = arrow.y-mob_table.y backtab.z = arrow.z-mob_table.z @@ -455,7 +456,6 @@ function initialize_arrow_offset(mob_table) end - ----------------------------------------------------------------------------------- --Name: assemble_action_packet(target_id,target_index,category,spell_id) --Desc: Puts together an "action" packet (0x1A) @@ -473,11 +473,11 @@ function assemble_action_packet(target_id,target_index,category,spell_id,arrow_o outstr = outstr..string.char( (target_id%256), math.floor(target_id/256)%256, math.floor( (target_id/65536)%256) , math.floor( (target_id/16777216)%256) ) outstr = outstr..string.char( (target_index%256), math.floor(target_index/256)%256) outstr = outstr..string.char( (category%256), math.floor(category/256)%256) - + if category == 16 then spell_id = 0 end - + outstr = outstr..string.char( (spell_id%256), math.floor(spell_id/256)%256)..string.char(0,0) .. 'fff':pack(arrow_offset.x,arrow_offset.z,arrow_offset.y) return outstr end @@ -499,7 +499,7 @@ function assemble_use_item_packet(target_id,target_index,item_id) outstr = outstr..string.char( (target_id%256), math.floor(target_id/256)%256, math.floor( (target_id/65536)%256) , math.floor( (target_id/16777216)%256) ) outstr = outstr..string.char(0,0,0,0) outstr = outstr..string.char( (target_index%256), math.floor(target_index/256)%256) - inventory_index,bag_id = find_usable_item(item_id,true) + inventory_index,bag_id = find_usable_item(item_id) if inventory_index then outstr = outstr..string.char(inventory_index%256)..string.char(0,bag_id,0,0,0) else @@ -524,7 +524,7 @@ end function assemble_menu_item_packet(target_id,target_index,...) local outstr = string.char(0x36,0x20,0,0) -- Message is coming out too short by 12 characters - + -- Target ID outstr = outstr.."I":pack(target_id) local item_ids,counts,count = {...},{},0 @@ -534,7 +534,7 @@ function assemble_menu_item_packet(target_id,target_index,...) count = count + 1 end end - + local unique_items = 0 for i,v in pairs(counts) do outstr = outstr.."I":pack(v) @@ -547,11 +547,11 @@ function assemble_menu_item_packet(target_id,target_index,...) while #outstr < 0x30 do outstr = outstr..string.char(0) end - + -- Inventory Index for the one unit - + for i,v in pairs(counts) do - inventory_index,bag_id = find_usable_item(i,false) + inventory_index = find_inventory_item(i) if inventory_index then outstr = outstr..string.char(inventory_index%256) else @@ -570,22 +570,41 @@ function assemble_menu_item_packet(target_id,target_index,...) end +----------------------------------------------------------------------------------- +--Name: find_inventory_item(item_id) +--Desc: Finds a npc trade item in normal inventory. Assumes items array +-- is accurate already. +--Args: +---- item_id - The resource line for the current item +----------------------------------------------------------------------------------- +--Returns: +---- inventory_index - The item's use inventory index (if it exists) +---- bag_id - The item's bag ID (if it exists) +----------------------------------------------------------------------------------- +function find_inventory_item(item_id) + for i,v in pairs(items.inventory) do + if type(v) == 'table' and v.id == item_id and v.status == 0 then + return i + end + end +end + + ----------------------------------------------------------------------------------- --Name: find_usable_item(item_id,bool) --Desc: Finds a usable item in temporary or normal inventory. Assumes items array -- is accurate already. --Args: ---- item_id - The resource line for the current item ----- bool - Indicates whether the item must show up in your control-I menu as usable ----------------------------------------------------------------------------------- --Returns: ---- inventory_index - The item's use inventory index (if it exists) ---- bag_id - The item's bag ID (if it exists) ----------------------------------------------------------------------------------- -function find_usable_item(item_id,bool) +function find_usable_item(item_id) for _,bag in ipairs(usable_item_bags) do for i,v in pairs(items[to_windower_bag_api(bag.en)]) do - if type(v) == 'table' and v.id == item_id and (v.status == 5 or v.status == 0) and (not bool or is_usable_item(v)) then + if type(v) == 'table' and v.id == item_id and is_usable_item(v,bag.id) then return i, bag.id end end @@ -597,13 +616,18 @@ end --Desc: Determines whether the item table belongs to a usable item. --Args: ---- i_tab - current item table +---- bag_id - The item's bag ID ----------------------------------------------------------------------------------- --Returns: ---- true or false to indicate whether the item is usable ----------------------------------------------------------------------------------- -function is_usable_item(i_tab) +function is_usable_item(i_tab,bag_id) local ext = extdata.decode(i_tab) - if res.items[i_tab.id].type == 7 or (ext.type == 'Enchanted Equipment' and ext.usable) or res.items[i_tab.id].category == 'Usable' then return true end + if ext.type == 'Enchanted Equipment' and ext.usable then + return i_tab.status == 5 + elseif i_tab.status == 0 and bag_id < 4 then + return true + end return false end @@ -626,89 +650,98 @@ end ----------------------------------------------------------------------------------- --Name: filter_pretarget(spell) ---Desc: Determines whether the current player is capable of using the proposed spell +--Desc: Determines whether the current player is capable of using the proposed action ---- at pretarget. --Args: ----- spell - current spell table +---- action - current action ----------------------------------------------------------------------------------- --Returns: ---- false to cancel further command processing and just return the command. ----------------------------------------------------------------------------------- -function filter_pretarget(spell) - local category = outgoing_action_category_table[unify_prefix[spell.prefix]] +function filter_pretarget(action) + local category = outgoing_action_category_table[unify_prefix[action.prefix]] + local bool = true + local err if world.in_mog_house then msg.debugging("Unable to execute commands. Currently in a Mog House zone.") return false elseif category == 3 then local available_spells = windower.ffxi.get_spells() - local spell_jobs = copy_entry(res.spells[spell.id].levels) - - -- Filter for spells that you do not know. Exclude Impact. - if not available_spells[spell.id] and not (spell.id == 503 or spell.id == 417) then - msg.debugging("Unable to execute command. You do not know that spell ("..(res.spells[spell.id][language] or spell.id)..")") - return false - -- Filter for spells that you know, but do not currently have access to - elseif (not spell_jobs[player.main_job_id] or not (spell_jobs[player.main_job_id] <= player.main_job_level or - (spell_jobs[player.main_job_id] >= 100 and number_of_jps(player.job_points[__raw.lower(res.jobs[player.main_job_id].ens)]) >= spell_jobs[player.main_job_id]) ) ) and - (not spell_jobs[player.sub_job_id] or not (spell_jobs[player.sub_job_id] <= player.sub_job_level)) and not (player.main_job_id == 23) then - msg.debugging("Unable to execute command. You do not have access to that spell ("..(res.spells[spell.id][language] or spell.id)..")") - return false - -- At this point, we know that it is technically castable by this job combination if the right conditions are met. - elseif player.main_job_id == 20 and ((addendum_white[spell.id] and not buffactive[401] and not buffactive[416]) or - (addendum_black[spell.id] and not buffactive[402] and not buffactive[416])) and - not (spell_jobs[player.sub_job_id] and spell_jobs[player.sub_job_id] <= player.sub_job_level) then - - if addendum_white[spell.id] then - msg.debugging("Unable to execute command. Addendum: White required for that spell ("..(res.spells[spell.id][language] or spell.id)..")") - end - if addendum_black[spell.id] then - msg.debugging("Unable to execute command. Addendum: Black required for that spell ("..(res.spells[spell.id][language] or spell.id)..")") - end - return false - elseif player.sub_job_id == 20 and ((addendum_white[spell.id] and not buffactive[401] and not buffactive[416]) or - (addendum_black[spell.id] and not buffactive[402] and not buffactive[416])) and - not (spell_jobs[player.main_job_id] and (spell_jobs[player.main_job_id] <= player.main_job_level or - (spell_jobs[player.main_job_id] >= 100 and number_of_jps(player.job_points[__raw.lower(res.jobs[player.main_job_id].ens)]) >= spell_jobs[player.main_job_id]) ) ) then - - if addendum_white[spell.id] then - msg.debugging("Unable to execute command. Addendum: White required for that spell ("..(res.spells[spell.id][language] or spell.id)..")") - end - if addendum_black[spell.id] then - msg.debugging("Unable to execute command. Addendum: Black required for that spell ("..(res.spells[spell.id][language] or spell.id)..")") - end - return false - elseif spell.type == 'BlueMagic' and not ((player.main_job_id == 16 and table.contains(windower.ffxi.get_mjob_data().spells,spell.id)) - or unbridled_learning_set[spell.english]) and - not (player.sub_job_id == 16 and table.contains(windower.ffxi.get_sjob_data().spells,spell.id)) then - -- This code isn't hurting anything, but it doesn't need to be here either. - msg.debugging("Unable to execute command. Blue magic must be set to cast that spell ("..(res.spells[spell.id][language] or spell.id)..")") - return false - elseif spell.type == 'Ninjutsu' then - if player.main_job_id ~= 13 and player.sub_job_id ~= 13 then - msg.debugging("Unable to make action packet. You do not have access to that spell ("..(spell[language] or spell.id)..")") - return false - elseif not player.inventory[tool_map[spell.english][language]] and not (player.main_job_id == 13 and player.inventory[universal_tool_map[spell.english][language]]) then - msg.debugging("Unable to make action packet. You do not have the proper tools.") - return false - end + bool,err = check_spell(available_spells,action) + elseif category == 7 then + local available = windower.ffxi.get_abilities().weapon_skills + if not table.contains(available,action.id) then + bool,err = false,"Unable to execute command. You do not have access to that weapon skill." end - elseif category == 7 or category == 9 then - local available = windower.ffxi.get_abilities() - if category == 7 and not S(available.weapon_skills)[spell.id] then - msg.debugging("Unable to execute command. You do not have access to that ability ("..(res.weapon_skills[spell.id][language] or spell.id)..")") - return false - elseif category == 9 and not S(available.job_abilities)[spell.id] then - msg.debugging("Unable to execute command. You do not have access to that ability ("..(res.job_abilities[spell.id][language] or spell.id)..")") - return false + elseif category == 9 then + local available = windower.ffxi.get_abilities().job_abilities + if not table.contains(available,action.id) then + bool,err = false,"Unable to execute command. You do not have access to that job ability." end elseif category == 25 and (not player.main_job_id == 23 or not windower.ffxi.get_mjob_data().species or - not res.monstrosity[windower.ffxi.get_mjob_data().species] or not res.monstrosity[windower.ffxi.get_mjob_data().species].tp_moves[spell.id] or - not (res.monstrosity[windower.ffxi.get_mjob_data().species].tp_moves[spell.id] <= player.main_job_level)) then + not res.monstrosity[windower.ffxi.get_mjob_data().species] or not res.monstrosity[windower.ffxi.get_mjob_data().species].tp_moves[action.id] or + not (res.monstrosity[windower.ffxi.get_mjob_data().species].tp_moves[action.id] <= player.main_job_level)) then -- Monstrosity filtering - msg.debugging("Unable to execute command. You do not have access to that monsterskill ("..(res.monster_abilities[spell.id][language] or spell.id)..")") + msg.debugging("Unable to execute command. You do not have access to that monsterskill ("..(res.monster_skills[action.id][language] or action.id)..")") return false end - + + if err then + msg.debugging(err) + end + return bool +end + + +----------------------------------------------------------------------------------- +--Name: check_spell(available_spells,spell) +--Desc: Determines whether the current player is capable of using the proposed spell +---- at precast. +--Args: +---- available_spells - current set of available spells +---- spell - current spell table +----------------------------------------------------------------------------------- +--Returns: +---- false if the spell is not currently accessible +----------------------------------------------------------------------------------- +function check_spell(available_spells,spell) + -- Filter for spells that you do not know. + -- Exclude Impact / Dispelga / Honor March if the respective slots are enabled. + -- Need to add logic to check whether the equipment is already on + local spell_jobs = copy_entry(res.spells[spell.id].levels) + if not available_spells[spell.id] and not ( + (not disable_table[5] and not disable_table[4] and spell.id == 503) or -- Body + Head + Impact + (not disable_table[2] and spell.id == 417) or -- Range + Honor March + ((not disable_table[0] or not disable_table[1]) and spell.id == 360) -- Main or Sub + Dispelga + ) then + return false,"Unable to execute command. You do not know that spell ("..(res.spells[spell.id][language] or spell.id)..")" + -- Filter for spells that you know, but do not currently have access to + elseif (not spell_jobs[player.main_job_id] or not (spell_jobs[player.main_job_id] <= player.main_job_level or + (spell_jobs[player.main_job_id] >= 100 and number_of_jps(player.job_points[__raw.lower(res.jobs[player.main_job_id].ens)]) >= spell_jobs[player.main_job_id]) ) ) and + (not spell_jobs[player.sub_job_id] or not (spell_jobs[player.sub_job_id] <= player.sub_job_level)) and not (player.main_job_id == 23) then + return false,"Unable to execute command. You do not have access to that spell ("..(res.spells[spell.id][language] or spell.id)..")" + -- At this point, we know that it is technically castable by this job combination if the right conditions are met. + elseif player.main_job_id == 20 and ((addendum_white[spell.id] and not buffactive[401] and not buffactive[416]) or + (addendum_black[spell.id] and not buffactive[402] and not buffactive[416])) and + not (spell_jobs[player.sub_job_id] and spell_jobs[player.sub_job_id] <= player.sub_job_level) then + return false,"Unable to execute command. Addendum required for that spell ("..(res.spells[spell.id][language] or spell.id)..")" + elseif player.sub_job_id == 20 and ((addendum_white[spell.id] and not buffactive[401] and not buffactive[416]) or + (addendum_black[spell.id] and not buffactive[402] and not buffactive[416])) and + not (spell_jobs[player.main_job_id] and (spell_jobs[player.main_job_id] <= player.main_job_level or + (spell_jobs[player.main_job_id] >= 100 and number_of_jps(player.job_points[__raw.lower(res.jobs[player.main_job_id].ens)]) >= spell_jobs[player.main_job_id]) ) ) then + return false,"Unable to execute command. Addendum required for that spell ("..(res.spells[spell.id][language] or spell.id)..")" + elseif spell.type == 'BlueMagic' and not ((player.main_job_id == 16 and table.contains(windower.ffxi.get_mjob_data().spells,spell.id)) + or unbridled_learning_set[spell.english]) and + not (player.sub_job_id == 16 and table.contains(windower.ffxi.get_sjob_data().spells,spell.id)) then + -- This code isn't hurting anything, but it doesn't need to be here either. + return false,"Unable to execute command. Blue magic must be set to cast that spell ("..(res.spells[spell.id][language] or spell.id)..")" + elseif spell.type == 'Ninjutsu' then + if player.main_job_id ~= 13 and player.sub_job_id ~= 13 then + return false,"Unable to make action packet. You do not have access to that spell ("..(spell[language] or spell.id)..")" + elseif not player.inventory[tool_map[spell.english][language]] and not (player.main_job_id == 13 and player.inventory[universal_tool_map[spell.english][language]]) then + return false,"Unable to make action packet. You do not have the proper tools." + end + end return true end @@ -829,7 +862,7 @@ function cmd_reg:find_by_spell(value) for i,v in pairs(self) do if type(v) == 'table' and v.spell and v.spell.prefix == value.prefix and v.spell.name == value.name then potential_entries[i] = v.timestamp or 0 - elseif type(v) == 'table' and v.spell and v.spell.name == 'Double-Up' and value.type == 'CorsairRoll' then + elseif type(v) == 'table' and v.spell and v.spell.english == 'Double-Up' and value.type == 'CorsairRoll' then -- Double Up ability uses will return action packets that match Corsair Rolls rather than Double Up potential_entries[i] = v.timestamp or 0 end @@ -856,7 +889,7 @@ end function cmd_reg:find_by_time(target_time) local time_stamp,ts target_time = target_time or os.time() - + -- Iterate over command_registry looking for the spell with the closest timestamp. -- Call aftercast with this spell's information (interrupted) if one is found. for i,v in pairs(self) do @@ -924,14 +957,14 @@ end function get_spell(act) local spell, abil_ID, effect_val local msg_ID = act.targets[1].actions[1].message - + if T{7,8,9}:contains(act.category) then abil_ID = act.targets[1].actions[1].param elseif T{3,4,5,6,11,13,14,15}:contains(act.category) then abil_ID = act.param effect_val = act.targets[1].actions[1].param end - + if act.category == 12 or act.category == 2 then spell = copy_entry(resources_ranged_attack) else @@ -948,13 +981,13 @@ function get_spell(act) else spell = {name=tostring(msg_ID)} end - + return spell end - + local fields = fieldsearch(res.action_messages[msg_ID].english) -- ENGLISH - + if table.contains(fields,'spell') then spell = copy_entry(res.spells[abil_ID]) if act.category == 4 then spell.recast = act.recast end @@ -984,7 +1017,7 @@ function get_spell(act) elseif msg_ID == 328 then spell = copy_entry(res.job_abilities[effect_val]) -- BPs that are out of range end - + if table.contains(fields,'item') then if spell then @@ -996,12 +1029,12 @@ function get_spell(act) spell = spell_complete(spell) end end - + if spell then spell.name = spell[language] spell.interrupted = false end - + return spell end @@ -1027,7 +1060,7 @@ function spell_complete(rline) -- Entrust allows Indi- spells to be cast on party members rline.targets.Party = true end - + if rline == nil then return {tpaftercast = player.tp, mpaftercast = player.mp, mppaftercast = player.mpp} end @@ -1037,18 +1070,18 @@ function spell_complete(rline) elseif not rline.tp_cost or rline.tp_cost == -1 then rline.tp_cost = 0 end - + if rline.skill and tonumber(rline.skill) then rline.skill = res.skills[rline.skill][language] end - + if rline.element and tonumber(rline.element) then rline.element = res.elements[rline.element][language] end - + if rline.tp_cost == 0 then rline.tpaftercast = player.tp else rline.tpaftercast = player.tp - rline.tp_cost end - + if rline.mp_cost == 0 then rline.mpaftercast = player.mp rline.mppaftercast = player.mpp @@ -1056,7 +1089,7 @@ function spell_complete(rline) rline.mpaftercast = player.mp - rline.mp_cost rline.mppaftercast = (player.mp - rline.mp_cost)/player.max_mp end - + return rline end diff --git a/addons/GearSwap/libs/Mote-Mappings.lua b/addons/GearSwap/libs/Mote-Mappings.lua index b1920e88d6..d3fc055688 100644 --- a/addons/GearSwap/libs/Mote-Mappings.lua +++ b/addons/GearSwap/libs/Mote-Mappings.lua @@ -17,10 +17,13 @@ elements.weak_to = {['Light']='Dark', ['Dark']='Light', ['Fire']='Ice', ['Ice']= elements.strong_to = {['Light']='Dark', ['Dark']='Light', ['Fire']='Water', ['Ice']='Fire', ['Wind']='Ice', ['Earth']='Wind', ['Lightning']='Earth', ['Water']='Lightning'} +storms = S{"Aurorastorm", "Voidstorm", "Firestorm", "Sandstorm", "Rainstorm", "Windstorm", "Hailstorm", "Thunderstorm", + "Aurorastorm II", "Voidstorm II", "Firestorm II", "Sandstorm II", "Rainstorm II", "Windstorm II", "Hailstorm II", "Thunderstorm II"} -storms = S{"Aurorastorm", "Voidstorm", "Firestorm", "Sandstorm", "Rainstorm", "Windstorm", "Hailstorm", "Thunderstorm"} elements.storm_of = {['Light']="Aurorastorm", ['Dark']="Voidstorm", ['Fire']="Firestorm", ['Earth']="Sandstorm", - ['Water']="Rainstorm", ['Wind']="Windstorm", ['Ice']="Hailstorm", ['Lightning']="Thunderstorm"} + ['Water']="Rainstorm", ['Wind']="Windstorm", ['Ice']="Hailstorm", ['Lightning']="Thunderstorm",['Light']="Aurorastorm II", + ['Dark']="Voidstorm II", ['Fire']="Firestorm II", ['Earth']="Sandstorm II", ['Water']="Rainstorm II", ['Wind']="Windstorm II", + ['Ice']="Hailstorm II", ['Lightning']="Thunderstorm II"} spirits = S{"LightSpirit", "DarkSpirit", "FireSpirit", "EarthSpirit", "WaterSpirit", "AirSpirit", "IceSpirit", "ThunderSpirit"} elements.spirit_of = {['Light']="Light Spirit", ['Dark']="Dark Spirit", ['Fire']="Fire Spirit", ['Earth']="Earth Spirit", @@ -144,6 +147,7 @@ ranged_weaponskills = data.weaponskills.ranged spell_maps = { ['Cure']='Cure',['Cure II']='Cure',['Cure III']='Cure',['Cure IV']='Cure',['Cure V']='Cure',['Cure VI']='Cure', + ['Full Cure']='Cure', ['Cura']='Curaga',['Cura II']='Curaga',['Cura III']='Curaga', ['Curaga']='Curaga',['Curaga II']='Curaga',['Curaga III']='Curaga',['Curaga IV']='Curaga',['Curaga V']='Curaga', -- Status Removal doesn't include Esuna or Sacrifice, since they work differently than the rest @@ -152,13 +156,13 @@ spell_maps = { ['Barfire']='BarElement',['Barstone']='BarElement',['Barwater']='BarElement',['Baraero']='BarElement',['Barblizzard']='BarElement',['Barthunder']='BarElement', ['Barfira']='BarElement',['Barstonra']='BarElement',['Barwatera']='BarElement',['Baraera']='BarElement',['Barblizzara']='BarElement',['Barthundra']='BarElement', ['Raise']='Raise',['Raise II']='Raise',['Raise III']='Raise',['Arise']='Raise', - ['Reraise']='Reraise',['Reraise II']='Reraise',['Reraise III']='Reraise', + ['Reraise']='Reraise',['Reraise II']='Reraise',['Reraise III']='Reraise',['Reraise IV']='Reraise', ['Protect']='Protect',['Protect II']='Protect',['Protect III']='Protect',['Protect IV']='Protect',['Protect V']='Protect', ['Shell']='Shell',['Shell II']='Shell',['Shell III']='Shell',['Shell IV']='Shell',['Shell V']='Shell', ['Protectra']='Protectra',['Protectra II']='Protectra',['Protectra III']='Protectra',['Protectra IV']='Protectra',['Protectra V']='Protectra', ['Shellra']='Shellra',['Shellra II']='Shellra',['Shellra III']='Shellra',['Shellra IV']='Shellra',['Shellra V']='Shellra', ['Regen']='Regen',['Regen II']='Regen',['Regen III']='Regen',['Regen IV']='Regen',['Regen V']='Regen', - ['Refresh']='Refresh',['Refresh II']='Refresh', + ['Refresh']='Refresh',['Refresh II']='Refresh',['Refresh III']='Refresh', ['Teleport-Holla']='Teleport',['Teleport-Dem']='Teleport',['Teleport-Mea']='Teleport',['Teleport-Altep']='Teleport',['Teleport-Yhoat']='Teleport', ['Teleport-Vahzl']='Teleport',['Recall-Pashh']='Teleport',['Recall-Meriph']='Teleport',['Recall-Jugner']='Teleport', ['Valor Minuet']='Minuet',['Valor Minuet II']='Minuet',['Valor Minuet III']='Minuet',['Valor Minuet IV']='Minuet',['Valor Minuet V']='Minuet', @@ -175,10 +179,11 @@ spell_maps = { ['Fire Carol']='Carol',['Ice Carol']='Carol',['Wind Carol']='Carol',['Earth Carol']='Carol',['Lightning Carol']='Carol',['Water Carol']='Carol',['Light Carol']='Carol',['Dark Carol']='Carol', ['Fire Carol II']='Carol',['Ice Carol II']='Carol',['Wind Carol II']='Carol',['Earth Carol II']='Carol',['Lightning Carol II']='Carol',['Water Carol II']='Carol',['Light Carol II']='Carol',['Dark Carol II']='Carol', ['Foe Lullaby']='Lullaby',['Foe Lullaby II']='Lullaby',['Horde Lullaby']='Lullaby',['Horde Lullaby II']='Lullaby', - ['Fire Threnody']='Threnody',['Ice Threnody']='Threnody',['Wind Threnody']='Threnody',['Earth Threnody']='Threnody',['Lightning Threnody']='Threnody',['Water Threnody']='Threnody',['Light Threnody']='Threnody',['Dark Threnody']='Threnody', + ['Fire Threnody']='Threnody',['Ice Threnody']='Threnody',['Wind Threnody']='Threnody',['Earth Threnody']='Threnody',['Ltng. Threnody']='Threnody',['Water Threnody']='Threnody',['Light Threnody']='Threnody',['Dark Threnody']='Threnody', + ['Fire Threnody II']='Threnody',['Ice Threnody II']='Threnody',['Wind Threnody II']='Threnody',['Earth Threnody II']='Threnody',['Ltng. Threnody II']='Threnody',['Water Threnody II']='Threnody',['Light Threnody II']='Threnody',['Dark Threnody II']='Threnody', ['Battlefield Elegy']='Elegy',['Carnage Elegy']='Elegy', ['Foe Requiem']='Requiem',['Foe Requiem II']='Requiem',['Foe Requiem III']='Requiem',['Foe Requiem IV']='Requiem',['Foe Requiem V']='Requiem',['Foe Requiem VI']='Requiem',['Foe Requiem VII']='Requiem', - ['Utsusemi: Ichi']='Utsusemi',['Utsusemi: Ni']='Utsusemi', + ['Utsusemi: Ichi']='Utsusemi',['Utsusemi: Ni']='Utsusemi',['Utsusemi: San']='Utsusemi', ['Katon: Ichi'] = 'ElementalNinjutsu',['Suiton: Ichi'] = 'ElementalNinjutsu',['Raiton: Ichi'] = 'ElementalNinjutsu', ['Doton: Ichi'] = 'ElementalNinjutsu',['Huton: Ichi'] = 'ElementalNinjutsu',['Hyoton: Ichi'] = 'ElementalNinjutsu', ['Katon: Ni'] = 'ElementalNinjutsu',['Suiton: Ni'] = 'ElementalNinjutsu',['Raiton: Ni'] = 'ElementalNinjutsu', @@ -186,12 +191,15 @@ spell_maps = { ['Katon: San'] = 'ElementalNinjutsu',['Suiton: San'] = 'ElementalNinjutsu',['Raiton: San'] = 'ElementalNinjutsu', ['Doton: San'] = 'ElementalNinjutsu',['Huton: San'] = 'ElementalNinjutsu',['Hyoton: San'] = 'ElementalNinjutsu', ['Banish']='Banish',['Banish II']='Banish',['Banish III']='Banish',['Banishga']='Banish',['Banishga II']='Banish', - ['Holy']='Holy',['Holy II']='Holy',['Drain']='Drain',['Drain II']='Drain',['Aspir']='Aspir',['Aspir II']='Aspir', + ['Holy']='Holy',['Holy II']='Holy',['Drain']='Drain',['Drain II']='Drain',['Drain III']='Drain',['Aspir']='Aspir',['Aspir II']='Aspir', ['Absorb-Str']='Absorb',['Absorb-Dex']='Absorb',['Absorb-Vit']='Absorb',['Absorb-Agi']='Absorb',['Absorb-Int']='Absorb',['Absorb-Mnd']='Absorb',['Absorb-Chr']='Absorb', ['Absorb-Acc']='Absorb',['Absorb-TP']='Absorb',['Absorb-Attri']='Absorb', + ['Enlight']='Enlight',['Enlight II']='Enlight',['Endark']='Endark',['Endark II']='Endark', ['Burn']='ElementalEnfeeble',['Frost']='ElementalEnfeeble',['Choke']='ElementalEnfeeble',['Rasp']='ElementalEnfeeble',['Shock']='ElementalEnfeeble',['Drown']='ElementalEnfeeble', ['Pyrohelix']='Helix',['Cryohelix']='Helix',['Anemohelix']='Helix',['Geohelix']='Helix',['Ionohelix']='Helix',['Hydrohelix']='Helix',['Luminohelix']='Helix',['Noctohelix']='Helix', + ['Pyrohelix II']='Helix',['Cryohelix II']='Helix',['Anemohelix II']='Helix',['Geohelix II']='Helix',['Ionohelix II']='Helix',['Hydrohelix II']='Helix',['Luminohelix II']='Helix',['Noctohelix II']='Helix', ['Firestorm']='Storm',['Hailstorm']='Storm',['Windstorm']='Storm',['Sandstorm']='Storm',['Thunderstorm']='Storm',['Rainstorm']='Storm',['Aurorastorm']='Storm',['Voidstorm']='Storm', + ['Firestorm II']='Storm',['Hailstorm II']='Storm',['Windstorm II']='Storm',['Sandstorm II']='Storm',['Thunderstorm II']='Storm',['Rainstorm II']='Storm',['Aurorastorm II']='Storm',['Voidstorm II']='Storm', ['Fire Maneuver']='Maneuver',['Ice Maneuver']='Maneuver',['Wind Maneuver']='Maneuver',['Earth Maneuver']='Maneuver',['Thunder Maneuver']='Maneuver', ['Water Maneuver']='Maneuver',['Light Maneuver']='Maneuver',['Dark Maneuver']='Maneuver', } @@ -226,14 +234,16 @@ areas.Cities = S{ "Bastok Mines", "Metalworks", "Aht Urhgan Whitegate", - "Tavanazian Safehold", + "Tavnazian Safehold", "Nashmau", "Selbina", "Mhaura", "Norg", "Eastern Adoulin", "Western Adoulin", - "Kazham" + "Kazham", + "Rabao", + "Chocobo Circuit", } -- Adoulin areas, where Ionis will grant special stat bonuses. areas.Adoulin = S{ @@ -259,7 +269,7 @@ areas.Adoulin = S{ ------------------------------------------------------------------------------------------------------------------- --- Lists of certain NPCs. +-- Lists of certain NPCs. (Not up to date) ------------------------------------------------------------------------------------------------------------------- npcs = {} diff --git a/addons/GearSwap/libs/Mote-SelfCommands.lua b/addons/GearSwap/libs/Mote-SelfCommands.lua index 3015e1fcc1..d32ff81c4e 100644 --- a/addons/GearSwap/libs/Mote-SelfCommands.lua +++ b/addons/GearSwap/libs/Mote-SelfCommands.lua @@ -53,7 +53,7 @@ function handle_set(cmdParams) if state_var then local oldVal = state_var.value - state_var:set(cmdParams[2]) + state_var:set(T(cmdParams):slice(2):concat(' ')) local newVal = state_var.value local descrip = state_var.description or cmdParams[1] diff --git a/addons/GearSwap/libs/Mote-Utility.lua b/addons/GearSwap/libs/Mote-Utility.lua index 12834d3e6a..0f734f37ef 100644 --- a/addons/GearSwap/libs/Mote-Utility.lua +++ b/addons/GearSwap/libs/Mote-Utility.lua @@ -523,11 +523,11 @@ function set_macro_page(set,book) add_to_chat(123,'Error setting macro page: book is not a valid number ('..tostring(book)..').') return end - if book < 1 or book > 20 then + if book < 1 or book > 40 then add_to_chat(123,'Error setting macro page: Macro book ('..tostring(book)..') must be between 1 and 20.') return end - send_command('@input /macro book '..tostring(book)..';wait .1;input /macro set '..tostring(set)) + send_command('@input /macro book '..tostring(book)..';wait 1.1;input /macro set '..tostring(set)) else send_command('@input /macro set '..tostring(set)) end diff --git a/addons/GearSwap/libs/closetCleaner.lua b/addons/GearSwap/libs/closetCleaner.lua new file mode 100644 index 0000000000..50a35efc2d --- /dev/null +++ b/addons/GearSwap/libs/closetCleaner.lua @@ -0,0 +1,377 @@ +--Copyright © 2016-2017, Brimstone +--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 closetCleaner 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 Brimstone 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.version = '1.0' + +local cc = {} +config = require ('config') +cc.sandbox = {} +cc.sandbox.windower = setmetatable({}, {__index = windower}) +cc.sandbox.windower.coroutine = functions.empty +cc.sandbox.windower.register_event = functions.empty +cc.sandbox.windower.raw_register_event = functions.empty +cc.sandbox.windower.register_unhandled_command = functions.empty + +defaults = T{} +-- Jobs you want to execute with, recomment put all active jobs you have lua for will look for .lua or _.lua files +defaults.ccjobs = { 'BLM', 'BLU', 'BRD', 'BST', 'COR', 'DNC', 'DRG', 'DRK', 'GEO', 'MNK', 'NIN', 'PLD', 'PUP', 'RDM', 'RNG', 'RUN', 'SAM', 'SCH', 'SMN', 'THF', 'WAR', 'WHM' } +-- Put any items in your inventory here you don't want to show up in the final report +-- recommended for furniture, food, meds, pop items or any gear you know you want to keep for some reason +-- use * for anything. +defaults.ccignore = S{ "Rem's Tale*", "Storage Slip *" } +-- Set to nil or delete for unlimited +defaults.ccmaxuse = nil +-- List bags you want to not check against, needs to match "Location" column in _report.txt +defaults.ccskipBags = S{ 'Storage', 'Temporary' } +-- this prints out the _sets _ignored and _inventory files +ccDebug = false + +settings = config.load('ccConfig.xml',defaults) + +register_unhandled_command(function(command) + command = command and command:lower() or nil + if command ~= 'cc' and command ~= 'closetcleaner' then + return + end + setmetatable(cc.sandbox, {__index = gearswap.user_env}) + cc.sandbox.itemsBylongName = T{} + cc.sandbox.itemsByName = T{} + cc.sandbox.inventoryGear = T{} + cc.sandbox.gsGear = T{} + for k,v in pairs(gearswap.res.items) do + cc.sandbox.itemsBylongName[gearswap.res.items[k].name_log:lower()] = k + cc.sandbox.itemsByName[gearswap.res.items[k].name:lower()] = k + end + cc.sandbox.jobs = {} + for k,v in pairs(gearswap.res.jobs) do + cc.sandbox.jobs[gearswap.res.jobs[k].english_short] = k + end + if not windower.dir_exists(windower.addon_path..'report') then + windower.create_dir(windower.addon_path..'report') + end + local path = windower.addon_path:gsub('\\','/') + path = path..'report/'..player.name + cc.run_report(path) + cc.sandbox = {} + cc.sandbox.windower = setmetatable({}, {__index = windower}) + cc.sandbox.windower.register_event = functions.empty + cc.sandbox.windower.raw_register_event = functions.empty + cc.sandbox.windower.register_unhandled_command = functions.empty + return true +end) + +-- This function creates the report and generates the calls to the other functions +function cc.run_report(path) + mainReportName = path..'_report.txt' + local f = io.open(mainReportName,'w+') + f:write('closetCleaner Report:\n') + f:write('=====================\n\n') + cc.export_inv(path) + cc.export_sets(path) + for k,v in pairs(cc.sandbox.inventoryGear) do + if cc.sandbox.gsGear[k] == nil then + cc.sandbox.gsGear[k] = 0 + end + end + data = T{"Name", " | ", "Count", " | ", "Location", " | ", "Jobs Used", " | ", "Long Name"} + form = T{"%25s", "%3s", "%10s", "%3s", "%20s", "%3s", "%-88s", "%3s", "%60s"} + cc.print_row(f, data, form) + cc.print_break(f, form) + if ccDebug then + ignoredReportName = path..'_ignored.txt' + f2 = io.open(ignoredReportName,'w+') + f2:write('closetCleaner ignored Report:\n') + f2:write('=====================\n\n') + cc.print_row(f2, data, form) + cc.print_break(f2, form) + end + for k,v in cc.spairs(cc.sandbox.gsGear, function(t,a,b) return t[b] > t[a] end) do + if settings.ccmaxuse == nil or v <= settings.ccmaxuse then + printthis = 1 + if not cc.job_used[k] then + cc.job_used[k] = " " + end + for s in pairs(settings.ccignore) do + if windower.wc_match(gearswap.res.items[k].english, s) then + printthis = nil + if cc.sandbox.inventoryGear[k] == nil then + data = T{gearswap.res.items[k].english, " | ", tostring(v), " | ", "NOT FOUND", " | ", cc.job_used[k], " | ", gearswap.res.items[k].english_log} + else + data = T{gearswap.res.items[k].english, " | ", tostring(v), " | ", cc.sandbox.inventoryGear[k], " | ", cc.job_used[k], " | ", gearswap.res.items[k].english_log} + end + if ccDebug then + cc.print_row(f2, data, form) + end + break + end + end + if printthis then + if cc.sandbox.inventoryGear[k] == nil then + data = T{gearswap.res.items[k].english, " | ", tostring(v), " | ", "NOT FOUND", " | ", cc.job_used[k], " | ", gearswap.res.items[k].english_log} + else + data = T{gearswap.res.items[k].english, " | ", tostring(v), " | ", cc.sandbox.inventoryGear[k], " | ", cc.job_used[k], " | ", gearswap.res.items[k].english_log} + end + cc.print_row(f, data, form) + end + end + end + if ccDebug then + f2:close() + print("File created: "..ignoredReportName) + end + f:close() + print("File created: "..mainReportName) +end + + -- This function tallies all the gear in your inventory +function cc.export_inv(path) + if ccDebug then + reportName = path..'_inventory.txt' + finv = io.open(reportName,'w+') + finv:write('closetCleaner Inventory Report:\n') + finv:write('=====================\n\n') + end + + local item_list = T{} + checkbag = true + for n = 0, #gearswap.res.bags do + if not settings.ccskipBags:contains(gearswap.res.bags[n].english) then + for i,v in ipairs(gearswap.get_item_list(gearswap.items[gearswap.res.bags[n].english:gsub(' ', ''):lower()])) do + if v.name ~= empty then + local slot = gearswap.xmlify(tostring(v.slot)) + local name = gearswap.xmlify(tostring(v.name)):gsub('NUM1','1') + + if cc.sandbox.itemsByName[name:lower()] ~= nil then + itemid = cc.sandbox.itemsByName[name:lower()] + elseif cc.sandbox.itemsBylongName[name:lower()] ~= nil then + itemid = cc.sandbox.itemsBylongName[name:lower()] + else + print("Item: "..name.." not found in gearswap.resources!") + end + if ccDebug then + finv:write("Name: "..name.." Slot: "..slot.." Bag: "..gearswap.res.bags[n].english.."\n") + end + if cc.sandbox.inventoryGear[itemid] == nil then + cc.sandbox.inventoryGear[itemid] = gearswap.res.bags[n].english + else + cc.sandbox.inventoryGear[itemid] = cc.sandbox.inventoryGear[itemid]..", "..gearswap.res.bags[n].english + end + end + end + end + end + if ccDebug then + finv:close() + print("File created: "..reportName) + end +end + +-- loads all the relevant jobs.lua files and inserts the sets tables into a supersets table: +-- supersets..sets.... +function cc.export_sets(path) + if ccDebug then + reportName = path..'_sets.txt' + fsets = io.open(reportName,'w+') + fsets:write('closetCleaner sets Report:\n') + fsets:write('=====================\n\n') + end + cc.supersets = {} + cc.job_used = T{} + cc.job_logged = T() + fpath = windower.addon_path:gsub('\\','/') + fpath = fpath:gsub('//','/') + fpath = string.lower(fpath) + dpath = fpath..'data/' + for i,v in ipairs(settings.ccjobs) do + dname = string.lower(dpath..player.name..'/'..v..'.lua') + lname = string.lower(dpath..player.name..'_'..v..'.lua') + lgname = string.lower(dpath..player.name..'_'..v..'_gear.lua') + sname = string.lower(dpath..v..'.lua') + sgname = string.lower(dpath..v..'_gear.lua') + if windower.file_exists(lgname) then + cc.supersets[v] = cc.extract_sets(lgname) + elseif windower.file_exists(lname) then + cc.supersets[v] = cc.extract_sets(lname) + elseif windower.file_exists(sgname) then + cc.supersets[v] = cc.extract_sets(sgname) + elseif windower.file_exists(sname) then + cc.supersets[v] = cc.extract_sets(sname) + elseif windower.file_exists(dname) then + cc.supersets[v] = cc.extract_sets(dname) + else + print('lua file for '..v..' not found!') + end + end + cc.list_sets(cc.supersets, fsets) + cc.supersets = nil + if ccDebug then + fsets:close() + print("File created: "..reportName) + end +end + +-- sets the 'sets' and puts them into supersets based off file name. +function cc.extract_sets(file) + local user_file = gearswap.loadfile(file) + if user_file then + gearswap.setfenv(user_file, cc.sandbox) + cc.sandbox.sets = {} + user_file() + local def_gear = cc.sandbox.init_get_sets or cc.sandbox.get_sets + if def_gear then + def_gear() + end + return table.copy(cc.sandbox.sets) + else + print('lua file for '..file..' not found!') + end +end + +-- this function tallies the items used in each lua file +function cc.list_sets(t, f) + write_sets = T{} + local print_r_cache={} + local function sub_print_r(t,fromTab) + if (type(t)=="table") then + for pos,val in pairs(t) do + if S{"WAR", "MNK", "WHM", "BLM", "RDM", "THF", "PLD", "DRK", "BST", "BRD", "RNG", "SAM", "NIN", "DRG", "SMN", "BLU", "COR", "PUP", "DNC", "SCH", "GEO", "RUN"}:contains(pos) then + job = pos + end + if (type(val)=="table") then + sub_print_r(val,job) + elseif (type(val)=="string") then + if val ~= "" and val ~= "empty" then + if S{"name", "main", "sub", "range", "ammo", "head", "neck", "left_ear", "right_ear", "body", "hands", "left_ring", "right_ring", "back", "waist", "legs", "feet", "ear1", "ear2", "ring1", "ring2", "lear", "rear", "lring", "rring"}:contains(pos) then + if cc.sandbox.itemsByName[val:lower()] ~= nil then + itemid = cc.sandbox.itemsByName[val:lower()] + elseif cc.sandbox.itemsBylongName[val:lower()] ~= nil then + itemid = cc.sandbox.itemsBylongName[val:lower()] + else + print("Item: '"..val.."' not found in gearswap.resources! "..pos) + end + if ccDebug then + f:write('Processing '..job..' name for val '..val..' id '..itemid..'\n') + end + if write_sets[itemid] == nil then + write_sets[itemid] = 1 + if cc.job_used[itemid] == nil then + cc.job_used[itemid] = job + cc.job_logged[itemid..job] = 1 + else + cc.job_used[itemid] = cc.job_used[itemid]..","..job + cc.job_logged[itemid..job] = 1 + end + else + write_sets[itemid] = write_sets[itemid] + 1 + if cc.job_logged[itemid..job] == nil then + cc.job_used[itemid] = cc.job_used[itemid]..","..job + cc.job_logged[itemid..job] = 1 + end + end + end + end + elseif (type(val)=="number") then + print("Found Number: "..val.." from "..pos.." table "..t) + else + print("Error: Val needs to be table or string "..type(val)) + end + end + end + end + sub_print_r(t,nil) + if ccDebug then + data = T{"Name", " | ", "Count", " | ", "Jobs", " | ", "Long Name"} + form = T{"%22s", "%3s", "%10s", "%3s", "%88s", "%3s", "%60s"} + cc.print_row(f, data, form) + cc.print_break(f, form) + f:write('\n') + for k,v in pairs(write_sets) do + data = T{gearswap.res.items[k].english, " | ", tostring(v), " | ", cc.job_used[k], " | ", gearswap.res.items[k].english_log} + cc.print_row(f, data, form) + cc.sandbox.gsGear[k] = v + end + f:write() + else + for k,v in pairs(write_sets) do + cc.sandbox.gsGear[k] = v + end + end +end + +-- interate throught table in a sorted order. +function cc.spairs(t, order) + -- collect the keys + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(t, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end + +-- pass in file handle and a table of formats and table of data +function cc.print_row(f, data, form) + for k,v in pairs(data) do + f:write(string.format(form[k], v)) + end + f:write('\n') +end + +-- pass in file handle and a table of formats and table of data +function cc.print_break(f, form) + for k,v in pairs(form) do + number = string.match(v,"%d+") + for i=1,number do + f:write('-') + end + -- f:write(' ') -- can add characters to end here like spaces but subtract from number in the for loop above + end + f:write('\n') +end + + +function cc.include(str) + str = str:lower() + if not (str == 'closetcleaner' or str == 'closetcleaner.lua') then + include(str, cc.sandbox) + end +end + +cc.sandbox.include = cc.include +cc.sandbox.require = cc.include \ No newline at end of file diff --git a/addons/GearSwap/libs/organizer-lib.lua b/addons/GearSwap/libs/organizer-lib.lua index c3111f6a8a..9ee65aab48 100644 --- a/addons/GearSwap/libs/organizer-lib.lua +++ b/addons/GearSwap/libs/organizer-lib.lua @@ -60,7 +60,7 @@ function org.export_set() -- #trans_item_list[i] = Number of a given item -- trans_item_list[i].id = item ID - local ward_ids = {8,10,11,12} + local ward_ids = {8,10,11,12,13,14,15,16} local wardrobes = {} local ward = {} @@ -234,4 +234,4 @@ function org.string_augments(tab) if tab.augment ~= 'none' then aug_str = aug_str.."'"..augment.."'," end end if aug_str ~= '' then return '{\n'..aug_str..'}' end -end \ No newline at end of file +end diff --git a/addons/GearSwap/packet_parsing.lua b/addons/GearSwap/packet_parsing.lua index f6e0ec0731..3f042a07b1 100644 --- a/addons/GearSwap/packet_parsing.lua +++ b/addons/GearSwap/packet_parsing.lua @@ -33,7 +33,7 @@ parse.i[0x00A] = function (data) windower.debug('zone change') command_registry = Command_Registry.new() table.clear(not_sent_out_equip) - + player.id = data:unpack('I',0x05) player.index = data:unpack('H',0x09) if player.main_job_id and player.main_job_id ~= data:byte(0xB5) and player.name and player.name == data:unpack('z',0x85) and not gearswap_disabled then @@ -49,7 +49,7 @@ parse.i[0x00A] = function (data) player.max_hp = data:unpack('I',0xE9) player.max_mp = data:unpack('I',0xED) update_job_names() - + world.zone_id = data:unpack('H',0x31) _ExtraData.world.conquest = false for i,v in pairs(region_to_zone_map) do @@ -63,9 +63,9 @@ parse.i[0x00A] = function (data) end weather_update(data:byte(0x69)) world.logged_in = true - + _ExtraData.world.in_mog_house = data:byte(0x81) == 1 - + _ExtraData.player.base_str = data:unpack('H',0xCD) _ExtraData.player.base_dex = data:unpack('H',0xCF) _ExtraData.player.base_vit = data:unpack('H',0xD1) @@ -80,7 +80,7 @@ parse.i[0x00A] = function (data) _ExtraData.player.add_int = data:unpack('h',0xE3) _ExtraData.player.add_mnd = data:unpack('h',0xE5) _ExtraData.player.add_chr = data:unpack('h',0xE7) - + _ExtraData.player.str = _ExtraData.player.base_str + _ExtraData.player.add_str _ExtraData.player.dex = _ExtraData.player.base_dex + _ExtraData.player.add_dex _ExtraData.player.vit = _ExtraData.player.base_vit + _ExtraData.player.add_vit @@ -89,7 +89,7 @@ parse.i[0x00A] = function (data) _ExtraData.player.mnd = _ExtraData.player.base_mnd + _ExtraData.player.add_mnd _ExtraData.player.chr = _ExtraData.player.base_chr + _ExtraData.player.add_chr refresh_ffxi_info() - + blank_0x063_v9_inc = true end @@ -115,7 +115,7 @@ parse.i[0x01B] = function (data) for job_id = 1,23 do player.jobs[to_windower_api(res.jobs[job_id].english)] = data:byte(job_id + 72) end - + local enc = data:unpack('H',0x61) local tab = {} for slot_id,slot_name in pairs(default_slot_map) do @@ -185,7 +185,9 @@ parse.i[0x037] = function (data) end end end]] - + -- Info provided by Akaden + vana_offset = os.time() - (((data:unpack("I",0x41)*60 - data:unpack("I",0x3D)) % 0x100000000) / 60) + local indi_byte = data:byte(0x59) if indi_byte%128/64 >= 1 then local temp_indi = _ExtraData.player.indi @@ -241,12 +243,12 @@ function parse_equip_chunk(chunk) if inv_slot == 0 then -- Unequipping local bag_id = items.equipment[equip_slot].bag_id inv_slot = items.equipment[equip_slot].slot - + if inv_slot == empty then return end -- unequipping something that was already unequipped? - + local inv = items[to_windower_compact(res.bags[bag_id].english)] if not inv[inv_slot] then inv[inv_slot] = make_empty_item_table(inv_slot) end - + inv[inv_slot].status = 0 -- Set the status to "unequipped" items.equipment[equip_slot] = {slot=empty,bag_id=0} else @@ -334,8 +336,9 @@ parse.i[0x117] = function (data) end parse.i[0x053] = function (data) - if data:unpack('H',0xD) == 0x12D and player then - -- You're unable to use trust magic if you're not the party leader or solo + local message = data:unpack('H',0xD) + if (message == 0x12D or message == 0x12A or message == 0x12B or message == 0x12C) and player then + -- You're unable to use trust magic if you're not the party leader, solo, pt full or trying to summon an already summoned trust local ts,tab = command_registry:find_by_time() if tab and tab.spell and tab.spell.prefix ~= '/pet' and not gearswap_disabled then tab.spell.action_type = 'Interruption' @@ -377,7 +380,7 @@ parse.i[0x061] = function (data) player.max_mp = data:unpack('I',9) player.main_job_id = data:byte(13) player.main_job_level = data:byte(14) - + _ExtraData.player.nation_id = data:byte(0x51) _ExtraData.player.nation = res.regions[_ExtraData.player.nation_id][language] or 'None' _ExtraData.player.base_str = data:unpack('H',0x15) @@ -404,7 +407,7 @@ parse.i[0x061] = function (data) _ExtraData.player.earth_resistance = data:unpack('h',0x3F) _ExtraData.player.water_resistance = data:unpack('h',0x41) _ExtraData.player.dark_resistance = data:unpack('h',0x43) - + _ExtraData.player.str = _ExtraData.player.base_str + _ExtraData.player.add_str _ExtraData.player.dex = _ExtraData.player.base_dex + _ExtraData.player.add_dex _ExtraData.player.vit = _ExtraData.player.base_vit + _ExtraData.player.add_vit @@ -412,7 +415,7 @@ parse.i[0x061] = function (data) _ExtraData.player.int = _ExtraData.player.base_int + _ExtraData.player.add_int _ExtraData.player.mnd = _ExtraData.player.base_mnd + _ExtraData.player.add_mnd _ExtraData.player.chr = _ExtraData.player.base_chr + _ExtraData.player.add_chr - + if player.sub_job_id ~= data:byte(15) then -- Subjob change event local temp_sub = player.sub_job @@ -456,17 +459,17 @@ parse.i[0x063] = function (data) for i=1,32 do local buff_id = data:unpack('H',i*2+7) if buff_id ~= 255 and buff_id ~= 0 then -- 255 is used for "no buff" - local t = data:unpack('I',i*4+0x45)/60+1439307535 + local t = data:unpack('I',i*4+0x45)/60 newbuffs[i] = setmetatable({ name=res.buffs[buff_id].name, buff=copy_entry(res.buffs[buff_id]), - id = buff_id, + id=buff_id, time=t, date=os.date('*t',t), }, {__index=function(t,k) if k and k=='duration' then - return rawget(t,'time')-os.time() + return rawget(t,'time')-os.time()+(vana_offset or 0) else return rawget(t,k) end @@ -474,7 +477,6 @@ parse.i[0x063] = function (data) end end if seen_0x063_type9 then - -- Look for exact matches for n,new in pairs(newbuffs) do newbuffs[n].matched_exactly = nil @@ -487,7 +489,7 @@ parse.i[0x063] = function (data) end end end - + -- Look for time-independent matches, which are assumedly a spell overwriting itself for n,new in pairs(newbuffs) do newbuffs[n].matched_imprecisely = nil @@ -502,7 +504,8 @@ parse.i[0x063] = function (data) end end end - + + local batch = L{} for n,new in pairs(newbuffs) do if new.matched_exactly then newbuffs[n].matched_exactly = nil @@ -527,17 +530,16 @@ parse.i[0x063] = function (data) local buff_name = res.buffs[new.id][language] windower.debug('gain buff '..buff_name..' ('..tostring(new.id)..')') -- Need to figure out what I'm going to do with this: - if T{'terror','sleep','stun','petrification','charm','weakness'}:contains(buff_name:lower()) then + if T{'terror','sleep','stun','petrification','charm','weakness','lullaby'}:contains(buff_name:lower()) then + --Weakness is technically incorrect, because monsters can afflict players with weakness without killing them. + --However, it is being used to detect when players die so for the moment it must stay. for ts,v in pairs(command_registry) do if v.midaction then command_registry:delete_entry(ts) end end end - if not gearswap_disabled then - refresh_globals() - equip_sets('buff_change',nil,buff_name,true,new) - end + batch:append({name=buff_name,gain=true,tab=new}) end end for i,old in pairs(_ExtraData.player.buff_details) do @@ -548,14 +550,17 @@ parse.i[0x063] = function (data) end local buff_name = res.buffs[old.id][language] windower.debug('lose buff '..buff_name..' ('..tostring(old.id)..')') - if not gearswap_disabled then - refresh_globals() - equip_sets('buff_change',nil,buff_name,false,old) - end + batch:append({name=buff_name,gain=false,tab=old}) + end + end + if not gearswap_disabled and #batch > 0 then + refresh_globals() + for v,_ in batch:it() do + equip_sets('buff_change',nil,v.name,v.gain,v.tab) end end end - + table.reassign(_ExtraData.player.buff_details,newbuffs) for i=1,32 do player.buffs[i] = (newbuffs[i] and newbuffs[i].id) or nil @@ -567,34 +572,39 @@ parse.i[0x063] = function (data) end parse.i[0x067] = function (data) - if data:byte(7)%128 == 4 and player.index == data:unpack('H',0x0D) then -- You are the owner + if player.index == data:unpack('H',0x0D) then -- You are the owner _ExtraData.pet.tp = data:unpack('H',0x11) end end parse.i[0x068] = function (data) - if data:byte(7)%128 == 4 and player.id == data:unpack('I',0x09) then -- You are the owner + if player.index == data:unpack('H',0x07) then -- You are the owner _ExtraData.pet.tp = data:unpack('H',0x11) end end parse.i[0x076] = function (data) - partybuffs = {} + _ExtraPartyData.buffs = {} + _ExtraPartyData.buff_details = {} for i = 0,4 do if data:unpack('I',i*48+5) == 0 then break else local index = data:unpack('H',i*48+5+4) - partybuffs[index] = { - id = data:unpack('I',i*48+5+0), - index = data:unpack('H',i*48+5+4), - buffs = {} - } + _ExtraPartyData.buffs[index] = {} + _ExtraPartyData.buff_details[index] = {} for n=1,32 do - partybuffs[index].buffs[n] = data:byte(i*48+5+16+n-1) + 256*( math.floor( data:byte(i*48+5+8+ math.floor((n-1)/4)) / 4^((n-1)%4) )%4) + local buff_id = data:byte(i*48+5+16+n-1) + 256*( math.floor( data:byte(i*48+5+8+ math.floor((n-1)/4)) / 4^((n-1)%4) )%4) + if buff_id ~= 255 and buff_id ~= 0 then + _ExtraPartyData.buffs[index][n] = buff_id + _ExtraPartyData.buff_details[index][n] = { + name=res.buffs[buff_id].name, + buff=copy_entry(res.buffs[buff_id]), + id=buff_id, + } + end end - - + if alliance[1] then local cur_player for n,m in pairs(alliance[1]) do @@ -603,17 +613,26 @@ parse.i[0x076] = function (data) break end end - local new_buffs = convert_buff_list(partybuffs[index].buffs) - if cur_player and cur_player.buffactive and not gearswap_disabled then + local new_buffs = convert_buff_list(_ExtraPartyData.buffs[index]) + if index == 1464 then + local newbuff_count = 0 + for _,v in pairs(new_buffs) do + newbuff_count = newbuff_count + 1 + end + end + if cur_player and cur_player.buffactive and not gearswap_disabled and + user_env and type(user_env['party_buff_change']) == 'function' then + -- Make sure the character existed before (with a buffactive list) - Avoids zoning. + -- This is also the heaviest event, so make sure the user is using it. local old_buffs = cur_player.buffactive - -- Make sure the character existed before (with a buffactive list) - Avoids zoning. + local batch = L{} for n,m in pairs(new_buffs) do if type(n) == 'number' and m ~= old_buffs[n] then if not old_buffs[n] or m > old_buffs[n] then -- gaining buff - equip_sets('party_buff_change',nil,cur_player,res.buffs[n][language],true,copy_entry(res.buffs[n])) + batch:append({player=cur_player,name=res.buffs[n][language],gain=true,tab=copy_entry(res.buffs[n])}) old_buffs[n] = nil else -- losing buff - equip_sets('party_buff_change',nil,cur_player,res.buffs[n][language],false,copy_entry(res.buffs[n])) + batch:append({player=cur_player,name=res.buffs[n][language],gain=false,tab=copy_entry(res.buffs[n])}) old_buffs[n] = nil end elseif type(n) ~= 'number' then @@ -621,52 +640,93 @@ parse.i[0x076] = function (data) old_buffs[n] = nil end end - + for n,m in pairs(old_buffs) do if type(n) == 'number' and m ~= new_buffs[n] then-- losing buff - equip_sets('party_buff_change',nil,cur_player,res.buffs[n][language],false,copy_entry(res.buffs[n])) + batch:append({player=cur_player,name=res.buffs[n][language],gain=false,tab=copy_entry(res.buffs[n])}) + end + end + if #batch > 0 then + refresh_globals() + for v,_ in batch:it() do + equip_sets('party_buff_change',nil,v.player,v.name,v.gain,v.tab) end end end if cur_player then - cur_player.buffactive = new_buffs + if cur_player.buffactive then + table.reassign(cur_player.buffactive, new_buffs) + else + cur_player.buffactive = new_buffs + end + end + if cur_player and cur_player.id ~= player.id then + if cur_player.buff_details then + table.reassign(cur_player.buff_details,_ExtraPartyData.buff_details[index]) + else + cur_player.buff_details = _ExtraPartyData.buff_details[index] + end end end - end end end -parse.i[0x0DF] = function (data) - if data:unpack('I',5) == player.id then - player.vitals.hp = data:unpack('I',9) - player.vitals.mp = data:unpack('I',13) - player.vitals.tp = data:unpack('I',0x11) - player.vitals.hpp = data:byte(0x17) - player.vitals.mpp = data:byte(0x18) - - player.hp = data:unpack('I',9) - player.mp = data:unpack('I',13) - player.tp = data:unpack('I',0x11) - player.hpp = data:byte(0x17) - player.mpp = data:byte(0x18) +function update_vitals(id, hp, mp, tp, hpp, mpp) + if id==player.id then + player.vitals.hp = hp + player.vitals.mp = mp + player.vitals.tp = tp + player.vitals.hpp = hpp + player.vitals.mpp = mpp + + player.hp = hp + player.mp = mp + player.tp = tp + player.hpp = hpp + player.mpp = mpp + end + -- Update alliance + local found_person = false + for i,v in pairs(alliance) do + if type(v) == 'table' then + for k,j in pairs(v) do + if type(j) == 'table' and j.id == id then + j.hp = hp + j.mp = mp + j.tp = tp + j.hpp = hpp + j.mpp = mpp + found_person = true + end + end + if found_person then + break + end + end end end +parse.i[0x0DF] = function (data) + update_vitals( + data:unpack('I',5), + data:unpack('I',9), + data:unpack('I',13), + data:unpack('I',0x11), + data:byte(0x17), + data:byte(0x18) + ) +end + parse.i[0x0E2] = function (data) - if data:unpack('I',5)==player.id then - player.vitals.hp = data:unpack('I',9) - player.vitals.mp = data:unpack('I',0xB) - player.vitals.tp = data:unpack('I',0x11) - player.vitals.hpp = data:byte(0x1E) - player.vitals.mpp = data:byte(0x1F) - - player.hp = data:unpack('I',9) - player.mp = data:unpack('I',0xB) - player.tp = data:unpack('I',0x11) - player.hpp = data:byte(0x1E) - player.mpp = data:byte(0x1F) - end + update_vitals( + data:unpack('I',5), + data:unpack('I',9), + data:unpack('I',0xB), + data:unpack('I',0x11), + data:byte(0x1E), + data:byte(0x1F) + ) end parse.o[0x100] = function(data) @@ -674,9 +734,9 @@ parse.o[0x100] = function(data) local newmain = data:byte(5) if res.jobs[newmain] and newmain ~= 0 and newmain ~= player.main_job_id then windower.debug('job change') - + command_registry = Command_Registry.new() - + table.clear(not_sent_out_equip) table.clear(equip_list_history) table.clear(equip_list) @@ -688,10 +748,9 @@ parse.o[0x100] = function(data) end windower.send_command('lua i '.._addon.name..' load_user_files '..newmain) end - - + if gearswap_disabled then return end - + local newmain = data:byte(5) if res.jobs[newmain] and newmain ~= player.main_job_id then command_enable('main','sub','range','ammo','head','neck','lear','rear','body','hands','lring','rring','back','waist','legs','feet') -- enable all slots @@ -700,13 +759,14 @@ end function initialize_packet_parsing() for i,v in pairs(parse.i) do - local lastpacket = windower.packets.last_incoming(i) - if lastpacket then - v(lastpacket) - end - if i == 0x63 and lastpacket and lastpacket:byte(5) ~= 9 then - -- Not receiving an accurate buff line on load because the wrong 0x063 packet was sent last - + if i ~= 0x028 then + local lastpacket = windower.packets.last_incoming(i) + if lastpacket then + v(lastpacket) + end + if i == 0x63 and lastpacket and lastpacket:byte(5) ~= 9 then + -- Not receiving an accurate buff line on load because the wrong 0x063 packet was sent last + end end end -end \ No newline at end of file +end diff --git a/addons/GearSwap/refresh.lua b/addons/GearSwap/refresh.lua index d7c0a1c312..18040d1824 100644 --- a/addons/GearSwap/refresh.lua +++ b/addons/GearSwap/refresh.lua @@ -61,39 +61,38 @@ end ----------------------------------------------------------------------------------- function load_user_files(job_id,user_file) job_id = tonumber(job_id) - + if current_file then user_pcall('file_unload',current_file) end - + for i in pairs(registered_user_events) do unregister_event_user(i) end - + for i in pairs(__raw.text.registry) do windower.text.delete(i) end - + for i in pairs(__raw.prim.registry) do windower.prim.delete(i) end - + current_file = nil - gearswap_disabled = true sets = nil user_env = nil unhandled_command_events = {} --registered_user_events = {} include_user_path = nil - + language = 'english' -- Reset language to english when changing job files. refresh_globals() - + if job_id and res.jobs[job_id] then player.main_job_id = job_id update_job_names() end - + local path,base_dir,filename path,base_dir,filename = pathsearch({user_file}) @@ -105,14 +104,13 @@ function load_user_files(job_id,user_file) player.name..'.lua',short_job..'.lua',long_job..'.lua','default.lua'} path,base_dir,filename = pathsearch(tab) end - + if not path then current_file = nil - gearswap_disabled = true sets = nil return end - + user_env = {gearswap = _G, _global = _global, _settings = _settings,_addon=_addon, -- Player functions equip = equip, cancel_spell=cancel_spell, change_target=change_target, cast_delay=cast_delay, @@ -122,17 +120,18 @@ function load_user_files(job_id,user_file) show_swaps = show_swaps,debug_mode=debug_mode,include_path=user_include_path, register_unhandled_command=user_unhandled_command,move_spell_target=move_spell_target, language=language, - + -- Library functions - string=string,math=math,table=table,set=set,list=list,T=T,S=S,L=L,pack=pack, - os=os,texts=texts,type=type,tostring=tostring,tonumber=tonumber,pairs=pairs, + string=string,math=math,table=table,set=set,list=list,queue=queue,T=T,S=S,L=L,Q=Q,pack=pack,functions=functions, + os=os,texts=texts,bit=bit,type=type,tostring=tostring,tonumber=tonumber,pairs=pairs, ipairs=ipairs, print=print, add_to_chat=add_to_chat_user,unpack=unpack,next=next, select=select,lua_base_path=windower.addon_path,empty=empty,file=file, loadstring=loadstring,assert=assert,error=error,pcall=pcall,io=io,dofile=dofile, - + debug=debug,coroutine=coroutine,setmetatable=setmetatable,getmetatable=getmetatable, rawset=rawset,rawget=rawget,require=include_user, - + _libs=_libs, + -- Player environment things buffactive=buffactive, player=player, @@ -146,42 +145,40 @@ function load_user_files(job_id,user_file) body=empty,hands=empty,ring1=empty,ring2=empty, back=empty,waist=empty,legs=empty,feet=empty}} } - + user_env['_G'] = user_env - + -- Try to load data/_
.lua local funct, err = loadfile(path) - + -- If the file cannot be loaded, print the error and load the default. if funct == nil then print('User file problem: '..err) current_file = nil - gearswap_disabled = true sets = nil return else current_file = filename print('GearSwap: Loaded your '..current_file..' file!') end - + setfenv(funct, user_env) - + -- Verify that funct contains functions. local status, plugin = pcall(funct) - + if not status then error('GearSwap: File failed to load: \n'..plugin) - gearswap_disabled = true sets = nil return nil end - + _global.pretarget_cast_delay = 0 _global.precast_cast_delay = 0 _global.cancel_spell = false _global.current_event = 'get_sets' user_pcall('get_sets') - + gearswap_disabled = false sets = user_env.sets end @@ -207,10 +204,10 @@ function refresh_player(dt,user_event_flag) if not user_event_flag or dt > 0.5 then pl = windower.ffxi.get_player() if not pl or not pl.vitals then return end - + player_mob_table = windower.ffxi.get_mob_by_index(pl.index) if not player_mob_table then return end - + table.reassign(player,pl) for i,v in pairs(player.vitals) do player[i]=v @@ -224,7 +221,7 @@ function refresh_player(dt,user_event_flag) end player.nation_id = player.nation player.nation = res.regions[player.nation_id][language] or 'None' - + for i,v in pairs(player_mob_table) do if i == 'name' then player.mob_name = v @@ -232,12 +229,12 @@ function refresh_player(dt,user_event_flag) player[i] = v end end - + if player_mob_table.race ~= nil then player.race_id = player.race player.race = res.races[player.race][language] end - + -- If we have a pet, create or update the table info. if player_mob_table and player_mob_table.pet_index then local player_pet_table = windower.ffxi.get_mob_by_index(player_mob_table.pet_index) @@ -247,7 +244,7 @@ function refresh_player(dt,user_event_flag) pet.is_npc = nil pet.isvalid = true if pet.tp then pet.tp = pet.tp/10 end - + if avatar_element[pet.name] then pet.element = res.elements[avatar_element[pet.name]][language] else @@ -259,12 +256,12 @@ function refresh_player(dt,user_event_flag) else table.reassign(pet, {isvalid=false}) end - + if player.main_job_id == 18 or player.sub_job_id == 18 then local auto_tab if player.main_job_id == 18 then auto_tab = windower.ffxi.get_mjob_data() else auto_tab = windower.ffxi.get_sjob_data() end - + if auto_tab.name then for i,v in pairs(auto_tab) do if not T{'available_heads','attachments','available_frames','available_attachments','frame','head'}:contains(i) then @@ -301,7 +298,7 @@ function refresh_player(dt,user_event_flag) pet.attachments[res.items[id][language]] = true end end - + if pet.max_mp ~= 0 then pet.mpp = math.floor(pet.mp/pet.max_mp*100) else @@ -311,7 +308,7 @@ function refresh_player(dt,user_event_flag) elseif player.main_job_id == 23 then local species_id = windower.ffxi.get_mjob_data().species -- Should add instincts when they become available - + if species_id then player.species = {} for i,v in pairs(res.monstrosity[species_id]) do @@ -329,15 +326,15 @@ function refresh_player(dt,user_event_flag) player.species = nil end end - + -- This being nil does not cause a return, but items should not really be changing when zoning. local cur_equip = table.reassign({},items.equipment) - + -- Assign player.equipment to be the gear that has been sent out and the server currently thinks -- you are wearing. (the sent_out_equip for loop above). player.equipment = make_user_table() table.reassign(player.equipment,to_names_set(cur_equip)) - + -- Assign player.inventory to be keyed to item.inventory[i][language] and to have a value of count, similar to buffactive for i,bag in pairs(res.bags) do local bag_name = to_windower_bag_api(bag.en) @@ -348,18 +345,18 @@ function refresh_player(dt,user_event_flag) player.target = target_complete(windower.ffxi.get_mob_by_target('t')) player.subtarget = target_complete(windower.ffxi.get_mob_by_target('st')) player.last_subtarget = target_complete(windower.ffxi.get_mob_by_target('lastst')) + - - + table.reassign(fellow,target_complete(windower.ffxi.get_mob_by_target(''))) if fellow.name then fellow.isvalid = true else fellow.isvalid=false end - + table.reassign(buffactive,convert_buff_list(player.buffs)) - + for global_variable_name,extradatatable in pairs(_ExtraData) do if _G[global_variable_name] then for sub_variable_name,value in pairs(extradatatable) do @@ -399,7 +396,7 @@ function refresh_ffxi_info(dt,user_event_flag) world[i] = v end end - + for global_variable_name,extradatatable in pairs(_ExtraData) do if _G[global_variable_name] then for sub_variable_name,value in pairs(extradatatable) do @@ -423,30 +420,22 @@ function weather_update(id) world.real_weather_id = id world.real_weather = res.weather[id][language] world.real_weather_element = res.elements[res.weather[id].element][language] - local buff = false + world.real_weather_intensity = res.weather[world.real_weather_id].intensity if buffactive[178] then - buff = true world.weather_id = 4 elseif buffactive[179] then - buff = true world.weather_id = 12 elseif buffactive[180] then - buff = true world.weather_id = 10 elseif buffactive[181] then - buff = true world.weather_id = 8 elseif buffactive[182] then - buff = true world.weather_id = 14 elseif buffactive[183] then - buff = true world.weather_id = 6 elseif buffactive[184] then - buff = true world.weather_id = 16 elseif buffactive[185] then - buff = true world.weather_id = 18 elseif buffactive[589] then world.weather_id = 5 @@ -465,11 +454,9 @@ function weather_update(id) elseif buffactive[596] then world.weather_id = 19 end - if buff and world.weather_id == world.real_weather_id then - world.weather_id = world.weather_id + 1 - end world.weather = res.weather[world.weather_id][language] world.weather_element = res.elements[res.weather[world.weather_id].element][language] + world.weather_intensity = res.weather[world.weather_id].intensity end @@ -490,25 +477,25 @@ function refresh_group_info(dt,user_event_flag) if not alliance or #alliance == 0 then alliance = make_alliance() end - + local c_alliance = make_alliance() - + local j = windower.ffxi.get_party() or {} - + c_alliance.leader = j.alliance_leader -- Test whether this works c_alliance[1].leader = j.party1_leader c_alliance[2].leader = j.party2_leader c_alliance[3].leader = j.party3_leader - + for i,v in pairs(j) do if type(v) == 'table' and v.mob and v.mob.race then v.mob.race_id = v.mob.race v.mob.race = res.races[v.mob.race][language] end - + local allyIndex local partyIndex - + -- For 'p#', ally index is 1, party index is the second char if i:sub(1,1) == 'p' and tonumber(i:sub(2)) then allyIndex = 1 @@ -518,17 +505,18 @@ function refresh_group_info(dt,user_event_flag) allyIndex = tonumber(i:sub(2,2))+1 partyIndex = tonumber(i:sub(3))+1 end - + if allyIndex and partyIndex then - if v.mob and partybuffs[v.mob.index] then - v.buffactive = convert_buff_list(partybuffs[v.mob.index].buffs) + if v.mob and _ExtraPartyData.buffs[v.mob.index] then + v.buffactive = convert_buff_list(_ExtraPartyData.buffs[v.mob.index]) + v.buff_details = _ExtraPartyData.buff_details[v.mob.index] elseif v.mob and v.mob.index == player.index then v.buffactive = buffactive end c_alliance[allyIndex][partyIndex] = v c_alliance[allyIndex].count = c_alliance[allyIndex].count + 1 c_alliance.count = c_alliance.count + 1 - + if v.mob then if v.mob.id == c_alliance[1].leader then c_alliance[1].leader = v @@ -537,14 +525,14 @@ function refresh_group_info(dt,user_event_flag) elseif v.mob.id == c_alliance[3].leader then c_alliance[3].leader = v end - + if v.mob.id == c_alliance.leader then c_alliance.leader = v end end end end - + -- Clear the old structure while maintaining the party references: for ally_party = 1,3 do @@ -555,7 +543,7 @@ function refresh_group_info(dt,user_event_flag) end alliance.count = 0 alliance.leader = nil - + -- Reassign to the new structure table.reassign(alliance[1],c_alliance[1]) table.reassign(alliance[2],c_alliance[2]) @@ -595,15 +583,15 @@ end ----------------------------------------------------------------------------------- function convert_buff_list(bufflist) local buffarr = {} - for i,id in pairs(bufflist) do - if res.buffs[id] then -- For some reason we always have buff 255 active, which doesn't have an entry. + for _,id in pairs(bufflist) do + if res.buffs[id] then local buff = res.buffs[id][language]:lower() if buffarr[buff] then buffarr[buff] = buffarr[buff] +1 else buffarr[buff] = 1 end - + if buffarr[id] then buffarr[id] = buffarr[id] +1 else @@ -639,7 +627,7 @@ function refresh_item_list(itemlist) if type(v) == 'table' and v.id and v.id ~= 0 then -- If we don't already have the primary item name in the table, add it. if res.items[v.id] and res.items[v.id][language] and not retarr[res.items[v.id][language]] then - retarr[res.items[v.id][language]] = v + retarr[res.items[v.id][language]] = table.copy(v) retarr[res.items[v.id][language]].shortname=res.items[v.id][language]:lower() -- If a long version of the name exists, and is different from the short version, -- add the long name to the info table and point the long name's key at that table. @@ -669,7 +657,7 @@ end function refresh_user_env(job_id) refresh_globals() if not job_id then job_id = windower.ffxi.get_player().main_job_id end - + if not job_id then windower.send_command('@wait 1;lua i '.._addon.name..' refresh_user_env') else @@ -691,17 +679,17 @@ function pathsearch(files_list) -- base directory search order: -- windower -- %appdata%/Windower/GearSwap - + -- sub directory search order: -- libs-dev (only in windower addon path) -- libs (only in windower addon path) -- data/player.name -- data/common -- data - + local gearswap_data = windower.addon_path .. 'data/' local gearswap_appdata = (os.getenv('APPDATA') or '') .. '/Windower/GearSwap/' - + local search_path = { [1] = windower.addon_path .. 'libs-dev/', [2] = windower.addon_path .. 'libs/', @@ -713,7 +701,7 @@ function pathsearch(files_list) [8] = gearswap_appdata, [9] = windower.windower_path .. 'addons/libs/' } - + local user_path local normal_path @@ -725,7 +713,7 @@ function pathsearch(files_list) user_path = basepath .. include_user_path .. '/' .. v end normal_path = basepath .. v - + if user_path and windower.file_exists(user_path) then return user_path,basepath,v elseif normal_path and windower.file_exists(normal_path) then @@ -735,6 +723,6 @@ function pathsearch(files_list) end end end - + return false end diff --git a/addons/GearSwap/statics.lua b/addons/GearSwap/statics.lua index 837ce993da..b0fd4a0587 100644 --- a/addons/GearSwap/statics.lua +++ b/addons/GearSwap/statics.lua @@ -25,7 +25,7 @@ --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- Convert the spells and job abilities into a referenceable list of aliases -- - + unify_prefix = {['/ma'] = '/ma', ['/magic']='/ma',['/jobability'] = '/ja',['/ja']='/ja',['/item']='/item',['/song']='/ma', ['/so']='/ma',['/ninjutsu']='/ma',['/weaponskill']='/ws',['/ws']='/ws',['/ra']='/ra',['/rangedattack']='/ra',['/nin']='/ma', ['/throw']='/ra',['/range']='/ra',['/shoot']='/ra',['/monsterskill']='/ms',['/ms']='/ms',['/pet']='/ja',['Monster']='Monster',['/bstpet']='/ja'} @@ -34,30 +34,19 @@ action_type_map = {['/ja']='Ability',['/jobability']='Ability',['/so']='Magic',[ ['/ra']='Ranged Attack',['/range']='Ranged Attack',['/throw']='Ranged Attack',['/shoot']='Ranged Attack',['/ms']='Ability',['/monsterskill']='Ability', ['/ws']='Ability',['/weaponskill']='Ability',['/item']='Item',['/pet']='Ability',['/bstpet']='Ability',['Monster']='Monster Move'} -usable_item_bags = { - res.bags[3], -- Temporary Items - res.bags[0], -- Inventory - res.bags[8], -- Wardrobe 1 - res.bags[10], -- Wardrobe 2 - res.bags[11], -- Wardrobe 3 - res.bags[12]} -- Wardrobe 4 - -equippable_item_bags = { - res.bags[0], -- Inventory - res.bags[8], -- Wardrobe 1 - res.bags[10], -- Wardrobe 2 - res.bags[11], -- Wardrobe 3 - res.bags[12]} -- Wardrobe 4 - +equippable_item_bags = {res.bags:equippable(true):extract()} + +usable_item_bags = {res.bags:with('command','temporary'), table.extract(equippable_item_bags)} + bag_string_lookup = {} for i,v in pairs(res.bags) do bag_string_lookup[to_windower_bag_api(v.en)]=i end - -bstpet_range = {min=672,max=782} -- Range of the JA resource devoted to BST jugpet abilities - + +bstpet_range = {min=672,max=798} -- Range of the JA resource devoted to BST jugpet abilities + delay_map_to_action_type = {['Ability']=3,['Magic']=20,['Ranged Attack']=10,['Item']=10,['Monster Move']=10,['Interruption']=3} - + validabils = {} validabils['english'] = {['/ma'] = {}, ['/ja'] = {}, ['/ws'] = {}, ['/item'] = {}, ['/ra'] = {}, ['/ms'] = {}, ['/pet'] = {}, ['/trig'] = {}, ['/echo'] = {}} validabils['french'] = {['/ma'] = {}, ['/ja'] = {}, ['/ws'] = {}, ['/item'] = {}, ['/ra'] = {}, ['/ms'] = {}, ['/pet'] = {}, ['/trig'] = {}, ['/echo'] = {}} @@ -92,16 +81,18 @@ for i,v in pairs(res.weapon_skills) do make_entry(v,i) end -for i,v in pairs(res.monster_abilities) do +for i,v in pairs(res.monster_skills) do v.type = 'MonsterSkill' make_entry(v,i) end for i,v in pairs(res.items) do v.prefix = '/item' - make_entry(v,i) + if not validabils['english'][v.prefix][v.english:lower()] or v.cast_delay then + make_entry(v,i) + end end - + -- Should transition these slot maps to be based off res.slots, but it's very unlikely to change. default_slot_map = T{'sub','range','ammo','head','body','hands','legs','feet','neck','waist', 'left_ear', 'right_ear', 'left_ring', 'right_ring','back'} @@ -135,14 +126,14 @@ encumbrance_map[0] = 0x79 -- Slots mapped onto encumbrance byte values. addendum_white = {[14]="Poisona",[15]="Paralyna",[16]="Blindna",[17]="Silena",[18]="Stona",[19]="Viruna",[20]="Cursna", [143]="Erase",[13]="Raise II",[140]="Raise III",[141]="Reraise II",[142]="Reraise III",[135]="Reraise"} - + addendum_black = {[253]="Sleep",[259]="Sleep II",[260]="Dispel",[162]="Stone IV",[163]="Stone V",[167]="Thunder IV", [168]="Thunder V",[157]="Aero IV",[158]="Aero V",[152]="Blizzard IV",[153]="Blizzard V",[147]="Fire IV",[148]="Fire V", [172]="Water IV",[173]="Water V",[255]="Break"} resources_ranged_attack = {id="0",index="0",prefix="/range",english="Ranged",german="Fernwaffe",french="Attaque à dist.",japanese="飛び道具",type="Misc",element="None",targets=S{"Enemy"}} - + -- _globals -- user_data_table = { __newindex = function(tab, key, val) @@ -154,16 +145,6 @@ user_data_table = { end } ---[[eq_data_table = { - __newindex = function(tab, key, val) - rawset(tab, slot_map[user_key_filter(key)], newtab) - end, - - __index = function(tab, key) - return rawget(tab, slot_map[user_key_filter(key)]) - end - }]] - slot_map = make_user_table() slot_map.main = 0 @@ -196,9 +177,10 @@ slot_map.back = 15 -gearswap_disabled = true +gearswap_disabled = false seen_0x063_type9 = false delay_0x063_v9 = false +vana_offset = 572662306+1009810800 not_sent_out_equip = {} command_registry = Command_Registry.new() equip_list = {} @@ -240,6 +222,12 @@ _ExtraData = { pet = {}, world = {in_mog_house = false,conquest=false}, } +-- _ExtraPartyData is the same, but for the party. +-- These structures are necessarily indexed by player index. +_ExtraPartyData = { + buffs = {}, + buff_details = {}, +} unbridled_learning_set = {['Thunderbolt']=true,['Harden Shell']=true,['Absolute Terror']=true, ['Gates of Hades']=true,['Tourbillion']=true,['Pyric Bulwark']=true,['Bilgestorm']=true, @@ -342,7 +330,7 @@ universal_tool_map = { ['Yain: Ichi'] = res.items[2972], } -region_to_zone_map = { +region_to_zone_map = { [4] = S{100,101,139,140,141,142,167,190}, [5] = S{102,103,108,193,196,248}, [6] = S{1,2,104,105,149,150,195}, @@ -363,7 +351,7 @@ region_to_zone_map = { [22] = S{11,12,13}, [24] = S{24,25,26,27,28,29,30,31,32}, } - + function initialize_globals() local pl = windower.ffxi.get_player() @@ -383,14 +371,14 @@ function initialize_globals() if not player.jobs then player.jobs = {} end if not player.merits then player.merits = {} end end - + player.equipment = make_user_table() pet = make_user_table() pet.isvalid = false fellow = make_user_table() fellow.isvalid = false partybuffs = {} - + -- GearSwap effectively needs to maintain two inventory structures: -- one is the proposed current inventory based on equip packets sent to the server, -- the other is the currently reported inventory based on packets sent from the server. @@ -442,4 +430,4 @@ function initialize_globals() end end -initialize_globals() \ No newline at end of file +initialize_globals() diff --git a/addons/GearSwap/targets.lua b/addons/GearSwap/targets.lua index 3e47b74da8..d4f0249e44 100644 --- a/addons/GearSwap/targets.lua +++ b/addons/GearSwap/targets.lua @@ -29,29 +29,33 @@ function valid_target(targ) local spelltarget = {} - local spell_targ - if pass_through_targs[targ] then + + if targ and pass_through_targs[targ] then local j = windower.ffxi.get_mob_by_target(targ) - - if j then spelltarget = target_complete(j) end - - spelltarget.raw = targ - return targ, spelltarget - elseif targ and tonumber(targ) and tonumber(targ) > 255 then - local j = windower.ffxi.get_mob_by_id(tonumber(targ)) - - if j then spelltarget = target_complete(j) end - + if j then + spelltarget = target_complete(j) + end spelltarget.raw = targ return targ, spelltarget - elseif targ and not tonumber(targ) and targ ~= '' then - local mob_array = windower.ffxi.get_mob_array() - for i,v in pairs(mob_array) do - if v.name:lower()==targ:lower() and (not v.is_npc or v.spawn_type == 14) then - spelltarget = target_complete(v) - spelltarget.raw = targ - return targ, spelltarget + elseif targ then + local id = tonumber(targ) + if id then + local j = windower.ffxi.get_mob_by_id(id) + if j then + spelltarget = target_complete(j) + end + spelltarget.raw = targ + return targ, spelltarget + elseif targ ~= '' then + local targ_name = targ:lower() + local mob_array = windower.ffxi.get_mob_array() + for i,v in pairs(mob_array) do + if v.name:lower()==targ_name and (not v.is_npc or v.spawn_type == 14) then + spelltarget = target_complete(v) + spelltarget.raw = targ + return targ, spelltarget + end end end end @@ -146,4 +150,4 @@ function target_type_check(spell) if spell.targets[temptype] then return true end return false -end \ No newline at end of file +end diff --git a/addons/GearSwap/triggers.lua b/addons/GearSwap/triggers.lua index eecaf81ebe..274383bfd9 100644 --- a/addons/GearSwap/triggers.lua +++ b/addons/GearSwap/triggers.lua @@ -44,8 +44,8 @@ windower.register_event('outgoing text',function(original,modified,blocked,ffxi, windower.debug('outgoing text') if gearswap_disabled then return modified end - local splitline = windower.from_shift_jis(windower.convert_auto_trans(modified)):gsub(' ',''):gsub('"(.-)"',function(str) - return str:gsub(' ',string.char(7)) + local splitline = windower.from_shift_jis(windower.convert_auto_trans(modified)):gsub('',''):gsub('"(.-)"',function(str) + return ' '..str:gsub(' ',string.char(7))..' ' end):split(' '):filter(-'') if splitline.n == 0 then return end @@ -77,31 +77,31 @@ windower.register_event('outgoing text',function(original,modified,blocked,ffxi, if unified_prefix and temptarg and (validabils[language][unified_prefix][abil] or unified_prefix=='/ra') then if st_flag then st_flag = nil - return true + return modified elseif temp_mob_arr then refresh_globals() - local r_line, find_monster_ability + local r_line, find_monster_skill - function find_monster_ability(abil) + function find_monster_skill(abil) local line = false if player.species and player.species.tp_moves then -- Iterates over currently available monster TP moves instead of using validabils for i,v in pairs(player.species.tp_moves) do - if res.monster_abilities[i][language]:lower() == abil then - line = copy_entry(res.monster_abilities[i]) + if res.monster_skills[i][language]:lower() == abil then + line = copy_entry(res.monster_skills[i]) break end end end return line end - + if unified_prefix == '/ma' then r_line = copy_entry(res.spells[validabils[language][unified_prefix][abil]]) storedcommand = command..' "'..windower.to_shift_jis(r_line[language])..'" ' - elseif unified_prefix == '/ms' and find_monster_ability(abil) then - r_line = find_monster_ability(abil) + elseif unified_prefix == '/ms' and find_monster_skill(abil) then + r_line = find_monster_skill(abil) storedcommand = command..' "'..windower.to_shift_jis(r_line[language])..'" ' elseif unified_prefix == '/ws' then r_line = copy_entry(res.weapon_skills[validabils[language][unified_prefix][abil]]) @@ -135,12 +135,17 @@ windower.register_event('outgoing text',function(original,modified,blocked,ffxi, if spell.prefix == '/item' then -- Item use packet handling here - if find_usable_item(spell.id,true) then + if bit.band(spell.target.spawn_type, 2) == 2 and find_inventory_item(spell.id) then + --0x36 packet + if spell.target.distance <= 6 then + command_registry[ts].proposed_packet = assemble_menu_item_packet(spell.target.id,spell.target.index,spell.id) + else + windower.add_to_chat(67, "Target out of range.") + return true + end + elseif find_usable_item(spell.id) then --0x37 packet command_registry[ts].proposed_packet = assemble_use_item_packet(spell.target.id,spell.target.index,spell.id) - else - --0x36 packet - command_registry[ts].proposed_packet = assemble_menu_item_packet(spell.target.id,spell.target.index,spell.id) end else command_registry[ts].proposed_packet = assemble_action_packet(spell.target.id,spell.target.index,outgoing_action_category_table[unify_prefix[spell.prefix]],spell.id,initialize_arrow_offset(spell.target)) @@ -181,7 +186,7 @@ parse.i[0x028] = function (data) --print(((res[unpackedaction.resource] or {})[unpackedaction.spell_id] or {}).english,unpackedaction.type,unpackedaction.value,unpackedaction.interruption) local temp_player_mob_table,temp_pet,pet_id = windower.ffxi.get_mob_by_index(player.index) - if temp_player_mob_table.pet_index then + if temp_player_mob_table and temp_player_mob_table.pet_index then temp_pet = windower.ffxi.get_mob_by_index(temp_player_mob_table.pet_index) if temp_pet then pet_id = temp_pet.id @@ -335,4 +340,4 @@ parse.i[0x029] = function (data) equip_sets(prefix..'aftercast',ts,tab.spell) end end -end \ No newline at end of file +end diff --git a/addons/GearSwap/user_functions.lua b/addons/GearSwap/user_functions.lua index 416c3c1cec..2062955ddc 100644 --- a/addons/GearSwap/user_functions.lua +++ b/addons/GearSwap/user_functions.lua @@ -77,10 +77,10 @@ function move_spell_target(position_table) error('\nGearSwap: move_spell_target() is only valid in the precast function', 2) return end - + if type(position_table) == 'table' and type(position_table.x or position_table.X) == 'number' and type(position_table.y or position_table.Y) == 'number' and - type(position_table.z or positino_table.Z) == 'number' then + type(position_table.z or position_table.Z) == 'number' then _global.target_arrow.x = position_table.x or position_table.X _global.target_arrow.y = position_table.y or position_table.Y _global.target_arrow.z = position_table.z or position_table.Z @@ -160,13 +160,13 @@ function enable(...) error('\nGearSwap: enable error, passed an unrecognized slot name. ('..tostring(v)..')',2) end end - + return sending_table end function user_enable(...) local sending_table = enable(...) - + if table.length(sending_table) > 0 then equip(sending_table) end @@ -175,7 +175,7 @@ end function command_enable(...) local sending_table = enable(...) - + if table.length(sending_table) > 0 then refresh_globals() equip_sets('equip_command',nil,sending_table) @@ -223,7 +223,7 @@ function print_set(set,title) end end end - + if #set == table.length(set) then -- If it is a list (keyed by continuous whole number starting at 1), then print it out in order for key,value in ipairs(set) do print_element(key,value) @@ -235,7 +235,7 @@ function print_set(set,title) print_element(k,set[k]) end end - for key,value in pairs(set) do + for key,_ in pairs(set) do if not slot_map[key] then print_element(key,set[key]) end @@ -301,20 +301,21 @@ function include_user(str, load_include_in_this_table) if not (type(str) == 'string') then error('\nGearSwap: include() was passed an invalid value ('..tostring(str)..'). (must be a string)', 2) end - - if T{'bit','socket','mime'}:contains(str:lower()) then - return _G[str:lower()] - elseif T{'pack'}:contains(str:lower()) then + + str = str:lower() + if type(package.loaded[str]) == 'table' then + return package.loaded[str] + elseif T{'pack'}:contains(str) then return end - + if str:sub(-4)~='.lua' then str = str..'.lua' end local path, loaded_values = pathsearch({str}) - + if not path then error('\nGearSwap: Cannot find the include file ('..tostring(str)..').', 2) end - + local f, err = loadfile(path) if f and not err then if load_include_in_this_table and type(load_include_in_this_table) == 'table' then @@ -357,7 +358,7 @@ function user_midaction(bool) return true, v.spell end end - + return false end @@ -389,7 +390,7 @@ function add_to_chat_user(num,str) -- It only needs the number. num=8 end - + if language == 'japanese' then msg.add_to_chat(num,windower.to_shift_jis(str)) else @@ -419,4 +420,4 @@ user_windower = {register_event = register_event_user, raw_register_event = raw_ user_coroutine = coroutine user_coroutine.sleep = user_sleep user_coroutine.yield = user_yield -setmetatable(user_windower,{__index=windower}) \ No newline at end of file +setmetatable(user_windower,{__index=windower}) diff --git a/addons/GearSwap/validate.lua b/addons/GearSwap/validate.lua index 596987842f..11763fc7ec 100644 --- a/addons/GearSwap/validate.lua +++ b/addons/GearSwap/validate.lua @@ -28,6 +28,26 @@ -- Primary entry point. ------------------------------------------------------------------------------------------------------------------- +local validate_keys = { + sets = 'sets', set = 'sets', s = 'sets', + inventory = 'inventory', inv = 'inventory', i = 'inventory', + mogsafe = 'safe', safe = 'safe', ms = 'safe', bank = 'safe', + mogsafe2 = 'safe2', safe2 = 'safe2', ms2 = 'safe2', bank2 = 'safe2', + storage = 'storage', st = 'storage', + moglocker = 'locker', locker = 'locker', ml = 'locker', + mogsatchel = 'satchel', satchel = 'satchel', sa = 'satchel', + mogsack = 'sack', sack = 'sack', sk = 'sack', + mogcase = 'case', case = 'case', c = 'case', + wardrobe = 'wardrobe', w = 'wardrobe', + wardrobe2 = 'wardrobe2', w2 = 'wardrobe2', + wardrobe3 = 'wardrobe3', w3 = 'wardrobe3', + wardrobe4 = 'wardrobe4', w4 = 'wardrobe4', + wardrobe5 = 'wardrobe5', w5 = 'wardrobe5', + wardrobe6 = 'wardrobe6', w6 = 'wardrobe6', + wardrobe7 = 'wardrobe7', w7 = 'wardrobe7', + wardrobe8 = 'wardrobe8', w8 = 'wardrobe8', +} + -- Validate either gear sets or inventory. -- gs validate [inv|set] [filterlist] -- Where inv == i or inv or inventory @@ -36,18 +56,17 @@ function validate(options) local validateType = 'sets' if options and #options > 0 then - if S{'sets','set','s'}:contains(options[1]:lower()) then - table.remove(options,1) - elseif S{'inventory','inv','i'}:contains(options[1]:lower()) then - validateType = 'inv' - table.remove(options,1) + local match = validate_keys[options[1]:lower()] + if match then + validateType = match + table.remove(options, 1) end end - - if validateType == 'inv' then - validate_inventory(options) - else + + if validateType == 'sets' then validate_sets(options) + else + validate_inventory(options, validateType) end end @@ -55,12 +74,14 @@ end -- Functions to handle the primary logic separation. ------------------------------------------------------------------------------------------------------------------- --- Function for determining and displaying which items from a player's inventory are not in their gear sets. -function validate_inventory(filter) - msg.addon_msg(123,'Checking for items in inventory that are not used in your gear sets.') - - local extra_items = search_sets_for_items_in_bag(items.inventory, filter) - +-- Function for determining and displaying which items from a player's selected repository are not in their gear sets. +function validate_inventory(filter, repository) + msg.addon_msg(123,'Checking for items in '..repository..' that are not used in your gear sets.') + + --msg.addon_msg(123,items.repository) + + local extra_items = search_sets_for_items_in_bag(items[repository], filter) + local display_list = get_item_names(extra_items):sort(insensitive_sort) display_list:map(function(item) msg.add_to_chat(120, windower.to_shift_jis((string.gsub(item, "^%l", string.upper))) ) end) msg.addon_msg(123,'Final count = '..tostring(display_list:length())) @@ -69,7 +90,7 @@ end -- Function for determining and displaying which items of a player's gear sets are not in their inventory. function validate_sets(filter) msg.addon_msg(123,'Checking for items in gear sets that are not in your inventory.') - + local missing_items = search_bags_for_items_in_set(sets, filter) local display_list = get_item_names(missing_items):sort(insensitive_sort) @@ -99,9 +120,8 @@ function get_item_name(item) elseif item.name then name = item.name end - - - local aug = item.aug and table.concat(item.aug,', ') or get_augment_string(item) + + local aug = get_augment_string(item) if aug then name = name .. ' {' .. aug .. '}' end @@ -115,7 +135,7 @@ end function get_formal_name_by_item_id(id) local shortname = get_short_name_by_item_id(id) local logname = get_log_name_by_item_id(id) - + return (#logname > #shortname) and logname or shortname end @@ -146,12 +166,12 @@ function get_augment_string(item) if started then aug_str = aug_str .. ',' end - + aug_str = aug_str.."'"..augment.."'" started = true end end - + return aug_str end end @@ -170,7 +190,7 @@ function search_sets_for_items_in_bag(bag, filter) end end end - + return extra_bag_items end @@ -179,17 +199,16 @@ function search_bags_for_items_in_set(gear_table, filter, missing_items, stack) if stack and stack:contains(gear_table) then return end if type(gear_table) ~= 'table' then return end if missing_items == nil then missing_items = S{} end - + for i,v in pairs(gear_table) do local name = (type(v) == 'table' and v.name) or v local aug = (type (v) == 'table' and (v.augments or v.augment)) - + if type(aug) == 'string' then aug = {aug} end if type(name) == 'string' and name ~= 'empty' and name ~= '' and type(i) == 'string' then if not slot_map[i] then msg.addon_msg(123,windower.to_shift_jis(tostring(i))..' contains a "name" element but is not a valid slot.') elseif tryfilter(lowercase_name(name), filter) and not find_in_equippable_inventories(name, aug) then - -- This is one spot where inventory names will be left hardcoded until an equippable bool is added to the resources missing_items:add({name=lowercase_name(name),aug=aug}) end elseif type(name) == 'table' and name ~= empty then @@ -200,7 +219,7 @@ function search_bags_for_items_in_set(gear_table, filter, missing_items, stack) stack:remove(gear_table) end end - + return missing_items end @@ -242,12 +261,12 @@ function find_in_sets(item, tab, stack) end end end - + return false end -- Utility function to help search inventory -function find_in_inv(bag, name, aug) +function find_in_inv(bag, name, aug) for _,item in ipairs(bag) do if compare_item(item, name, aug) then return true @@ -261,7 +280,7 @@ function compare_item(item, name, aug, item_short_name, item_log_name) if item.id == 0 or not res.items[item.id] then return false end - + name = lowercase_name(name) item_short_name = lowercase_name(item_short_name or get_short_name_by_item_id(item.id)) item_log_name = lowercase_name(item_log_name or get_log_name_by_item_id(item.id)) @@ -271,7 +290,7 @@ function compare_item(item, name, aug, item_short_name, item_log_name) return true end end - + return false end @@ -284,7 +303,7 @@ function tryfilter(itemname, filter) if not filter or #filter == 0 then return true end - + local pass = true for _,v in pairs(filter) do if v[1] == '-' then diff --git a/addons/GearSwap/version_history.txt b/addons/GearSwap/version_history.txt index 49e1946a6d..3d4e29ef0f 100644 --- a/addons/GearSwap/version_history.txt +++ b/addons/GearSwap/version_history.txt @@ -1,4 +1,16 @@ ------------------------------------------------- +GearSwap 0.935 - Filter enchanted items with duplicate names. +------------------------------------------------- +GearSwap 0.934 - Fixed /item command handling. +------------------------------------------------- +GearSwap 0.933 - Adjusted how item use packets are chosen. +------------------------------------------------- +GearSwap 0.932 - Fixed bug that prevented gearswap from identifying items by their bag when worn. +------------------------------------------------- +GearSwap 0.931 - Added support to exporting with custom file names. +------------------------------------------------- +GearSwap 0.930 - Fixed a problem with player[bag][item_name].count in the user environment. +------------------------------------------------- GearSwap 0.929 - Adjusted the print_set function to give preference and order to slot name keys. ------------------------------------------------- GearSwap 0.928 - Changed how the outgoing equipment chunks were parsed due to a changing understanding of how the windower packet events work. @@ -221,4 +233,4 @@ GearSwap 0.502 - Require unmasked and documented. GearSwap 0.501 - File_unload user function added. ------------------------------------------------- GearSwap 0.500 - Initial beta release -------------------------------------------------- \ No newline at end of file +------------------------------------------------- diff --git a/addons/InfoBar/InfoBar.lua b/addons/InfoBar/InfoBar.lua new file mode 100644 index 0000000000..8b03d0ef92 --- /dev/null +++ b/addons/InfoBar/InfoBar.lua @@ -0,0 +1,276 @@ +--[[Copyright © 2018, Kenshi +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 InfoBar 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 KENSHI 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 = 'Infobar' +_addon.author = 'Kenshi' +_addon.version = '1.0' +_addon.commands = {'ib', 'infobar'} + +config = require('config') +texts = require('texts') +require('vectors') +res = require('resources') +require('sqlite3') + +defaults = {} +defaults.NoTarget = "${name} (${main_job}${main_job_level}/${sub_job}${sub_job_level}) (${x},${y},${z})" +defaults.TargetPC = "${name}" +defaults.TargetNPC = "${name}" +defaults.TargetMOB = "${name}" +defaults.display = {} +defaults.display.pos = {} +defaults.display.pos.x = 0 +defaults.display.pos.y = 0 +defaults.display.bg = {} +defaults.display.bg.red = 0 +defaults.display.bg.green = 0 +defaults.display.bg.blue = 0 +defaults.display.bg.alpha = 102 +defaults.display.text = {} +defaults.display.text.font = 'Consolas' +defaults.display.text.red = 255 +defaults.display.text.green = 255 +defaults.display.text.blue = 255 +defaults.display.text.alpha = 255 +defaults.display.text.size = 12 + +settings = config.load(defaults) + +box = texts.new("", settings.display, settings) + +local infobar = {} +infobar.new_line = '\n' + +windower.register_event('load',function() + db = sqlite3.open(windower.addon_path..'/database.db') + notesdb = sqlite3.open(windower.addon_path..'/notes.db') + notesdb:exec('CREATE TABLE IF NOT EXISTS notes(name TEXT primary key, note TEXT)') + if not windower.ffxi.get_info().logged_in then return end + local target = windower.ffxi.get_mob_by_target('st') or windower.ffxi.get_mob_by_target('t') or windower.ffxi.get_player() + get_target(target.index) +end) + +windower.register_event('unload',function() + db:close() + notesdb:close() +end) + +function getDegrees(value) + return math.round(360 / math.tau * value) +end + +local dir_sets = L{'W', 'WNW', 'NW', 'NNW', 'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W'} +function DegreesToDirection(val) + return dir_sets[math.round((val + math.pi) / math.pi * 8) + 1] +end + +function get_db(target, zones, level) + local query = 'SELECT * FROM "monster" WHERE name = "'..target..'" AND zone = "'..zones..'"' + local MOB_infobar = {} + box:bold(false) + + if db:isopen() and query then + for id,name,family,job,zone,isaggressive,islinking,isnm,isfishing,levelmin,levelmax,sight,sound,magic,lowhp,healing,ts,th,scent,weakness,resistances,immunities,drops,stolen,spawn,spawntime in db:urows(query) do + if name == target and zone == zones then + MOB_infobar.family = family or '' + MOB_infobar.job = job or '' + MOB_infobar.levelrange = levelmin and levelmax and levelmin.."-"..levelmax or '' + MOB_infobar.weakness = weakness or '' + MOB_infobar.resistances = resistances or '' + MOB_infobar.immunities = immunities or '' + MOB_infobar.drops = drops or '' + MOB_infobar.stolen = stolen or '' + MOB_infobar.spawns = spawn or '' + MOB_infobar.spawntime = spawntime or '' + if isaggressive == 1 then + MOB_infobar.isagressive = 'A' + if type(levelmax) == 'number' and (level - levelmax) <= 10 then + box:bold(true) + end + else + MOB_infobar.isagressive = 'NA' + end + MOB_infobar.islinking = islinking == 1 and 'L' or 'NL' + MOB_infobar.isnm = isnm == 1 and 'NM' or 'No NM' + MOB_infobar.isfishing = isfishing == 1 and 'F' or 'NF' + local detect = L{ + sight == 1 and 'S' or '', + sound == 1 and 'H' or '', + magic == 1 and 'M' or '', + lowhp == 1 and 'HP' or '', + healing == 1 and 'R' or '', + ts == 1 and 'TS' or '', + th == 1 and 'TH' or '', + scent == 1 and 'Sc' or '', + } + MOB_infobar.detect = detect:filter(-''):concat(',') + end + end + end + box:update(MOB_infobar) +end + +function get_notes(target) + local statement = notesdb:prepare('SELECT * FROM "notes" WHERE name = ?;') + if notesdb:isopen() and statement then + statement:bind(1, target) + for name, note in statement:urows(query, { target }) do + if name == target then + return note or nil + end + end + end +end + +function get_target(index) + local player = windower.ffxi.get_player() + local target = windower.ffxi.get_mob_by_target('st') or windower.ffxi.get_mob_by_target('t') or player + infobar.name = target.name + infobar.id = target.id + infobar.index = target.index + infobar.notes = get_notes(target.name) + if index == 0 or index == player.index then + infobar.main_job = player.main_job + infobar.main_job_level = player.main_job_level + infobar.sub_job = player.sub_job + infobar.sub_job_level = player.sub_job_level + box:color(255,255,255) + box:bold(false) + box:text(settings.NoTarget) + else + if target.spawn_type == 13 or target.spawn_type == 14 or target.spawn_type == 9 or target.spawn_type == 1 then + box:bold(false) + if target.spawn_type == 1 then + box:color(255,255,255) + else + box:color(128,255,255) + end + box:text(settings.TargetPC) + elseif target.spawn_type == 2 or target.spawn_type == 34 then + box:color(128,255,128) + box:text(settings.TargetNPC) + box:bold(false) + elseif target.spawn_type == 16 then + local zone = res.zones[windower.ffxi.get_info().zone].name + box:color(255,255,128) + box:text(settings.TargetMOB) + get_db(target.name, zone, player.main_job_level) + end + end + box:update(infobar) +end + +windower.register_event('incoming chunk',function(id,org,modi,is_injected,is_blocked) + if id == 0xB then + zoning_bool = true + elseif id == 0xA then + zoning_bool = false + end +end) + +windower.register_event('prerender', function() + local info = windower.ffxi.get_info() + + if not info.logged_in or not windower.ffxi.get_player() or zoning_bool then + box:hide() + return + end + + infobar.game_moon = res.moon_phases[info.moon_phase].name + infobar.game_moon_pct = info.moon..'%' + infobar.zone_name = res.zones[info.zone].name + + local pos = windower.ffxi.get_mob_by_target('st') or windower.ffxi.get_mob_by_target('t') or windower.ffxi.get_mob_by_target('me') + if not pos then return end + infobar.x = string.format('%0.3f', pos.x) + infobar.y = string.format('%0.3f', pos.y) + infobar.z = string.format('%0.3f', pos.z) + infobar.facing = tostring(getDegrees(pos.facing))..'°' + infobar.facing_dir = DegreesToDirection(pos.facing) + + box:update(infobar) + box:show() +end) + +windower.register_event('target change', get_target) +windower.register_event('job change', function() + get_target(windower.ffxi.get_player().index) +end) + +windower.register_event('time change', function(new, old) + local alchemy = new >= 8*60 and new <= 23*60 and 'Open' or 'Closed' + infobar.alchemy = alchemy == "Closed" and '\\cs(255,0,0)'..alchemy..'\\cr' or '\\cs(0,255,0)'..alchemy..'\\cr' + local bonecraft = new >= 8*60 and new <= 23*60 and 'Open' or 'Closed' + infobar.bonecraft = bonecraft == "Closed" and '\\cs(255,0,0)'..bonecraft..'\\cr' or '\\cs(0,255,0)'..bonecraft..'\\cr' + local clothcraft = new >= 6*60 and new <= 21*60 and 'Open' or 'Closed' + infobar.clothcraft = clothcraft == "Closed" and '\\cs(255,0,0)'..clothcraft..'\\cr' or '\\cs(0,255,0)'..clothcraft..'\\cr' + local cooking = new >= 5*60 and new <= 20*60 and 'Open' or 'Closed' + infobar.cooking = cooking == "Closed" and '\\cs(255,0,0)'..cooking..'\\cr' or '\\cs(0,255,0)'..cooking..'\\cr' + local fishing = new >= 3*60 and new <= 18*60 and 'Open' or 'Closed' + infobar.fishing = fishing == "Closed" and '\\cs(255,0,0)'..fishing..'\\cr' or '\\cs(0,255,0)'..fishing..'\\cr' + local goldsmithing = new >= 8*60 and new <= 23*60 and 'Open' or 'Closed' + infobar.goldsmithing = goldsmithing == "Closed" and '\\cs(255,0,0)'..goldsmithing..'\\cr' or '\\cs(0,255,0)'..goldsmithing..'\\cr' + local leathercraft = new >= 3*60 and new <= 18*60 and 'Open' or 'Closed' + infobar.leathercraft = leathercraft == "Closed" and '\\cs(255,0,0)'..leathercraft..'\\cr' or '\\cs(0,255,0)'..leathercraft..'\\cr' + local smithing = new >= 8*60 and new <= 23*60 and 'Open' or 'Closed' + infobar.smithing = smithing == "Closed" and '\\cs(255,0,0)'..smithing..'\\cr' or '\\cs(0,255,0)'..smithing..'\\cr' + local woodworking = new >= 6*60 and new <= 21*60 and 'Open' or 'Closed' + infobar.woodworking = woodworking == "Closed" and '\\cs(255,0,0)'..woodworking..'\\cr' or '\\cs(0,255,0)'..woodworking..'\\cr' + box:update(infobar) +end) + +windower.register_event('addon command', function(...) + local args = T{...} + if args[1] then + if args[1]:lower() == 'help' then + windower.add_to_chat(207,"Infobar Commands:") + windower.add_to_chat(207,"//ib|infobar notes add 'string'") + windower.add_to_chat(207,"//ib|infobar notes delete") + elseif args[1]:lower() == 'notes' then + local target = windower.ffxi.get_mob_by_target('t') + local tname = string.gsub(target.name, ' ', '_') + if not args[2] then + windower.add_to_chat(207,"Second argument not specified, use '//ib|infobar help' for info.") + elseif args[2]:lower() == 'add' then + if not target then windower.add_to_chat(207,"No target selected") return end + for i,v in pairs(args) do args[i]=windower.convert_auto_trans(args[i]) end + local str = table.concat(args," ",3) + notesdb:exec('INSERT OR REPLACE INTO notes VALUES ("'..target.name..'","'..str..'")') + get_target(target.index) + elseif args[2]:lower() == 'delete' then + if not target then windower.add_to_chat(207,"No target selected") return end + notesdb:exec('DELETE FROM notes WHERE name = "'..target.name..'"') + get_target(target.index) + else + windower.add_to_chat(207,"Second argument wrong, use '//ib|infobar help' for info.") + end + else + windower.add_to_chat(207,"First argument wrong, use '//ib|infobar help' for info.") + end + else + windower.add_to_chat(207,"First argument not specified, use '//ib|infobar help' for info.") + end +end) diff --git a/addons/InfoBar/ReadMe.md b/addons/InfoBar/ReadMe.md new file mode 100644 index 0000000000..c43f8b06a1 --- /dev/null +++ b/addons/InfoBar/ReadMe.md @@ -0,0 +1,46 @@ +# InfoBar # + +Displays a configurable bar showing information on your targets. + +List of variables: +${name}, ${id}, ${index}, ${x}, ${y}, ${z}, ${facing}, ${facing_dir}, ${game_moon}, ${game_moon_pct}, ${zone_name}, ${notes} +${alchemy}, ${bonecraft}, ${clothcraft}, ${cooking}, ${fishing}, ${goldsmithing}, ${leathercraft}, ${smithing}, +${woodworking} (this will show if the guild shops are closed or open) +player only variables: ${main_job}, ${main_job_level}, ${sub_job}, ${sub_job_level} +mob only variables: ${family}, ${job}, ${levelrange}, ${weakness}, ${resistances}, +${immunities}, ${drops}, ${stolen}, ${spawns}, ${spawntime}, ${isagressive}, +${islinking}, ${isnm}, ${isfishing}, ${detect} + +Adding variables: +To add variables open the settings.xml in the data folder with an editor and add the variables as you wish +to the NoTarget (when you have no target or target yourself), TargetPC (you target another player), +TargetNPC (you target a npc) , TargetMob (you target a mob) tags. +You can also add normal strings to them, for example Name: ${name} + +---- + +### Commands: ### + +#### help #### + +``` +//ib|infobar help +``` + +Shows a list of commands. + +#### notes add #### + +``` +//ib|infobar notes add +``` + +Defines a note to the current target. + +#### notes delete #### + +``` +//ib|infobar notes delete +``` + +Delete a note to the current target that was defined previously. diff --git a/addons/InfoBar/database.db b/addons/InfoBar/database.db new file mode 100644 index 0000000000..2127d6e87d Binary files /dev/null and b/addons/InfoBar/database.db differ diff --git a/addons/JobChange/README.md b/addons/JobChange/README.md new file mode 100644 index 0000000000..369c22a70e --- /dev/null +++ b/addons/JobChange/README.md @@ -0,0 +1,15 @@ +Job Change AddOn. + +Allows command line job change as long as you're within 6 yalms of a Job Change NPC. + +Usage: +* //jc main job - change just main job +* //jc sub job - change just sub job +* //jc main/sub - change both jobs at the same time. +* //jc reset (Resets JA's by changing your sub job off and back) + + +If you are already the slot and job you want (IE you're already WAR and want to change MAIN to war) we'll temp-change to another job and change back to WAR. + +If your sub or main conflicts with the target job change (IE: You're main WAR and want to change to sub WAR) we'll temp-change MAIN to another job (random starter), then change sub to WAR. + diff --git a/addons/JobChange/jobchange.lua b/addons/JobChange/jobchange.lua new file mode 100644 index 0000000000..81e6ff52d8 --- /dev/null +++ b/addons/JobChange/jobchange.lua @@ -0,0 +1,227 @@ +--[[ +Copyright © 2017, Sammeh of Quetzalcoatl +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 JobChange 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 Sammeh 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 = 'Job Change' +_addon.author = 'Sammeh; Akaden' +_addon.version = '1.0.4' +_addon.command = 'jc' + +-- 1.0.1 first release +-- 1.0.2 added 'reset' command to simply reset to existing job. Changes sub job to a random starting job and back. +-- 1.0.3 Code clean-up +-- 1.0.4 Added /jc main/sub command and organized solve for fewest changes. + +require('tables') +packets = require('packets') +res = require ('resources') + +local temp_jobs = T { 'NIN', 'DNC', 'WAR', 'MNK', 'WHM', 'BLM', 'RDM', 'THF' } +local mog_zones = S { 'Selbina', 'Mhaura', 'Tavnazian Safehold', 'Nashmau', 'Rabao', 'Kazham', 'Norg', 'Walk of Echoes [P1]', 'Walk of Echoes [P2]' } +local moogles = S { 'Moogle', 'Nomad Moogle', 'Green Thumb Moogle', 'Pilgrim Moogle' } + +local log = function(msg) + windower.add_to_chat(4,'JobChange: '..msg) +end + +local jobchange = function(job, main) + local packet = packets.new('outgoing', 0x100, { + [(main and 'Main' or 'Sub')..' Job'] = job, + }) + packets.inject(packet) +end + +local find_conflict = function(job_name, p) + if p.main_job == job_name:upper() then + return 'main' + end + if p.sub_job == job_name:upper() then + return 'sub' + end +end + +injected_poke = false +local poke = function(npc) + local p = packets.new('outgoing', 0x1a, { + ["Target"] = npc.id, + ["Target Index"] = npc.index, + }) + injected_poke = true + packets.inject(p) +end +windower.register_event('incoming chunk',function(id,data,modified,injected,blocked) + local p = packets.parse('incoming',data) + if id == 0x02E and injected_poke then + injected_poke = false + return true + end +end) + +local find_temp_job = function(p) + for _, job_name in ipairs(temp_jobs) do + if not find_conflict(job_name, p) and p.jobs[job_name:upper()] > 0 then + for index,value in pairs(res.jobs) do + if value.ens == job_name then + return index + end + end + end + end +end + +local find_job = function(job,p) + if job == nil then return nil end + local jobLevel = p.jobs[job:upper()] + for index,value in pairs(res.jobs) do + if value.ens:lower() == job and jobLevel > 0 then + return index + end + end +end + +local find_job_change_npc = function() + local info = windower.ffxi.get_info() + if not (info.mog_house or mog_zones:contains(res.zones[info.zone].english)) then + log('Not in a zone with a Change NPC') + return + end + + for _, v in pairs(windower.ffxi.get_mob_array()) do + if v.distance < 36 and v.valid_target and moogles:contains(v.name) then + return v + end + end +end + +windower.register_event('addon command', function(command, ...) + local p = windower.ffxi.get_player() + local args = L{...} + local job = '' + if args[1] then + job = args[1]:lower() + end + local main = nil + local sub = nil + if command:lower() == 'main' then + main = job + if main and main:upper() == p.main_job then main = nil end + elseif command:lower() == 'sub' then + sub = job + if sub and sub:upper() == p.sub_job then main = nil end + elseif command:lower() == 'reset' then + log('Resetting Job') + sub = p.sub_job:lower() + elseif command:contains('/') or command:contains('\\') then + command = command:gsub('\\','/') + local js = command:split('/') + main = (js[1] ~= '' and js[1] or nil) + sub = (js[2] ~= '' and js[2] or nil) + -- remove identicals. + if main and main:upper() == p.main_job then main = nil end + if sub and sub:upper() == p.sub_job then sub = nil end + elseif command ~= nil and command ~= '' then + main = command:lower() + if main and main:upper() == p.main_job then main = nil end + else + log('Syntax: //jc main|sub JOB -- Chnages main or sub to target JOB') + log('Syntax: //jc main/sub -- Changes main and sub') + log('Syntax: //jc reset -- Resets Current Job') + return + end + + local changes = T{} + + local main_id = find_job(main, p) + if main ~= nil and main_id == nil then + log('Could not change main job to to '..main:upper()..' ---Mistype|NotUnlocked') + return + end + local sub_id = find_job(sub, p) + if sub ~= nil and sub_id == nil then + log('Could not change sub job to to '..sub:upper()..' ---Mistype|NotUnlocked') + return + end + + if main_id == nil and sub_id == nil then + log('No change required.') + return + end + + if main_id ~= nil and main:upper() == p.sub_job then + if sub_id ~= nil and sub:upper() == p.main_job then + changes:append({job_id=find_temp_job(p), is_conflict=true, is_main=false}) + changes:append({job_id=main_id, is_main=true}) + changes:append({job_id=sub_id, is_main=false}) + else + if sub_id ~= nil then + changes:append({job_id=sub_id, is_main=false}) + else + changes:append({job_id=find_temp_job(p), is_conflict=true, is_main=false}) + end + changes:append({job_id=main_id, is_main=true}) + end + elseif sub_id ~= nil and sub:upper() == p.main_job then + if main_id ~= nil then + changes:append({job_id=main_id, is_main=true}) + else + changes:append({job_id=find_temp_job(p), is_conflict=true, is_main=true}) + end + changes:append({job_id=sub_id, is_main=false}) + else + if main_id ~= nil then + if main:upper() == p.main_job then + changes:append({job_id=find_temp_job(p), is_conflict=true, is_main=true}) + end + changes:append({job_id=main_id, is_main=true}) + end + if sub_id ~= nil then + if sub:upper() == p.sub_job then + changes:append({job_id=find_temp_job(p), is_conflict=true, is_main=false}) + end + changes:append({job_id=sub_id, is_main=false}) + end + end + + local npc = find_job_change_npc() + if npc then + if npc.name == 'Nomad Moogle' or npc.name == 'Pilgrim Moogle'then + poke(npc) + coroutine.sleep(1) -- the moogles don't return an 0x032~0x034 so can't job change in response to an incoming menu packet. + end + for _, change in ipairs(changes) do + if change.is_conflict then + log('Conflict with '..(change.is_main and 'main' or 'sub')..' job. Changing to: '..res.jobs[change.job_id].ens) + else + log('Changing '..(change.is_main and 'main' or 'sub')..' job to: '..res.jobs[change.job_id].ens) + end + jobchange(change.job_id, change.is_main) + coroutine.sleep(0.5) + end + else + log('Not close enough to a Moogle!') + end +end) diff --git a/addons/Lookup/Lookup.lua b/addons/Lookup/Lookup.lua new file mode 100644 index 0000000000..499f2a6016 --- /dev/null +++ b/addons/Lookup/Lookup.lua @@ -0,0 +1,248 @@ +--[[ + Copyright © 2018, Karuberu + 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 Lookup 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 THE COPYRIGHT HOLDERS OR CONTRIBUTORS 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 = 'Lookup' +_addon.author = 'Karuberu' +_addon.version = '1.0' +_addon.commands = {'lookup', 'lu'} + +config = require('config') +res = require('resources') + +settings = nil +ids = nil +last_item = nil + +function load_settings() + settings = config.load({ + default = 'ffxiclopedia'; + sites = { + ffxiclopedia = { + search = 'https://ffxiclopedia.fandom.com/wiki/Special:Search?query=${term}'; + }; + ['bg-wiki'] = { + search = 'https://www.bg-wiki.com/bg/Special:Search?go=Go&search=${term}'; + }; + ffxidb = { + item = 'http://www.ffxidb.com/items/${term}'; + zone = 'http://www.ffxidb.com/zones/${term}'; + search = 'http://www.ffxidb.com/search?q=${term}'; + }; + ffxiah = { + item = 'http://www.ffxiah.com/item/${term}'; + search = 'http://www.ffxiah.com/search/item?q=${term}'; + }; + ffxiahplayer = { + search = 'https://www.ffxiah.com/search/player?name=${term}'; + }; + google = { + search = 'https://www.google.com/search?q=${term}'; + }; + ffxi = { redirect = 'ffxiclopedia'; }; + wikia = { redirect = 'ffxiclopedia'; }; + bgwiki = { redirect = 'bg-wiki'; }; + bg = { redirect = 'bg-wiki'; }; + db = { redirect = 'ffxidb'; }; + ah = { redirect = 'ffxiah'; }; + ffxiahp = { redirect = 'ffxiahplayer'; }; + ahp = { redirect = 'ffxiahplayer'; }; + }; + }) +end + +-- Creates a list of item and zone ids by name for quicker lookup by name +function initialize_ids() + ids = { + items = {}; + zones = {}; + } + for item in res.items:it() do + ids.items[item.name] = item.id + ids.items[item.name_log] = item.id + end + for zone in res.zones:it() do + ids.zones[zone.name] = zone.id + end +end + +function get_id(name) + if id == nil then + return {} + end + return { + item = ids.items[name]; + zone = ids.zones[name]; + } +end + +function get_name(id, list) + if id == nil then + return nil + end + return (list[id] or {}).name +end + +-- Converts auto-translate strings to plain text. +-- If the string is not an auto-translate string, the original string is returned. +function translate(str) + return windower.convert_auto_trans(str) +end + +-- Checks to see if the string is a selector (enclosed by <>) and returns a replacement. +-- If the string is not a selector, the original string is returned. +function parse_selection(str) + local target = str:match('<(.+)>') + if target == nil then + return str + end + + -- custom selection handlers + if target == 'job' or target == 'mjob' then + return windower.ffxi.get_player().main_job_full + elseif target == 'sjob' then + return windower.ffxi.get_player().sub_job_full + elseif target == 'zone' then + if windower.ffxi.get_info().mog_house then + return 'Mog House' + else + return get_name(windower.ffxi.get_info().zone, res.zones) + end + elseif target == 'item' then + return get_name(last_item, res.items) + end + -- default to windower's selection handlers + return (windower.ffxi.get_mob_by_target(str) or {}).name +end + +function set_default_site(command_modifier, site) + settings.default = site + if command_modifier == 'player' or command_modifier == 'p' then + -- save only for the current character + settings:save() + else + -- save for all characters + settings:save('all') + end +end + +function modify_site_settings(site, type, url) + if url == 'remove' then + url = nil + end + settings.sites[site][type] = url +end + +function set_last_item(bag, index, id, count) + if bag == 0 then + last_item = id + end +end + +-- Replaces the named parameters in the url +function format_url(url, term) + if term == nil then + return term + end + return url:gsub('${term}', '%s':format(term)) +end + +function get_site(command) + local site = settings.sites[command] + if site ~= nil and site.redirect ~= nil then + site = settings.sites[site.redirect] + end + return site +end + +function get_url(site, term) + term = translate(term) + term = parse_selection(term) + local id = get_id(term) + if id.item ~= nil and site.item ~= nil then + url = format_url(site.item, id.item) + elseif id.zone ~= nil and site.zone ~= nil then + url = format_url(site.zone, id.zone) + else + url = format_url(site.search, term) + end + return url +end + +function process_command(...) + -- get the first argument and set it as the command for now + local command = ({...}[1] or ''):lower() + + if command == 'default' then + local command_modifier, default_site + if {...}[3] ~= nil then + -- if there are three or more arguments, the second one is the modifier + command_modifier = {...}[2] + default_site = {...}[3] + else + default_site = {...}[2] + end + set_default_site(command_modifier, default_site) + return + elseif command == 'site' then + local site = {...}[2] + local type = {...}[3] + local url = {...}[4] + modify_site_settings(site, type, url) + return + end + + local term; + if {...}[2] ~= nil then + -- if there are two arguments, the first is the command and the second the term + command = {...}[1] + term = {...}[2] + else + -- otherwise, just a term is provided, so use the default command + command = settings.default + term = {...}[1] + end + if term == nil then + return + end + + local site = get_site(command:lower()) + if site == nil then + return + end + + local url = get_url(site, term) + if url == nil then + return + end + windower.open_url(url) +end + +load_settings() +initialize_ids() + +windower.register_event('add item', set_last_item) +windower.register_event('addon command', process_command) diff --git a/addons/Lookup/README.md b/addons/Lookup/README.md new file mode 100644 index 0000000000..d091c0e983 --- /dev/null +++ b/addons/Lookup/README.md @@ -0,0 +1,147 @@ +# Lookup +A simple [Windower4](http://www.windower.net/) addon that looks up search terms through in-game commands. + +The default search is performed with the following command: +``` +//lookup "Search Term" +``` +Alternatively, the shorthand `lu` can be used: +``` +//lu "Search Term" +``` + +Running this command will open up the search in your default browser. + +The search term can be plain text, auto-translate text, or one of the available [selectors](#selectors). If the search term contains a space, it must be surrounded in quotes (this does not apply to selectors). + +The default search sites are [FFXIclopedia](http://ffxiclopedia.wikia.com/), [BGWiki](http://www.bg-wiki.com), [FFXIAH](http://www.ffxiah.com), [FFXIDB](http://www.ffxidb.com), and [Google](http://www.google.com). See the [site command](#site) for how to add additional sites. + +See the [commands](#commands) section for a list of all available commands. + +## Selectors +Selectors can be used in place of plain text search terms. They are very useful for quickly getting information about something in the environment or a recently obtained item. + +The following selectors are accepted by this addon: + +| Selector | Replacement | +|----------|-------------| +| ``
`` | The current player's main job. | +| `` | The current player's subjob. | +| `` | The current area/zone. | +| `` | The last item placed in the player's inventory, including items moved from other bags. | + +The selectors found in [Windower's documentation](https://github.com/Windower/Lua/wiki/FFXI-Functions#windowerffxiget_mob_by_targettarget) are also accepted. Some of the more useful selectors are listed below, for convenience: + +| Selector | Replacement | +|----------|-------------| +| `` | The current target's name. | +| `` | The current battle target'name . | +| `` | The name of the current player's pet. | +| `` | The current player's name. | +| `` | The name of the player that last sent a tell to you. | + +## Commands +``` +//lookup "Search Term" +``` +Searches for the term on the default site. The default site is set to "ffxiclopedia" initially, but can be changed with the "default" command. + +Alternatively, the shorthand `lu` can be used: +``` +//lu "Search Term" +``` + +#### Default +``` +//lookup default "site" +``` +Sets the default site to search with. Saved in the global settings (not character-specific). + +``` +//lookup default player "site" +``` +``` +//lookup default p "site" +``` +Saves the default site only for the current player. + +#### Site +``` +//lookup site "site" search "http://www.example.com/search?q=${term}" +``` +Adds or modifies the site lookup capability. + +The second argument, `"site"` is the site that you're modifying. For example, specifying `"ffxiclopedia"` would modify the settings for `ffxiclopedia` searches. New sites can also be added this way. + +The third argument, `search`, can be substituted for `zone` or `item` if the site supports zone or item ids in its url. + +The last argument is the url of the search. The `${term}` in the url will be substituted for the search term when a lookup is performed. + +``` +//lookup site "site" remove +``` +Removes all lookup capability for the specified site (`"site"`). + +``` +//lookup site "site" search remove +``` +Removes the `search` lookup capability for the specified site (`"site"`). The `search` argument can also be substituted for `zone` or `item`. + +#### FFXIclopedia +``` +//lookup ffxiclopedia "Search Term" +``` +``` +//lookup ffxi "Search Term" +``` +``` +//lookup wikia "Search Term" +``` +Searches for the term on [FFXIclopedia](http://ffxiclopedia.wikia.com/). + +#### BGWiki +``` +//lookup bg-wiki "Search Term" +``` +``` +//lookup bgwiki "Search Term" +``` +``` +//lookup bg "Search Term" +``` +Searches for the term on [BGWiki](http://www.bg-wiki.com). + +#### FFXIAH +``` +//lookup ffxiah "Item" +``` +``` +//lookup ah "Item" +``` +Searches for the item on [FFXIAH](http://www.ffxiah.com). + +``` +//lookup ffxiahplayer "Player" +``` +``` +//lookup ffxiahp "Player" +``` +``` +//lookup ahp "Player" +``` +Searches for the player on [FFXIAH](http://www.ffxiah.com). + +#### FFXIDB +``` +//lookup ffxidb "Search Term" +``` +``` +//lookup db "Search Term" +``` +Searches for the term on [FFXIDB](http://www.ffxidb.com). + +#### Google +``` +//lookup google "Search Term" +``` +Searches for the term on [Google](http://www.google.com). diff --git a/addons/MountMuzzle/LICENSE b/addons/MountMuzzle/LICENSE new file mode 100644 index 0000000000..1b2e964655 --- /dev/null +++ b/addons/MountMuzzle/LICENSE @@ -0,0 +1,25 @@ +Copyright © 2018, Sjshovan (Apogee) +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 Mount Muzzle 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 Sjshovan (Apogee) 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. \ No newline at end of file diff --git a/addons/MountMuzzle/README.md b/addons/MountMuzzle/README.md new file mode 100644 index 0000000000..6345213471 --- /dev/null +++ b/addons/MountMuzzle/README.md @@ -0,0 +1,238 @@ +**Author:** [Sjshovan (Apogee)](https://github.com/Ap0gee) +**Version:** v0.9.5 + + +# Mount Muzzle + +> A Windower 4 addon that allows the user to change or remove the default mount music in Final Fantasy 11 Online. + + +### Table of Contents + +- [Prerequisites](#prerequisites) +- [Installation](#installation) +- [Aliases](#aliases) +- [Usage](#usage) +- [Commands](#commands) +- [Support](#support) +- [Change Log](#change-log) +- [Known Issues](#known-issues) +- [TODOs](#todos) +- [License](#license) + +___ +### Prerequisites +1. [Final Fantasy 11 Online](http://www.playonline.com/ff11us/index.shtml) +2. [Windower 4](http://windower.net/) + +___ +### Installation + +**Windower:** +1. Navigate to the `Addons` section at the top of Windower. +2. Locate the `MountMuzzle` addon. +3. Click the download button. +4. Ensure the addon is switched on. + +**Manual:** +1. Navigate to . +2. Click on `Releases`. +3. Click on the `Source code (zip)` link within the latest release to download. +4. Extract the zipped folder to `Windower4/addons/`. +5. Rename the folder to remove the version tag (`-v0.9.5`). The folder should be named `MountMuzzle`. + +___ +### Aliases +The following aliases are available to Mount Muzzle commands: + +**mountmuzzle:** muzzle | mm +**list:** l +**set:** s +**get:** g +**default:** d +**unload:** u +**reload:** r +**about:** a +**silent:** s +**mount:** m +**chocobo:** c +**zone:** z +**help:** h + + ___ +### Usage + +Manually load the addon by using one of the following commands: + + //lua load mountmuzzle + //lua l mountmuzzle + +___ +### Commands + +**help** + +Displays available Mount Muzzle commands. Below are the equivalent ways of calling the command: + + //mountmuzzle help + //muzzle help + //mm help + //mountmuzzle h + //muzzle h + //mm h + +**list** + +Displays the available muzzle types. Below are the equivalent ways of calling the command: + + //mountmuzzle list + //muzzle list + //mm list + //mm l + +**set _\_** + +Sets the current muzzle to the given muzzle type. This command takes a single argument represented by ``. Below are the equivalent ways of calling the command: + + //mountmuzzle set + //muzzle set + //mm set + //mm s + +Here are some usage examples for the **set _\_** command: `mm set silent` and `muzzle set zone` etc... + +**get** + +Displays the current muzzle that is set. Below are the equivalent ways of calling the command: + + //mountmuzzle get + //muzzle get + //mm get + //mm g + +**default** + +Sets the current muzzle to the default muzzle type: `Silent`. Below are the equivalent ways of calling the command: + + //mountmuzzle default + //muzzle default + //mm default + //mm d + +**unload** + +Unloads the Mount Muzzle addon. Below are the equivalent ways of calling the command: + + //mountmuzzle unload + //muzzle unload + //mm unload + //mm u + +**reload** + +Reloads the Mount Muzzle addon. Below are the equivalent ways of calling the command: + + //mountmuzzle reload + //muzzle reload + //mm reload + //mm r + +**about** + +Displays information about the Mount Muzzle addon. Below are the equivalent ways of calling the command: + + //mountmuzzle about + //muzzle about + //mm about + //mm a + +___ +### Support +**Having Issues with this addon?** +* Please let me know [here](https://github.com/Ap0gee/MountMuzzle/issues/new). + +**Have something to say?** +* Send me some feedback here: + +**Want to stay in the loop with my work?** +* You can follow me at: + +**Want to show your love and help me make more awesome stuff?** +* You can do so here: + +___ +### Change Log + +**v0.9.5** - 1/05/2019 +- **Fix:** Client sometimes crashes/locks when exiting game. +- **Update:** Silent muzzle song id changed to help prevent future game updates from overriding. +- **Update:** README Known Issues updated. +- **Update:** README TODOS updated. + +**v0.9.4** - 9/06/2018 +- **Fix:** Music wouldn't change if addon loaded while on mount. +- **Fix:** Music wouldn't change if addon unloaded while on mount. +- **Fix:** Muzzle type 'Silent' was playing incorrect track. +- **Update:** Licences now display correct addon name. +- **Update:** Muzzle type 'Normal' changed to 'Mount'. +- **Update:** Muzzle type 'Choco' changed to 'Chocobo'. +- **Update:** mountmuzzle.lua refactored and condensed. +- **Update:** README Commands updated. +- **Update:** README Installation updated. +- **Update:** README Table of Contents updated. +- **Update:** README Known Issues updated. +- **Update:** README TODOS updated. +- **Add:** New commands added (about, unload). +- **Add:** Shorthand aliases added to all commands. +- **Add:** Aliases added to README. + +**v0.9.3** - 5/31/2018 +- **Remove:** Removed /data/settings.xml file. +- **Update:** Licences now display correct author name. +- **Update:** helpers.lua now requires only colors from constants.lua. +- **Update:** constants.lua now returns table of globals for modular support. +- **Update:** mountmuzzle.lua refactored in attempt to meet merge criteria. +- **Update:** README refactored in attempt to meet merge criteria. + +**v0.9.2** - 5/24/2018 +- **Fix:** Zone music gets silenced if player enters reive on mount with zone muzzle selected. +- **Fix:** Player reaches error if no arguments are given upon invoking the addon. +- **Update:** Convert tab characters to spaces, simplify code. +- **Update:** README Usage Instructions updated. +- **Update:** README Known Issues updated. +- **Add:** Table of Contents added to README. +- **Add:** Prerequisites added to README. +- **Add:** Installation added to README. +- **Add:** Support added to README. +- **Add:** License added to README. + +**v0.9.1** - 5/22/2018 +- **Fix:** Chosen music does not start upon login if mounted. +- **Fix:** Chosen music does not persist upon changing zones. +- **Add:** Known Issues added to README. +- **Add:** TODOS added to README. + +**v0.9.0** - 5/21/2018 +- Initial release + +___ +### Known Issues + +- **Issue:** If Mount Muzzle is selected to automatically load and the player is mounted upon login, there is a significant delay before the chosen music will begin to play. +- **Issue:** Upon changing zones the default music can be heard for a moment before the chosen music begins to play. +- **Issue:** Unable to correctly set mount music to original if Mount Muzzle is unloaded while mounted. +- **Issue:** Unable to alter mount music upon addon unload through the Windower `exit` command, which causes client to crash. No known viable alternatives. +___ +### TODOs + +- **TODO:** Investigate alternative methods for music change as packet injection/swap allows the player to hear the default music upon zone change and login, regardless of chosen music. +- **TODO:** Investigate methods for determining which mount type the player is on when loading/unloading Mount Muzzle. +- **TODO:** Investigate ways to prevent packet injection client crash/lock within unload event if triggered through Windower `exit` command. +___ + +### License + +Copyright © 2018, [Sjshovan (Apogee)](https://github.com/Ap0gee). +Released under the [BSD License](LICENSE). + +*** \ No newline at end of file diff --git a/addons/MountMuzzle/constants.lua b/addons/MountMuzzle/constants.lua new file mode 100644 index 0000000000..dfd66a7d6c --- /dev/null +++ b/addons/MountMuzzle/constants.lua @@ -0,0 +1,111 @@ +--[[ +Copyright © 2018, Sjshovan (Apogee) +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 Mount Muzzle 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 Sjshovan (Apogee) 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. +--]] + +packets = { + inbound = { + music_change = { + id = 0x05F + }, + zone_update = { + id = 0x00A + } + }, + outbound = { + action = { + id = 0x1A, + categories = { + mount = 0x1A, + unmount = 0x12 + }, + } + }, +} + +player = { + statuses = { + mounted = 85 + }, + buffs = { + reiveMark = 511, + mounted = 252 + } +} + +music = { + songs = { + silent = 9999, + mount = 84, + chocobo = 212, + zone = 0, + }, + types = { + mount = 4, + idle_day = 0, + idle_night = 1 + } +} + +colors = { + primary = 200, + secondary = 207, + info = 0, + warn = 140, + danger = 167, + success = 158 +} + +muzzles = { + silent = { + name = 'silent', + song = music.songs.silent, + description = 'No Music (Default)' + }, + mount = { + name = 'mount', + song = music.songs.mount, + description = 'Mount Music' + }, + chocobo = { + name = 'chocobo', + song = music.songs.chocobo, + description = 'Chocobo Music' + }, + zone = { + name = 'zone', + song = music.songs.zone, + description = 'Current Zone Music' + } +} + +return { + packets = packets, + player = player, + music = music, + colors = colors, + muzzles = muzzles +} \ No newline at end of file diff --git a/addons/MountMuzzle/helpers.lua b/addons/MountMuzzle/helpers.lua new file mode 100644 index 0000000000..000a65e929 --- /dev/null +++ b/addons/MountMuzzle/helpers.lua @@ -0,0 +1,80 @@ +--[[ +Copyright © 2018, Sjshovan (Apogee) +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 Mount Muzzle 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 Sjshovan (Apogee) 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. +--]] + +local colors = require("constants").colors + +function buildHelpCommandEntry(command, description) + local short_name = "mm":color(colors.primary) + local command = command:color(colors.secondary) + local sep = "=>":color(colors.primary) + local description = description:color(colors.info) + + return "%s %s %s %s":format(short_name, command, sep, description) +end + +function buildHelpTypeEntry(name, description) + local name = name:color(colors.secondary) + local sep = "=>":color(colors.primary) + local description = description:color(colors.info) + + return "%s %s %s":format(name, sep, description) +end + +function buildHelpTitle(context) + local context = context:color(colors.danger) + + return "%s Help: %s":color(colors.primary):format(_addon.name, context) +end + +function buildHelpSeperator(character, count) + local sep = '' + + for i = 1, count do + sep = sep .. character + end + + return sep:color(colors.warn) +end + +function buildCommandResponse(message, success) + local response_color = colors.success + local response_type = 'Success' + + if not success then + response_type = 'Error' + response_color = colors.danger + end + + return "%s: %s":format(response_type:color(response_color), message) +end + +function displayResponse(response, color) + color = color or colors.info + windower.add_to_chat(color, response) + windower.console.write(response:strip_colors()) +end \ No newline at end of file diff --git a/addons/MountMuzzle/mountmuzzle.lua b/addons/MountMuzzle/mountmuzzle.lua new file mode 100644 index 0000000000..95ab08037b --- /dev/null +++ b/addons/MountMuzzle/mountmuzzle.lua @@ -0,0 +1,261 @@ +--[[ +Copyright © 2018, Sjshovan (Apogee) +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 Mount Muzzle 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 Sjshovan (Apogee) 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 = 'Mount Muzzle' +_addon.description = 'Change or remove the default mount music.' +_addon.author = 'Sjshovan (Apogee) sjshovan@gmail.com' +_addon.version = '0.9.5' +_addon.commands = {'mountmuzzle', 'muzzle', 'mm'} + +local _logger = require('logger') +local _config = require('config') +local _packets = require('packets') + +require('constants') +require('helpers') + +local needs_inject = false + +local defaults = { + muzzle = muzzles.silent.name +} + +local settings = _config.load(defaults) + +local help = { + commands = { + buildHelpSeperator('=', 26), + buildHelpTitle('Commands'), + buildHelpSeperator('=', 26), + buildHelpCommandEntry('list', 'Display the available muzzle types.'), + buildHelpCommandEntry('set ', 'Set the current muzzle to the given muzzle type.'), + buildHelpCommandEntry('get', 'Display the current muzzle.'), + buildHelpCommandEntry('default', 'Set the current muzzle to the default (Silent).'), + buildHelpCommandEntry('unload', 'Unload Mount Muzzle.'), + buildHelpCommandEntry('reload', 'Reload Mount Muzzle.'), + buildHelpCommandEntry('about', 'Display information about Mount Muzzle.'), + buildHelpCommandEntry('help', 'Display Mount Muzzle commands.'), + buildHelpSeperator('=', 26), + }, + types = { + buildHelpSeperator('=', 23), + buildHelpTitle('Types'), + buildHelpSeperator('=', 23), + buildHelpTypeEntry(muzzles.silent.name:ucfirst(), muzzles.silent.description), + buildHelpTypeEntry(muzzles.mount.name:ucfirst(), muzzles.mount.description), + buildHelpTypeEntry(muzzles.chocobo.name:ucfirst(), muzzles.chocobo.description), + buildHelpTypeEntry(muzzles.zone.name:ucfirst(), muzzles.zone.description), + buildHelpSeperator('=', 23), + }, + about = { + buildHelpSeperator('=', 23), + buildHelpTitle('About'), + buildHelpSeperator('=', 23), + buildHelpTypeEntry('Name', _addon.name), + buildHelpTypeEntry('Description', _addon.description), + buildHelpTypeEntry('Author', _addon.author), + buildHelpTypeEntry('Version', _addon.version), + buildHelpSeperator('=', 23), + }, + aliases = { + muzzles = { + s = muzzles.silent.name, + m = muzzles.mount.name, + c = muzzles.chocobo.name, + z = muzzles.zone.name + } + } +} + +function display_help(table_help) + for index, command in pairs(table_help) do + displayResponse(command) + end +end + +function getMuzzle() + return settings.muzzle +end + +function getPlayerBuffs() + return T(windower.ffxi.get_player().buffs) +end + +function resolveCurrentMuzzle() + local current_muzzle = getMuzzle() + + if not muzzleValid(current_muzzle) then + current_muzzle = muzzles.silent.name + setMuzzle(current_muzzle) + displayResponse( + 'Note: Muzzle found in settings was not valid and is now set to the default (%s).':format('Silent':color(colors.secondary)), + colors.warn + ) + end + + return muzzles[current_muzzle] +end + +function setMuzzle(muzzle) + settings.muzzle = muzzle + settings:save() +end + +function playerInReive() + return getPlayerBuffs():contains(player.buffs.reiveMark) +end + +function playerIsMounted() + local _player = windower.ffxi.get_player() + + if _player then + return _player.status == player.statuses.mounted or getPlayerBuffs():contains(player.buffs.mounted) + end + + return false +end + +function muzzleValid(muzzle) + return muzzles[muzzle] ~= nil +end + +function injectMuzzleMusic() + injectMusic(music.types.mount, resolveCurrentMuzzle().song) +end + +function injectMusic(bgmType, songID) + _packets.inject(_packets.new('incoming', packets.inbound.music_change.id, { + ['BGM Type'] = bgmType, + ['Song ID'] = songID, + })) +end + +function requestInject() + needs_inject = true +end + +function handleInjectionNeeds() + if needs_inject and playerIsMounted() then + injectMuzzleMusic() + needs_inject = false; + end +end + +function tryInject() + requestInject() + handleInjectionNeeds() +end + +windower.register_event('login', 'load', 'zone change', function() + tryInject() +end) + +windower.register_event('addon command', function(command, ...) + if command then + command = command:lower() + else + return display_help(help.commands) + end + + local command_args = {...} + local respond = false + local response_message = '' + local success = true + + if command == 'list' or command == 'l' then + display_help(help.types) + + elseif command == 'set' or command == 's' then + respond = true + + local muzzle = tostring(command_args[1]):lower() + local from_alias = help.aliases.muzzles[muzzle] + + if (from_alias ~= nil) then + muzzle = from_alias + end + + if not muzzleValid(muzzle) then + success = false + response_message = 'Muzzle type not recognized.' + else + requestInject() + setMuzzle(muzzle) + response_message = 'Updated current muzzle to %s.':format(muzzle:ucfirst():color(colors.secondary)) + end + + elseif command == 'get' or command == 'g' then + respond = true + response_message = 'Current muzzle is %s.':format(getMuzzle():ucfirst():color(colors.secondary)) + + elseif command == 'default' or command == 'd' then + respond = true + requestInject() + + setMuzzle(muzzles.silent.name) + response_message = 'Updated current muzzle to the default (%s).':format('Silent':color(colors.secondary)) + + elseif command == 'reload' or command == 'r' then + windower.send_command('lua r mountmuzzle') + + elseif command == 'unload' or command == 'u' then + respond = true + response_message = 'Thank you for using Mount Muzzle. Goodbye.' + injectMusic(music.types.mount, muzzles.zone.song) + windower.send_command('lua unload mountmuzzle') + + elseif command == 'about' or command == 'a' then + display_help(help.about) + + elseif command == 'help' or command == 'h' then + display_help(help.commands) + else + display_help(help.commands) + end + + if respond then + displayResponse( + buildCommandResponse(response_message, success) + ) + end + + handleInjectionNeeds() +end) + +windower.register_event('incoming chunk', function(id, data) + if id == packets.inbound.music_change.id then + local packet = _packets.parse('incoming', data) + + if packet['BGM Type'] == music.types.mount then + packet['Song ID'] = resolveCurrentMuzzle().song + return _packets.build(packet) + end + + tryInject() + end +end) \ No newline at end of file diff --git a/addons/MountRoulette/MountRoulette.lua b/addons/MountRoulette/MountRoulette.lua new file mode 100644 index 0000000000..220cae44ec --- /dev/null +++ b/addons/MountRoulette/MountRoulette.lua @@ -0,0 +1,162 @@ +--[[ +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 Mount Roulette 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 = 'Mount Roulette' +_addon.author = 'Dean James (Xurion of Bismarck)' +_addon.version = '3.1.0' +_addon.commands = {'mountroulette', 'mr'} + +require('lists') +require('sets') +resources = require('resources') +config = require('config') +settings = config.load({ + blacklist = S{} +}) + +math.randomseed(os.time()) + +allowed_mounts = L{} +possible_mounts = L{} +for _, mount in pairs(resources.mounts) do + possible_mounts:append(mount.name:lower()) +end + +function update_allowed_mounts() + local allowed_mounts_set = S{} + local kis = windower.ffxi.get_key_items() + + for _, id in ipairs(kis) do + local ki = resources.key_items[id] + if ki.category == 'Mounts' and ki.name ~= "trainer's whistle" then -- Don't care about the quest KI + local mount_index = possible_mounts:find(function(possible_mount) + return windower.wc_match(ki.name:lower(), '♪' .. possible_mount .. '*') + end) + local mount = possible_mounts[mount_index] + + -- Add this to allowed mounts if it is not blacklisted + if not settings.blacklist:contains(mount) then + allowed_mounts_set:add(mount) + end + end + end + + allowed_mounts = L(allowed_mounts_set) +end + +update_allowed_mounts() + +windower.register_event('incoming chunk', function(id) + if id == 0x055 then --ki update + update_allowed_mounts() + end +end) + +commands = {} + +commands.mount = function() + local player = windower.ffxi.get_player() + + -- If the player is mounted, dismount now + for _, buff in pairs(player.buffs) do + if buff == 252 then --mounted buff + windower.send_command('input /dismount') + return + end + end + + if #allowed_mounts == 0 then return end + + -- Generate random number and use it to choose a mount + local mount_index = math.ceil(math.random() * #allowed_mounts) + windower.send_command('input /mount "' .. allowed_mounts[mount_index] .. '"') +end + +commands.blacklist = function(args) + local operation = args:remove(1) + + if not operation then + windower.add_to_chat(8, 'Blacklisted mounts:') + for mount in settings.blacklist:it() do + windower.add_to_chat(8, ' ' .. mount) + end + return + end + + local mount = args:concat(' '):lower() + + if not operation or not mount then + commands.help() + return + end + + if not possible_mounts:contains(mount) then + windower.add_to_chat(8, 'Unknown mount ' .. mount) + return + end + + if operation == 'add' and not settings.blacklist:contains(mount) then + for allowed_mount, index in allowed_mounts:it() do + if allowed_mount == mount then + allowed_mounts:remove(index) + end + end + settings.blacklist:add(mount) + windower.add_to_chat(8, 'The ' .. mount .. ' mount is now blacklisted') + settings:save() + elseif operation == 'remove' then + for blacklisted_mount in settings.blacklist:it() do + if blacklisted_mount == mount then + settings.blacklist:remove(mount) + end + end + allowed_mounts:append(mount) + windower.add_to_chat(8, 'The ' .. mount .. ' mount is no longer blacklisted') + settings:save() + end +end + +commands.help = function() + windower.add_to_chat(8, '---Mount Roulette---') + windower.add_to_chat(8, 'Available commands:') + windower.add_to_chat(8, '//mr mount (or just //mr) - Selects a mount at random, or dismounts if mounted') + windower.add_to_chat(8, '//mr blacklist - show blacklisted mounts') + windower.add_to_chat(8, '//mr blacklist add - blacklist a mount so it is never randomly selected') + windower.add_to_chat(8, '//mr blacklist remove - remove a mount from the blacklist') + windower.add_to_chat(8, '//mr help - displays this help') +end + +windower.register_event('addon command', function(command, ...) + command = command and command:lower() or 'mount' + + if commands[command] then + commands[command](L{...}) + else + commands.help() + end +end) diff --git a/addons/MountRoulette/README.md b/addons/MountRoulette/README.md new file mode 100644 index 0000000000..c0f8620138 --- /dev/null +++ b/addons/MountRoulette/README.md @@ -0,0 +1,37 @@ +# Final Fantasy XI Mount Roulette + +A Lua addon to summon a mount at random for Windower 4. Mimics the FFXIV Mount Roulette function. + +## Usage + +Get the addon from the addon section of the Windower launcher. + +### Summon a mount + +`//mr` (or `//mr mount`) + +This will also dismount you if you're currently mounted. + +### Add a mount to the blacklist + +`//mr blacklist add ` + +Prevents the given mount from being summoned by Mount Roulette. + +### Remove a mount from the blacklist + +`//mr blacklist remove ` + +Allows the given mount to be summoned by Mount Roulette. + +### List blacklisted mounts + +`//mr blacklist` + +### Show help and commands + +`//mr help` + +## Mount music + +In an earlier version, this addon disabled mount music. This is now removed in favour of the MountMuzzle addon. diff --git a/addons/MyHome/MyHome.lua b/addons/MyHome/MyHome.lua new file mode 100644 index 0000000000..3c4a6685c5 --- /dev/null +++ b/addons/MyHome/MyHome.lua @@ -0,0 +1,123 @@ +--[[ +Copyright © 2018, from20020516 +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 MyHome 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 from20020516 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 = 'MyHome' +_addon.author = 'from20020516' +_addon.version = '1.1.1' +_addon.commands = {'myhome','mh','warp'} + +require('logger') +extdata = require('extdata') +res_bags = require('resources').bags + +log_flag = true + +lang = string.lower(windower.ffxi.get_info().language) +item_info = { + [1]={id=28540,japanese='デジョンリング',english='"Warp Ring"',slot=13}, + [2]={id=17040,japanese='デジョンカジェル',english='"Warp Cudgel"',slot=0}, + [3]={id=4181,japanese='呪符デジョン',english='"Instant Warp"'}} + +function search_item() + if windower.ffxi.get_player().status > 1 then + log('You cannot use items at this time.') + return + end + + local item_array = {} + local get_items = windower.ffxi.get_items + local set_equip = windower.ffxi.set_equip + + for bag_id in pairs(res_bags:equippable(true)) do + local bag = get_items(bag_id) + for _,item in ipairs(bag) do + if item.id > 0 then + item_array[item.id] = item + item_array[item.id].bag = bag_id + item_array[item.id].bag_enabled = bag.enabled + end + end + end + for index,stats in pairs(item_info) do + local item = item_array[stats.id] + if item and item.bag_enabled then + local ext = extdata.decode(item) + local enchant = ext.type == 'Enchanted Equipment' + local recast = enchant and ext.charges_remaining > 0 and math.max(ext.next_use_time+18000-os.time(),0) + local usable = recast and recast == 0 + log(stats[lang],usable and '' or recast and recast..' sec recast.') + if usable or ext.type == 'General' then + if enchant and item.status ~= 5 then --not equipped + set_equip(item.slot,stats.slot,item.bag) + repeat --waiting cast delay + coroutine.sleep(1) + local ext = extdata.decode(get_items(item.bag,item.slot)) + local delay = ext.activation_time+18000-os.time() + if delay > 0 then + log(stats[lang],delay) + elseif log_flag then + log_flag = false + log('Item use within 3 seconds..') + end + until ext.usable or delay > 30 + end + windower.chat.input('/item '..windower.to_shift_jis(stats[lang])..' ') + break; + end + elseif item and not item.bag_enabled then + log('You cannot access '..stats[lang]..' from ' .. res_bags[item.bag].name ..' at this time.') + else + log('You don\'t have '..stats[lang]..'.') + end + end +end + +windower.register_event('addon command',function(...) + local args = T{...} + local cmd = args[1] + if cmd == 'all' then + windower.chat.input('//myhome') + windower.send_ipc_message('myhome') + else + local player = windower.ffxi.get_player() + local get_spells = windower.ffxi.get_spells() + local spell = S{player.main_job_id,player.sub_job_id}[4] + and (get_spells[261] and player.vitals.mp >= 100 and {japanese='デジョン',english='"Warp"'} + or get_spells[262] and player.vitals.mp >= 150 and {japanese='デジョンII',english='"Warp II"'}) + if spell then + windower.chat.input('/ma '..windower.to_shift_jis(spell[lang])..' ') + else + search_item() + end + end +end) + +windower.register_event('ipc message',function (msg) + if msg == 'myhome' then + windower.chat.input('//myhome') + end +end) diff --git a/addons/MyHome/README.md b/addons/MyHome/README.md new file mode 100644 index 0000000000..67d44fe4ee --- /dev/null +++ b/addons/MyHome/README.md @@ -0,0 +1,30 @@ +# MyHome +## English +- Automatically choose and uses a warp spell or an item. + +### Command +- `//mh` OR `//warp` +- `//mh all` OR `//warp all` will warp all characters. + + +- Priorities are: + 1. Warp - require learned and main job or sub job BLM. + 2. Warp II + 3. Warp Ring - search inventory and wardrobes. + 4. Warp Cudgel + 5. Instant Warp - search inventory. + +## 日本語 +- デジョンやデジョン系アイテムをリキャストに応じて自動で選択、使用します。 + +### Command +- `//mh` または `//warp` +- `//mh all` または `//warp all` すべての文字をワープします。 +- 優先順位: + + + 1. デジョン - 習得済かつメインまたはサポートジョブが黒魔道士 + 2. デジョンII + 3. デジョンリング - マイバッグ、またはワードローブ(1~4)を検索 + 4. デジョンカジェル + 5. 呪符デジョン - マイバッグを検索 diff --git a/addons/NoCampaignMusic/NoCampaignMusic.lua b/addons/NoCampaignMusic/NoCampaignMusic.lua new file mode 100644 index 0000000000..a45e9ff281 --- /dev/null +++ b/addons/NoCampaignMusic/NoCampaignMusic.lua @@ -0,0 +1,129 @@ +--[[ +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 No Campaign Music 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 = 'No Campaign Music' +_addon.author = 'Dean James (Xurion of Bismarck)' +_addon.version = '2.0.1' +_addon.commands = {'nocampaignmusic', 'ncm'} + +packets = require('packets') +config = require('config') + +defaults = { + Notifications = false, +} + +settings = config.load(defaults) + +campaign_id = 247 +solo_id = 101 +party_id = 215 +solo_dungeon_id = 115 +party_dungeon_id = 216 + +zone_music_map = {} +zone_music_map[80] = { 254, 254, solo_id, party_id } --Southern San d'Oria [S] +zone_music_map[81] = { 251, 251, solo_id, party_id } --East Ronfaure [S] +zone_music_map[82] = { 0, 0, solo_id, party_id } --Jugner Forest [S] +zone_music_map[83] = { 0, 0, solo_id, party_id } --Vunkerl Inlet [S] +zone_music_map[84] = { 252, 252, solo_id, party_id } --Batallia Downs [S] +zone_music_map[85] = { 44, 44, solo_dungeon_id, party_dungeon_id } --La Vaule [S] +zone_music_map[87] = { 180, 180, solo_id, party_id } --Bastok Markets [S] +zone_music_map[88] = { 253, 253, solo_id, party_id } --North Gustaberg [S] +zone_music_map[89] = { 0, 0, solo_id, party_id } --Grauberg [S] +zone_music_map[90] = { 0, 0, solo_id, party_id } --Pashhow Marshlands [S] +zone_music_map[91] = { 252, 252, solo_id, party_id } --Rolanberry Fields [S] +zone_music_map[92] = { 44, 44, solo_dungeon_id, party_dungeon_id } --Beadeaux [S] +zone_music_map[94] = { 182, 182, solo_id, party_id } --Windurst Waters [S] +zone_music_map[95] = { 141, 141, solo_id, party_id } --West Sarutabaruta [S] +zone_music_map[96] = { 0, 0, solo_id, party_id } --Fort Karugo-Narugo [S] +zone_music_map[97] = { 0, 0, solo_id, party_id } --Meriphataud Mountains [S] +zone_music_map[98] = { 252, 252, solo_id, party_id } --Sauromugue Champaign [S] +zone_music_map[99] = { 44, 44, solo_dungeon_id, party_dungeon_id } --Castle Oztroja [S] +zone_music_map[136] = { 0, 0, solo_id, party_id } --Beaucedine Glacier [S] +zone_music_map[137] = { 42, 42, solo_id, party_id } --Xarcabard [S] +zone_music_map[138] = { 43, 43, solo_dungeon_id, party_dungeon_id } --Castle Zvahl Baileys [S] +zone_music_map[155] = { 43, 43, solo_dungeon_id, party_dungeon_id } --Castle Zvahl Keep [S] +zone_music_map[164] = { 0, 0, solo_dungeon_id, party_dungeon_id } --Garlaige Citadel [S] +zone_music_map[171] = { 0, 0, solo_dungeon_id, party_dungeon_id } --Crawlers' Nest [S] +zone_music_map[175] = { 0, 0, solo_dungeon_id, party_dungeon_id } --The Eldieme Necropolis [S] + +windower.register_event('incoming chunk', function(id, data) + if id ~= 0x00A and id ~= 0x05F then return end + + local parsed = packets.parse('incoming', data) + local zone_music = zone_music_map[parsed['Zone'] or windower.ffxi.get_info().zone] + + if not zone_music then return end + + if id == 0x00A then --Zone update (zoned in) + if parsed['Day Music'] == campaign_id and zone_music then + parsed['Day Music'] = zone_music[1] + parsed['Night Music'] = zone_music[2] + parsed['Solo Combat Music'] = zone_music[3] + parsed['Party Combat Music'] = zone_music[4] + + return packets.build(parsed) + end + else --Music update (campaign possibly started/finished) + local info = windower.ffxi.get_info() + if parsed['Song ID'] == campaign_id then + + if settings.Notifications and parsed['BGM Type'] == 0 then --only log to the chat once + windower.add_to_chat(8, 'Prevented campaign music.') + end + + parsed['Song ID'] = zone_music[parsed['BGM Type'] + 1] + return packets.build(parsed) + end + end +end) + +commands = {} + +commands.notify = function() + settings.Notifications = not settings.Notifications + settings:save() + windower.add_to_chat(8, 'Campaign notifications: ' .. tostring(settings.Notifications)) +end + +commands.help = function() + windower.add_to_chat(8, 'No Campaign Music:') + windower.add_to_chat(8, ' //ncm notify - toggles campaign notifications (default false)') + windower.add_to_chat(8, ' //ncm help - shows this help') +end + +windower.register_event('addon command', function(command) + command = command and command:lower() or 'help' + + if commands[command] then + commands[command]() + else + commands.help() + end +end) diff --git a/addons/NoCampaignMusic/README.md b/addons/NoCampaignMusic/README.md new file mode 100644 index 0000000000..63ec719c04 --- /dev/null +++ b/addons/NoCampaignMusic/README.md @@ -0,0 +1,27 @@ +# FFXI - No Campaign Music + +Prevents all campaign battle music from playing in Final Fantasy XI, so you can listen to that sweet music that is normally obnoxiously interrupted. + +## Load + +``` +//lua load ncm +``` + +## Campaign notifications + +If you want to know when campaign is happening, you can toggle notifications: + +``` +//ncm notify +``` + +## Note + +When campaign music is prevented from playing (whether it's as you zone in, or campaign starts in the zone) a message will log to the chatlog stating "Prevented campaign music." This not only confirms the addon is working, but shows you there's a campaign active should you want to take part. + +## Contributing + +If you notice something not quite right, please [raise an issue](https://github.com/xurion/ffxi-no-campaign-music/issues). + +Or better yet, [pull requests](https://github.com/xurion/ffxi-no-campaign-music/pulls) are welcome! diff --git a/addons/NyzulHelper/NyzulHelper.lua b/addons/NyzulHelper/NyzulHelper.lua new file mode 100644 index 0000000000..b39e2353fe --- /dev/null +++ b/addons/NyzulHelper/NyzulHelper.lua @@ -0,0 +1,323 @@ +--[[ +Copyright © 2020, Glarin of Asura +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 NyzulHelper 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 Glarin 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 = 'NyzulHelper' +_addon.author = 'Glarin' +_addon.version = '1.0' +_addon.commands = {'nh', 'nyzulhelper'} +_addon.language = 'english' + +require('logger') +require('coroutine') + +config = require('config') +packets = require('packets') +res = require('resources') +texts = require('texts') + +defaults = {} +defaults.interval = .1 + +settings = config.load(defaults) +box = texts.new('${current_string}', settings) + +pending_color = '\\cs(255,250,120)' +warning_color = '\\cs(255,165,0)' +good_color = '\\cs(0,255,0)' +bad_color = '\\cs(255,0,0)' + +frame_time = 0 +zone_timer = 0 +end_time = nil +has_armband = false +party_size = 1 +objective = '' +floor_clear = pending_color +restriction = '' +restriction_failed = warning_color +starting_floor = 0 +current_floor = 0 +completed = 0 +floor_penalities = 0 +potential_tokens = 0 + + +-- Handle addon args +windower.register_event('addon command', function(input, ...) + + local cmd = input and input:lower() or 'help' + local args = {...} + + if cmd == 'reset' then + reset() + elseif cmd == 'show' then + box:show() + elseif cmd == 'hide' then + box:hide() + elseif cmd == 'reload' then + windower.send_command('lua reload nyzulhelper') + elseif cmd == 'help' then + windower.add_to_chat(167, 'Commands:') + windower.add_to_chat(167, ' nyzulhelper reset') + windower.add_to_chat(167, ' nyzulhelper show') + windower.add_to_chat(167, ' nyzulhelper hide') + windower.add_to_chat(167, ' nyzulhelper reload') + else + log(cmd..' command unknown.') + end + +end) + +-- Event Handlers +windower.register_event('load', function() + + local info = windower.ffxi.get_info() + if info.logged_in and info.zone == 77 then + box:show() + end + +end) + +windower.register_event('prerender', function() + + local curr = os.clock() + if curr > frame_time + settings.interval then + if end_time ~= nil and zone_timer >= 1 and zone_timer ~= (end_time - os.time()) then + zone_timer = end_time - os.time() + end + + frame_time = curr + update_box() + end + +end) + +windower.register_event('zone change',function(new, old) + + box:hide() + + if new == 72 and old == 77 then + zone_timer = 0 + has_armband = false + else + reset() + end + + if new == 77 then + box:show() + party_size = windower.ffxi.get_party_info().party1_count + end + +end) + +windower.register_event('incoming chunk', function(id, data, modified, injected, blocked) + + if id == 0x55 and windower.ffxi.get_info().zone == 72 and has_value(windower.ffxi.get_key_items(), 797) then + has_armband = true + end + +end) + +windower.register_event('incoming text', function(original, modified, mode, _, blocked) + + local info = windower.ffxi.get_info() + if not info.logged_in or info.zone ~= 77 or blocked or original == '' then + return + end + + if mode == 123 then + + if string.find(original, 'Security field malfunction') then + restriction = string.strip_format(original) + restriction_failed = bad_color + update_box() + elseif string.find(original, 'Time limit has been reduced') then + set_timer(zone_timer - tonumber(original:match('%d+')) * 60) + elseif string.find(original, 'Potential token reward reduced') then + floor_penalities = floor_penalities + 1 + end + + elseif (mode == 146 or mode == 148) and string.find(original, '(Earth time)') then + + local multiplier = 1 + if string.find(original, 'minute') then multiplier = 60 end + + set_timer(tonumber(original:match('%d+')) * multiplier) + + elseif mode == 146 then + + if string.find(original,'Floor %d+ objective complete. Rune of Transfer activated.') then + completed = completed + 1 + floor_clear = good_color + restriction = '' + restriction_failed = warning_color + calculate_tokens() + update_box() + end + + elseif mode == 148 then + + if string.find(original,'Objective:') then + if string.find(original,'Commencing') then + objective = 'Complete on-site objectives' + else + objective = string.strip_format(original:sub(11)) + end + floor_clear = pending_color + elseif string.find(original, 'archaic') then + restriction = string.strip_format(original) + elseif string.find(original,'Transfer complete. Welcome to Floor %d+.') then + current_floor = tonumber(original:match('%d+')) + resync_values() + end + + end + +end) + +function reset() + + zone_timer = 0 + end_time = nil + objective = '' + floor_clear = pending_color + restriction = '' + restriction_failed = warning_color + starting_floor = 0 + current_floor = 0 + completed = 0 + floor_penalities = 0 + potential_tokens = 0 + +end + +function has_value(list, value) + + if list ~= nil and value ~= nil then + for _, v in pairs(list) do + if v == value then + return true + end + end + end + + return false + +end + +function set_timer(remaining) + + zone_timer = remaining + end_time = os.time() + zone_timer + +end + +function get_relative_floor() + + if current_floor < starting_floor then + return current_floor + 100 + end + + return current_floor + +end + +function get_token_rate() + + local rate = 1 + if has_armband then + rate = rate + .1 + end + + if party_size > 3 then + rate = rate - ((party_size - 3 ) * .1) + end + + return rate + +end + +function resync_values() + + if starting_floor == 0 then + starting_floor = current_floor + if zone_timer == 0 then + set_timer(1800) + end + end + + local relative_floor = get_relative_floor() + if (relative_floor - starting_floor) > completed then + completed = relative_floor - starting_floor + end + + floor_penalities = 0 + +end + +function get_token_penalty(rate) + + return math.round(117 * rate) * floor_penalities + +end + +function calculate_tokens() + + local relative_floor = get_relative_floor() + local rate = get_token_rate() + + local floor_bonus = 0 + if relative_floor > 1 then + floor_bonus = (10 * math.floor((relative_floor - 1) / 5)) + end + + potential_tokens = potential_tokens + ((200 + floor_bonus) * rate) - get_token_penalty(rate) + +end + +function update_box() + + local timer_color = '' + if zone_timer < 60 then + timer_color = bad_color + end + + local lines = L{} + lines:append(' Current Floor: '..current_floor) + lines:append('\n Time Remaining: '..timer_color..os.date('%M:%S', zone_timer)..'\\cr ') + lines:append('\n Objective: '..floor_clear..objective..'\\cr ') + if restriction ~= '' then + lines:append(' Restriction: '..restriction_failed..restriction..'\\cr ') + end + lines:append('\n Floors Completed: '..completed) + lines:append(' Reward Rate: %d%%':format(get_token_rate() * 100)) + lines:append(' Potential Tokens: '..potential_tokens) + + box.current_string = lines:concat('\n') + +end diff --git a/addons/NyzulHelper/ReadMe.md b/addons/NyzulHelper/ReadMe.md new file mode 100644 index 0000000000..d0f9f85bc4 --- /dev/null +++ b/addons/NyzulHelper/ReadMe.md @@ -0,0 +1,6 @@ +**Authors:** Glarin +**Version:** 1.0 +**Date:** 7/14/2020 + +**Description:** +NyzulHelper is an addon that tracks and displays the Current Floor, Time Remaining, Objective, Floors Completed, Reward Rate, and Potenial Tokens. \ No newline at end of file diff --git a/addons/Pouches/Pouches.lua b/addons/Pouches/Pouches.lua index 815278f5cc..d935ad1868 100644 --- a/addons/Pouches/Pouches.lua +++ b/addons/Pouches/Pouches.lua @@ -58,9 +58,8 @@ end windower.register_event('addon command', function(...) local inv = windower.ffxi.get_items(0) -- get main inventory - local args = T{...}:map(string.lower) - item.name = table.concat(args," ") + item.name = windower.convert_auto_trans(table.concat({...}," ")):lower() item.count = 0 if inverted[item.name] == nil then log('Item, "'..item.name..'", does not exist.') diff --git a/addons/SetTarget/SetTarget.lua b/addons/SetTarget/SetTarget.lua new file mode 100644 index 0000000000..7d32772e2c --- /dev/null +++ b/addons/SetTarget/SetTarget.lua @@ -0,0 +1,26 @@ +local packets = require('packets') + +_addon.name = 'SetTarget' +_addon.author = 'Arcon' +_addon.commands = {'settarget', 'st'} +_addon.version = '1.0.0.0' + +windower.register_event('addon command', function(id) + id = tonumber(id) + if id == nil then + return + end + + local target = windower.ffxi.get_mob_by_id(id) + if not target then + return + end + + local player = windower.ffxi.get_player() + + packets.inject(packets.new('incoming', 0x058, { + ['Player'] = player.id, + ['Target'] = target.id, + ['Player Index'] = player.index, + })) +end) diff --git a/addons/SpellBook/SpellBook.lua b/addons/SpellBook/SpellBook.lua new file mode 100644 index 0000000000..311f287e06 --- /dev/null +++ b/addons/SpellBook/SpellBook.lua @@ -0,0 +1,447 @@ +_addon.name = 'SpellBook' +_addon.author = 'SigilBaram' +_addon.version = '1.0.1' +_addon.commands = {'spellbook','spbk'} + +require('tables') +res = require('resources') + +spell_types = { + whitemagic = { type = 'WhiteMagic', readable = 'White Magic spells' }, + blackmagic = { type = 'BlackMagic', readable = 'Black Magic spells' }, + songs = { type = 'BardSong', readable = 'Bard songs' }, + ninjutsu = { type = 'Ninjutsu', readable = 'Ninjutsu' }, + summoning = { type = 'SummonerPact', readable = 'Summoning spells' }, + bluemagic = { type = 'BlueMagic', readable = 'Blue Magic spells' }, + geomancy = { type = 'Geomancy', readable = 'Geomancy spells' }, + trusts = { type = 'Trust', readable = 'Trusts'}, + all = { type = 'all', readable = 'spells of all types'} +} + +windower.register_event('addon command', function (command, ...) + local args = L{...} + local jobs = build_job_list() + + command = command and command:lower() or 'current' + + if command == 'help' then + display_help() + elseif command == 'current' then + local player = windower.ffxi.get_player() + spells_by_current(player) + elseif command == 'main' then + local player = windower.ffxi.get_player() + local level = player.main_job_level + local job_points = player.job_points[player.main_job:lower()].jp_spent + if job_points > 99 then + level = job_points + end + level = args[1] or level + if level == 'all' then + level = 1500 + end + level = tonumber(level) + if level then + spells_by_job(player.main_job_id, level) + else + invalid_input() + end + elseif command == 'sub' then + local player = windower.ffxi.get_player() + if not player.sub_job then + windower.add_to_chat(7, "You don't have a subjob equipped.") + return + end + local level = args[1] or player.sub_job_level + if level == 'all' then + level = 1500 + end + level = tonumber(level) + if level then + spells_by_job(player.sub_job_id, level) + else + invalid_input() + end + elseif spell_types[command] then + if args[1] == 'all' then + local player = windower.ffxi.get_player() + spells_by_type(player, spell_types[command], false) + elseif args[1] == nil then + local player = windower.ffxi.get_player() + spells_by_type(player, spell_types[command], true) + else + invalid_input() + end + elseif jobs[command] then + local job = jobs[command] + local player = windower.ffxi.get_player() + local level = args[1] or player.jobs[res.jobs[job].english_short] + if level == 'all' then + level = 1500 + end + level = tonumber(level) + if level then + spells_by_job(job, level) + else + invalid_input() + end + else + invalid_input() + end +end) + +-------------------------------------------------------------------------------- +--Name: build_job_list +-------------------------------------------------------------------------------- +--Returns: +---- (table) list of jobs with short name as the key and id as the value +-------------------------------------------------------------------------------- +function build_job_list() + local jobs = {} + for id,val in pairs(res.jobs) do + jobs[val.english_short:lower()] = id + end + return jobs +end + +-------------------------------------------------------------------------------- +--Name: invalid_input +---- Display an error message for invalid input. +-------------------------------------------------------------------------------- +function invalid_input() + windower.add_to_chat(7, 'Invalid input. See //spbk help.') +end + +-------------------------------------------------------------------------------- +--Name: display_help +-- Display help text for the addon. +-------------------------------------------------------------------------------- +function display_help() + windower.add_to_chat(7, _addon.name .. ' version ' .. _addon.version) + windower.add_to_chat(7, 'Spent jp can be specified for spells learned from Gifts by entering a value of 100-1500.') + windower.add_to_chat(7, 'Spells are never given as Gifts for less than 100 jp and values under 100 are treated as level.') + windower.add_to_chat(7, '//spbk help -- Show this help text.') + windower.add_to_chat(7, '//spbk [current] -- Show learnable spells based on current main and sub job and level/jp.') + windower.add_to_chat(7, '//spbk [] -- Show missing spells for current main or sub job. Defaults to the job\'s current level/jp.') + windower.add_to_chat(7, '//spbk [] -- Show missings spells for specified job and level. Defaults to the job\'s level/jp.') + windower.add_to_chat(7, '//spbk [all] -- Show learnable spells by category. Limited to spells which are learnable, unless all is added after the category.') + windower.add_to_chat(7, 'Categories: whitemagic, blackmagic, songs, ninjustu, summoning, bluemagic, geomancy, trusts, all (Trusts are not included in all)') +end + +-------------------------------------------------------------------------------- +--Name: is_learnable +--Args: +---- player (table): player object from windower.ffxi.get_player() +---- spell (table): a spell from resources.spells +-------------------------------------------------------------------------------- +--Returns: +---- (bool) true if player has a job that is high enough level to learn spell +-------------------------------------------------------------------------------- +function is_learnable(player, spell) + local player_levels = player.jobs + for job,level in pairs(spell.levels) do + if player_levels[res.jobs[job].english_short] >= level then + return true + end + end + return false +end + +-------------------------------------------------------------------------------- +--Name: format_spell +-- Formats a spell as the spell's name followed by a list of jobs and levels +-- which would qualify to learn that spell. +--Args: +---- spell (table): a spell from resources.spells +-------------------------------------------------------------------------------- +--Returns: +---- (string) the formatted string +-------------------------------------------------------------------------------- +function format_spell(spell) + local format + + if spell.type ~= 'Trust' then + local jobs = T{} + local levels = T{} + for job_id,_ in pairs(spell.levels) do + jobs:append(job_id) + end + jobs:sort() + for _,job_id in ipairs(jobs) do + if spell.levels[job_id] <= 99 then + levels:append(res.jobs[job_id].english_short .. ' Lv.' .. + tostring(spell.levels[job_id])) + else + levels:append(res.jobs[job_id].english_short .. ' Jp.' .. + tostring(spell.levels[job_id])) + end + end + format = levels:concat(' / ') + else + format = ' ( Trust )' + end + return string.format('%-20s %s', spell.english, format) +end + +-------------------------------------------------------------------------------- +--Name: spells_by_type +-- List spells of a given type, i.e. white magic. +--Args: +---- player (T): player object from windower.ffxi.get_player() +---- spell_type (table): one of the types from spell_types global +---- learnable_only (bool): if true then the output is limited to spell for +---- which the player has a job that is high enough level +-------------------------------------------------------------------------------- +function spells_by_type(player, spell_type, learnable_only) + local missing_spells = T{} + local player_spells = windower.ffxi.get_spells() + local spell_count = 0 + + for spell_id,spell in pairs(res.spells) do + if ((spell_type.type == 'all' and spell.type ~= 'Trust') or + spell.type == spell_type.type) and + not table.empty(spell.levels) and + not player_spells[spell_id] and + (is_learnable(player, spell) or not learnable_only) and + not (spell_type.type == 'Trust' and spell.name:match('.*%(UC%)')) and + not spell.unlearnable then + + missing_spells:append(format_spell(spell)) + spell_count = spell_count + 1 + end + end + + if learnable_only then + windower.add_to_chat(7, string.format('Showing learnable %s.', + spell_type.readable)) + else + windower.add_to_chat(7, string.format('Showing all missing %s.', + spell_type.readable)) + end + + if not missing_spells:empty() then + missing_spells:sort() + for _,spell in ipairs(missing_spells) do + windower.add_to_chat(7, spell) + end + if learnable_only then + windower.add_to_chat(7,string.format( + 'List Complete. You are missing %d learnable %s.', + spell_count, spell_type.readable)) + else + windower.add_to_chat(7,string.format( + 'List Complete. You are missing %d %s.', + spell_count, spell_type.readable)) + end + else + if learnable_only then + windower.add_to_chat(7,string.format( + 'Congratulations! You know all currently learnable %s.', + spell_type.readable)) + else + windower.add_to_chat(7,string.format( + 'Congratulations! You know all %s.', + spell_type.readable)) + end + end +end + +-------------------------------------------------------------------------------- +--Name: spells_by_job +-- List unknown spells by job. +--Args: +---- job (int): the job's id +---- level_cap (int): the max level/jp required by listed spells +-------------------------------------------------------------------------------- +function spells_by_job(job, level_cap) + local missing_spells = T{} + local player_spells = windower.ffxi.get_spells() + local spell_count = 0 + + for spell_id,spell in pairs(res.spells) do + local spell_level = spell.levels[job] + if spell_level and spell_level <= level_cap and + spell.type ~= 'Trust' and not player_spells[spell_id] and + not spell.unlearnable then + + missing_spells[spell_level] = missing_spells[spell_level] or T{} + missing_spells[spell_level]:append(spell.english) + spell_count = spell_count + 1 + end + end + + if not missing_spells:empty() then + if level_cap > 99 then + windower.add_to_chat(7, string.format( + 'Showing missing spells for %s up to %d spent job points.', + res.jobs[job].en, level_cap)) + else + windower.add_to_chat(7, string.format( + 'Showing missing spells for %s up to level %d.', + res.jobs[job].en, level_cap)) + end + + for level=1,level_cap do + if missing_spells[level] then + missing_spells[level]:sort() + if level > 99 then + windower.add_to_chat(7, + level .. 'jp: ' .. missing_spells[level]:concat(', ')) + else + windower.add_to_chat(7, + level .. ': ' .. missing_spells[level]:concat(', ')) + end + end + end + if level_cap > 99 then + windower.add_to_chat(7, string.format( + 'List Complete. You are missing %d %s spells up to %d spent job points.', + spell_count, res.jobs[job].en, level_cap)) + else + windower.add_to_chat(7, string.format( + 'List Complete. You are missing %d %s spells up to level %d.', + spell_count, res.jobs[job].en, level_cap)) + end + else + if level_cap >= 1500 then + windower.add_to_chat(7,string.format( + 'Congratulations! You know all spells for %s.', + res.jobs[job].en)) + elseif level_cap > 99 then + windower.add_to_chat(7,string.format( + 'Congratulations! You know all spells for %s up to %d spent job points!', + res.jobs[job].en, level_cap)) + else + windower.add_to_chat(7,string.format( + 'Congratulations! You know all spells for %s up to level %d!', + res.jobs[job].en, level_cap)) + end + end +end + +-------------------------------------------------------------------------------- +--Name: spells_by_current +-- Show missing spells for the current main and sub jobs. +--Args: +---- player (T): player object from windower.ffxi.get_player() +-------------------------------------------------------------------------------- +function spells_by_current(player) + local missing_spells = T{} + local player_spells = windower.ffxi.get_spells() + local spell_count = 0 + + + local main_job_level = player.main_job_level + local main_job_jp = player.job_points[player.main_job:lower()].jp_spent + + local main_level + local sub_level + + -- If the player has over 99 spend jp, then switch to treating JP as level. + if main_job_jp > 99 then + main_job_level = main_job_jp + end + + for spell_id,spell in pairs(res.spells) do + local main_level = spell.levels[player.main_job_id] + local sub_level = spell.levels[player.sub_job_id] + local spell_level = nil + + + if main_level and main_level > main_job_level then + main_level = nil + end + if sub_level and sub_level > player.sub_job_level then + sub_level = nil + end + + if main_level and sub_level then + spell_level = math.min(main_level, sub_level) + else + spell_level = spell_level or main_level or sub_level + end + + if spell_level and spell.type ~= 'Trust' and + not player_spells[spell_id] and not spell.unlearnable then + + missing_spells:append(format_spell(spell)) + spell_count = spell_count + 1 + end + end + + if not missing_spells:empty() then + if main_job_jp > 0 then + if player.sub_job then + windower.add_to_chat(7, string.format('Showing learnable spells for %s%d with %d spent job points and %s%d.', + player.main_job, player.main_job_level, + player.job_points[player.main_job:lower()].jp_spent, + player.sub_job, player.sub_job_level)) + else + windower.add_to_chat(7, string.format('Showing learnable spells for %s%d with %d spent job points.', + player.main_job, player.main_job_level, + player.job_points[player.main_job:lower()].jp_spent)) + end + else + if player.sub_job then + windower.add_to_chat(7, string.format('Showing learnable spells for %s%d/%s%d.', + player.main_job, player.main_job_level, + player.sub_job, player.sub_job_level)) + else + windower.add_to_chat(7, string.format('Showing learnable spells for %s%d.', + player.main_job, player.main_job_level)) + end + end + + missing_spells:sort() + for _,spell in ipairs(missing_spells) do + windower.add_to_chat(7, spell) + end + if player.sub_job then + windower.add_to_chat(7, string.format('List Complete. You are missing %d learnable spells for %s%d/%s%d.', + spell_count, + player.main_job, player.main_job_level, + player.sub_job, player.sub_job_level)) + else + windower.add_to_chat(7, string.format('List Complete. You are missing %d learnable spells for %s%d.', + spell_count, + player.main_job, player.main_job_level)) + end + else + if player.sub_job then + windower.add_to_chat(7, string.format('Congratulations! You know all learnable spells for %s%d/%s%d!', + player.main_job, player.main_job_level, + player.sub_job, player.sub_job_level)) + else + windower.add_to_chat(7, string.format('Congratulations! You know all learnable spells for %s%d!', + player.main_job, player.main_job_level)) + end + end +end + +--[[ +Copyright © 2018, John S Hobart +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 SpellBook 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 John S Hobart 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. +--]] diff --git a/addons/SpellBook/readme.md b/addons/SpellBook/readme.md new file mode 100644 index 0000000000..aef96a267d --- /dev/null +++ b/addons/SpellBook/readme.md @@ -0,0 +1,37 @@ +# SpellBook + +This addon helps you find missing spells. You can search by job and level, +or by category. + +## Usage +Spent jp can be specified for spells learned from Gifts by entering a value of 100-1500. +Spells are never given as Gifts for less than 100 jp and values under 100 are treated as level. + + +``` +//spbk help +``` +Show help text. +``` +//spbk [current] +``` +Show learnable spells based on current main and sub job and level/jp. +``` +//spbk [] +``` +Show missing spells for current main or sub job. Defaults to the job\'s current level/jp. +``` +//spbk [] +``` +Show missings spells for specified job and level. Defaults to the job\'s level/jp. +``` +//spbk [all] +``` +Show learnable spells by category. Limited to spells which are learnable, unless all is added after the category. + +Categories: whitemagic, blackmagic, songs, ninjustu, summoning, bluemagic, geomancy, trusts, all (Trusts are not included in all) + + +## Credits + +Inspired by the SpellCheck addon by Zubis diff --git a/addons/Stubborn/Stubborn.lua b/addons/Stubborn/Stubborn.lua new file mode 100644 index 0000000000..69865fac44 --- /dev/null +++ b/addons/Stubborn/Stubborn.lua @@ -0,0 +1,54 @@ +--[[Copyright © 2021, Arico +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 Stubborn 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 Arico 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 = 'Stubborn' +_addon.author = 'Arico' +_addon.version = '1' +_addon.commands = {'stubborn','cfh'} + +require('logger') +packets = require('packets') + +windower.register_event('outgoing chunk', function(id, original, modified, injected, blocked) + if id == 0x01A and not injected then + local p = packets.parse('outgoing', original) + if p['Category'] == 5 then + return true + end + end +end) + +windower.register_event('addon command', function(...) + local target = windower.ffxi.get_mob_by_target('t') + if target and target.claim_id ~= 0 then + local p = packets.new('outgoing', 0x01A, { + ['Target'] = target['id'], + ['Target Index'] = target['index'], + ['Category'] = 5, + }) + packets.inject(p) + end +end) diff --git a/addons/Stubborn/readme.md b/addons/Stubborn/readme.md new file mode 100644 index 0000000000..1ca7d48458 --- /dev/null +++ b/addons/Stubborn/readme.md @@ -0,0 +1,6 @@ +# Stubborn +A Windower 4 addon to prevent unnecessary "Call for help!" + +Stubborn is a light weight replacement to the old CFHProtect addon. + +If you need to call for help. Type //stubborn or //cfh. diff --git a/addons/Tab/README.md b/addons/Tab/README.md new file mode 100644 index 0000000000..a98513269c --- /dev/null +++ b/addons/Tab/README.md @@ -0,0 +1,9 @@ +# Tab + +### English +- Simple addon Replace Tab key input to `` or ``. (X+Tab) +- **Tips:** if you won't to include pet or trust in `` by other players, use `/ignorepet on` and `/ignoretrust on` (in-game commands) + +### 日本語 +- Tabキーの動作を``または``(X+Tab)に置き換えます。 +- **Tips:** ``に他プレイヤーのペットやフェイスを含めたくない場合、`/ignorepet on` または `/ignorefaith on`(ゲーム内コマンド)をご利用ください。 diff --git a/addons/Tab/tab.lua b/addons/Tab/tab.lua new file mode 100644 index 0000000000..cae63eaf58 --- /dev/null +++ b/addons/Tab/tab.lua @@ -0,0 +1,49 @@ +--[[ +Copyright © 2018, from20020516 +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 Tab 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 from20020516 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 = 'Tab' +_addon.author = 'from20020516' +_addon.version = '1.0' + +require('sets') +st = false +x_pressed = false + +--replace input tab. validated in Japanese keyboard. please let me know if problems occur with the English keyboard. +windower.register_event('keyboard',function(dik,pressed,flags,blocked) + if dik == 45 then + x_pressed = pressed + elseif not windower.chat.is_open() then + if dik == 15 and pressed and not st then --Tab + st = x_pressed and '' or '' + windower.chat.input('/ta '..st) + return true; --tab input blocking. it's probably broken.. + elseif S{1,28}[dik] and pressed then --Esc or Enter + st = false + end + end +end) diff --git a/addons/TreasurePool/TreasurePool.lua b/addons/TreasurePool/TreasurePool.lua index 780ad75c65..65529ad101 100644 --- a/addons/TreasurePool/TreasurePool.lua +++ b/addons/TreasurePool/TreasurePool.lua @@ -1,4 +1,4 @@ ---[[Copyright © 2017, Kenshi +--[[Copyright © 2019, Kenshi All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.]] _addon.name = 'TreasurePool' _addon.author = 'Kenshi' -_addon.version = '1.0' +_addon.version = '2.0' require('luau') texts = require('texts') @@ -54,115 +54,110 @@ defaults.display.text.alpha = 255 defaults.display.text.size = 12 settings = config.load(defaults) +box = texts.new('${current_string}', settings) -treasure_text = texts.new(settings.display, settings) +local items = T{} -treasure_text:appendline('Treasure Pool:') -for i = 0, 9 do - treasure_text:appendline(i .. ': ${index' .. i .. '|-}${lotting' .. i .. '}') -end - -goals = {} - -lotter = {} - -lot = {} +windower.register_event('load', function() + local treasure = windower.ffxi.get_items().treasure + for i = 0, 9 do + if treasure[i] and treasure[i].item_id then + local item = res.items[treasure[i].item_id] and res.items[treasure[i].item_id].en or treasure[i].item_id + local pos = treasure[i].timestamp + i + table.insert(items, {position = pos, index = i, name = item, timestamp = treasure[i].timestamp, + temp = treasure[i].timestamp + 300, lotter = nil, lot = nil}) + end + end + table.sort(items, function(a,b) return a and b and a.position < b.position end) +end) windower.register_event('incoming chunk', function(id, data) - if id == 0x0D2 then - - local packet = packets.parse('incoming', data) - + local packet = packets.parse('incoming', data) -- Ignore gil drop if packet.Item == 0xFFFF then return end - - local time_check = packet.Timestamp + 300 - local diff = os.difftime(time_check, os.time()) - + -- Double packet and leaving pt fix + for key, value in pairs(items) do + if value and value.index == packet.Index then + if value.timestamp == packet.Timestamp then + return + else + table.remove(items, key) + end + end + end + -- Ignore item 0 packets + if packet.Item == 0 then + return + end + -- Create table + local time_check = packet.Timestamp + 300 + local diff = os.difftime(time_check, os.time()) + local item = res.items[packet.Item] and res.items[packet.Item].en or packet.Item + local pos = packet.Timestamp + packet.Index if diff <= 300 then - goals[packet.Index] = packet.Timestamp + 300 - lotter[packet.Index] = ' ' + table.insert(items, {position = pos, index = packet.Index, name = item, timestamp = packet.Timestamp, + temp = packet.Timestamp + 300, lotter = nil, lot = nil}) else - goals[packet.Index] = os.time() + 300 - lotter[packet.Index] = ' ' + table.insert(items, {position = pos, index = packet.Index, name = item, timestamp = packet.Timestamp, + temp = os.time() + 300, lotter = nil, lot = nil}) end - + -- Sort table + table.sort(items, function(a,b) return a and b and a.position < b.position end) end - if id == 0x0D3 then - - local lotpacket = packets.parse('incoming', data) - - -- Ignore drop to a player or floored - if lotpacket.Drop ~= 0 then - return - else - lotter[lotpacket.Index] = lotpacket['Highest Lotter Name'] - lot[lotpacket.Index] = lotpacket['Highest Lot'] + local packet = packets.parse('incoming', data) + for key, value in pairs(items) do + if value.index == packet.Index then + if packet.Drop ~= 0 then + table.remove(items, key) + table.sort(items, function(a,b) return a and b and a.position < b.position end) + else + value.lotter = packet['Highest Lotter Name'] + value.lot = packet['Highest Lot'] + end + end end - end - - -- Check to hide text box if zoning with treasure up if id == 0xB then - zoning_bool = true - elseif id == 0xA and zoning_bool then - zoning_bool = false + items = T{} end - end) windower.register_event('prerender', function() - local treasure = T(windower.ffxi.get_items().treasure) - local remove = S{} - local info = S{} - if zoning_bool or treasure:empty() then - treasure_text:update(info) - treasure_text:hide() + if items:empty() then + box:hide() return end - for i = 0, 9 do - if treasure[i] and treasure[i].item_id then - if goals[i] then - local diff = os.difftime(goals[i], os.time()) - local timer = {} - timer[i] = os.date('!%M:%S', diff) - if timer[i] then - if diff < 0 then -- stop the timer when 00:00 so it don't show 59:59 for a brief moment - remove:add('index' .. i) - remove:add('lotting' .. i) - else - info['index' .. i] = ( - diff < 60 and - '\\cs(255,0,0)' .. res.items[treasure[i].item_id].name .. ' → ' .. timer[i] - or diff > 180 and - '\\cs(0,255,0)' .. res.items[treasure[i].item_id].name .. ' → ' .. timer[i] - or - '\\cs(255,128,0)' .. res.items[treasure[i].item_id].name .. ' → ' .. timer[i]) .. '\\cr' - end + local current_string = 'Treasure Pool:' + for key, value in pairs(items) do + if value and value.temp then + local diff = os.difftime(value.temp, os.time()) + local timer = os.date('!%M:%S', diff) + if diff >= 0 then + current_string = current_string..'\n['..key..']' + current_string = ( + diff < 60 and + current_string..'\\cs(255,0,0) '..value.name..' → '..timer + or diff > 180 and + current_string..'\\cs(0,255,0) '..value.name..' → '..timer + or + current_string..'\\cs(255,128,0) '..value.name..' → '..timer)..'\\cr' + if value.lotter and value.lot and value.lot > 0 then + current_string = current_string..' | ' + current_string = (current_string..'\\cs(0,255,255)'..value.lotter..': '..value.lot)..'\\cr' end - else -- show item name in case the addon is loaded with items on tresure box - info['index' .. i] = res.items[treasure[i].item_id].name + else + table.remove(items, key) end - if lotter[i] and lot[i] then - if lotter[i] == ' ' then - remove:add('lotting' .. i) - elseif lot[i] > 0 then - info['lotting' .. i] = ( - '\\cs(0,255,255)' .. (' | ' .. lotter[i] .. ': ' .. lot[i])) .. '\\cr' - end - end - treasure_text:show() - else - remove:add('index' .. i) - remove:add('lotting' .. i) + box:show() end - treasure_text:update(info) - end - for entry in remove:it() do - treasure_text[entry] = nil end + box.current_string = current_string +end) + +windower.register_event('logout', function() + items = T{} end) diff --git a/addons/Treasury/ReadMe.md b/addons/Treasury/ReadMe.md index 769f9ef18c..0b23864f50 100644 --- a/addons/Treasury/ReadMe.md +++ b/addons/Treasury/ReadMe.md @@ -20,6 +20,11 @@ There are a few special key words for `name`: * `avatarites` matches all geode items (HQ) * `currency` matches all Dynamis currency (all three tiers of all three kinds) * `seals` matches the standard seals found in the field (BS, KS, KC, HKC, SKC) +* `detritus` matches Swart Astral Detritus and Murky Astral Detritus +* `heroism` matches Heroism Crystal and Heroism Aggregate +* `moldy` matches all Moldy weapons and neck items from Dynamis Divergence +* `dynad` matches all three card types, all three medal types, and the crafting materials from Dynamis Divergence +* `papers` matches all shards and all void items from Dynamis Divergence * `pool` matches your current treasure pool '//treasury lot|pass|drop clear|list` diff --git a/addons/Treasury/Treasury.lua b/addons/Treasury/Treasury.lua index 773e207159..dda4966de3 100644 --- a/addons/Treasury/Treasury.lua +++ b/addons/Treasury/Treasury.lua @@ -1,6 +1,6 @@ _addon.name = 'Treasury' _addon.author = 'Ihina' -_addon.version = '1.2.0.2' +_addon.version = '1.2.1.1' _addon.commands = {'treasury', 'tr'} res = require('resources') @@ -19,22 +19,46 @@ defaults.Verbose = false settings = config.load(defaults) -ids = T{} +all_ids = T{} for item in res.items:it() do - ids[item.name:lower()] = item.id - ids[item.name_log:lower()] = item.id + local name = item.name:lower() + if not all_ids[name] then + all_ids[name] = S{} + end + local name_log = item.name_log:lower() + if not all_ids[name_log] then + all_ids[name_log] = S{} + end + all_ids[name]:add(item.id) + all_ids[name_log]:add(item.id) end -s = S{'pass', 'lot', 'drop'} code = {} code.pass = S{} code.lot = S{} code.drop = S{} +local flatten = function(s) + return s:reduce(function(s1, s2) + return s1 + s2 + end, S{}) +end + +local extract_ids = function(settings_table, key) + local valid = settings_table[key]:filter(function(name) + local found = all_ids[name:lower()] ~= nil + if not found then + print('Treasury: Item "%s" not found in %s list.':format(name, key)) + end + return found + end) + return flatten(valid:map(table.get+{all_ids} .. string.lower)) +end + config.register(settings, function(settings_table) - code.pass = settings_table.Pass:map(table.get+{ids} .. string.lower) - code.lot = settings_table.Lot:map(table.get+{ids} .. string.lower) - code.drop = settings_table.Drop:map(table.get+{ids} .. string.lower) + code.pass = extract_ids(settings_table, 'Pass') + code.lot = extract_ids(settings_table, 'Lot') + code.drop = extract_ids(settings_table, 'Drop') end) lotpassdrop_commands = T{ @@ -105,7 +129,7 @@ function force_check() -- Check inventory for unwanted items if settings.AutoDrop then for index, item in pairs(items.inventory) do - if type(item) == 'table' and code.drop:contains(item.id) then + if type(item) == 'table' and code.drop:contains(item.id) and item.status == 0 then drop(item.id, index, item.count) end end @@ -126,13 +150,13 @@ end function find_id(name) if name == 'pool' then return pool_ids() - + elseif name == 'seals' then return S{1126, 1127, 2955, 2956, 2957} - + elseif name == 'currency' then return S{1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457} - + elseif name == 'geodes' then return S{3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304} @@ -142,8 +166,23 @@ function find_id(name) elseif name == 'crystals' then return S{4096, 4097, 4098, 4099, 4100, 4101, 4102, 4103} + elseif name == 'detritus' then + return S{9875, 9876} + + elseif name == 'heroism' then + return S{9877, 9878} + + elseif name == 'moldy' then + return S{9773, 9830, 9831, 9832, 9833, 9834, 9835, 9836, 9837, 9838, 9839, 9840, 9841, 9843, 9868, 9869, 9870, 9871, 9872, 9873, 9874} + + elseif name == 'dynad' then + return S{9538, 9539, 9540, 9541, 9542, 9543, 9844, 9845} + + elseif name == 'papers' then + return S{9544, 9545, 9546, 9547, 9548, 9549, 9550, 9551, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9581, 9582, 9583, 9584, 9585, 9586, 9587, 9588, 9589, 9590, 9591, 9592, 9593, 9594, 9595, 9596, 9597, 9598, 9599, 9600, 9601, 9602, 9603, 9604, 9605, 9606, 9607, 9608, 9609, 9610, 9611, 9612, 9613, 9614, 9615, 9616, 9617, 9618, 9619, 9620, 9621, 9622, 9623, 9624, 9625, 9626, 9627, 9628, 9629, 9630, 9631, 9632, 9633, 9634, 9635, 9636, 9637, 9638, 9639, 9640, 9641, 9642, 9643, 9644, 9645, 9646, 9647, 9648, 9649, 9650, 9651, 9652, 9653, 9654, 9655, 9656, 9657, 9658, 9659, 9660, 9661, 9662, 9663, 9664, 9665, 9666, 9667, 9668, 9669, 9670, 9671, 9672, 9673, 9674, 9675, 9676, 9677, 9678, 9679, 9680, 9681, 9682, 9683, 9684, 9685, 9686, 9687, 9688, 9689, 9690, 9691, 9692, 9693, 9694, 9695, 9696, 9697, 9698, 9699, 9700, 9701, 9702, 9703, 9704, 9705, 9706, 9707, 9708, 9709, 9710, 9711, 9712, 9713, 9714, 9715, 9716, 9717, 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, 9734, 9735, 9736, 9737, 9738, 9739, 9740, 9741, 9742, 9743, 9744, 9745, 9746, 9747, 9748, 9749, 9750, 9751, 9752, 9753, 9754, 9755, 9756, 9757, 9758, 9759, 9760, 9761, 9762, 9763} + else - return S(ids:key_filter(windower.wc_match-{name})) + return flatten(S(all_ids:key_filter(windower.wc_match-{name}))) end end @@ -184,7 +223,7 @@ windower.register_event('incoming chunk', function(id, data) return end - if id == 0x020 and settings.AutoDrop and code.drop:contains(chunk.Item) then + if id == 0x020 and settings.AutoDrop and code.drop:contains(chunk.Item) and chunk.Status == 0 then drop(chunk.Item, chunk.Index, chunk.Count) else -- Don't need to stack in the other case, as a new inventory packet will come in after the drop anyway @@ -228,7 +267,7 @@ windower.register_event('addon command', function(command1, command2, ...) error('No items found that match: %s':format(name)) return end - lotpassdrop(command1, command2, ids) + lotpassdrop(command1, command2, ids) if global then windower.send_ipc_message('treasury %s %s %s':format(command1, command2, ids:concat(' '))) @@ -248,12 +287,12 @@ windower.register_event('addon command', function(command1, command2, ...) end elseif command1 == 'passall' then - for slot_index, item_table in pairs(windower.ffxi.get_items().treasure) do + for slot_index, item_table in pairs(windower.ffxi.get_items().treasure) do windower.ffxi.pass_item(slot_index) end - + elseif command1 == 'lotall' then - for slot_index, item_table in pairs(windower.ffxi.get_items().treasure) do + for slot_index, item_table in pairs(windower.ffxi.get_items().treasure) do windower.ffxi.lot_item(slot_index) end @@ -320,12 +359,11 @@ windower.register_event('addon command', function(command1, command2, ...) print(' \\cs(255,255,255)autostack [on|off]\\cr - Enables/disables (or toggles) the autostack feature') print(' \\cs(255,255,255)delay \\cr - Allows you to change the delay of actions (default: 0)') - end end) --[[ -Copyright © 2014-2015, Windower +Copyright © 2014-2018, Windower All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/addons/Trusts/README.md b/addons/Trusts/README.md new file mode 100644 index 0000000000..463026e6da --- /dev/null +++ b/addons/Trusts/README.md @@ -0,0 +1,36 @@ +# Trusts + +- //tru save `` : Save trusts in current party. +- //tru `` : Calls trusts you saved. +- //tru list : Lists your saved sets. +- //tru random : What's your fortune today? +- //tru check : List of unlearned trusts. gotta catch 'em all! + +### 使い方 + +- //tru save `` + - 呼び出し中のフェイスをセットに保存(セット名は半角英字) +- //tru `` + - 保存したセットのフェイスを召喚 + - 呼び出し先と"同枠"のフェイスは戻す + - 既にPTにいる場合は戻さない = 倒れたフェイスの補充が可能 + - リキャストが不足している場合は戻さない +- //tru list + - 保存したセットを一覧表示します。 +- //tru random + - フェイスガチャ。PT枠上限までランダムで召喚 +- //tru check + - 未習得フェイスを表示 + +### data/settings.xml (auto-generated) +- language : `` OR `` +- auto : `true` OR `false` + - 登録フェイスを全て自動で呼び出すか、1体ごとに1クリックするか選択 +- wait + - ユーザーのPC環境に応じて長くする。ファストキャストは無関係 + - aftercast : `number` + - 詠唱完了から次の詠唱までの待機時間。初期値3秒 + - retr : `number` + - フェイスを戻したあと次の詠唱までの待機時間。初期値1.25秒 + - retrall : `number` + - フェイスを全て戻したあと次の詠唱までの待機時間。初期値3秒 diff --git a/addons/Trusts/Trusts.lua b/addons/Trusts/Trusts.lua new file mode 100644 index 0000000000..c35f66c36e --- /dev/null +++ b/addons/Trusts/Trusts.lua @@ -0,0 +1,373 @@ +--[[ +Copyright © 2018, from20020516 +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 Trusts 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 from20020516 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='Trusts' +_addon.author='from20020516' +_addon.version='1.1' +_addon.commands={'trusts','tru'} + +config = require('config') +math = require('math') +math.randomseed(os.clock()) +require('logger') + +windower.register_event('load',function() + defaults = { + auto=true, + language=windower.ffxi.get_info().language, + sets={ + ['default']={ + English={ + ['1']='Valaineral', + ['2']='Mihli Aliapoh', + ['3']='Tenzen', + ['4']='Adelheid', + ['5']='Joachim'}, + Japanese={ + ['1']='ヴァレンラール', + ['2']='ミリ・アリアポー', + ['3']='テンゼン', + ['4']='アーデルハイト', + ['5']='ヨアヒム'}}[windower.ffxi.get_info().language]}, + wait={ + ['aftercast']=3, + ['retr']=1.25, + ['retrall']=3},} + settings = config.load(defaults) + lang = string.lower(settings.language) + player = windower.ffxi.get_player() +end) + +windower.register_event('login',function() + player = windower.ffxi.get_player() +end) + +windower.register_event('addon command',function(...) + cmd = {...} + if cmd[1] == 'help' then + local chat = windower.add_to_chat + local color = string.color + chat(1,'Trusts - Command List:') + chat(207,'//tru '..color('save ',166,160)..' --Save trusts in current party.') + chat(207,'//tru '..color('',166,160)..' --Calls trusts you saved.') + chat(207,'//tru '..color('list',166,160)..' --Lists your saved sets.') + chat(207,'//tru '..color('random',166,160)..' --What\'s your fortune today?') + chat(207,'//tru '..color('check',166,160)..' --List of unlearned trusts. gotta catch \'em all!') + elseif cmd[1] == 'save' then + save_set(cmd[2]) + elseif cmd[1] == 'check' then + check_learned() + elseif cmd[1] == 'list' then + list_sets() + else + call_set(cmd[1] or 'default') + end +end) + +function save_set(set) + settings.sets[set] = {} + local trust_ind = 0 + local get_party = windower.ffxi.get_party() + for i=1,5 do + local trust = get_party['p'..i] + if trust and trust.mob.spawn_type == 14 then + trust_ind = trust_ind + 1 + settings.sets[set][tostring(trust_ind)]=trusts:with('models',trust.mob.models[1])[lang] + end + end + settings:save('all') + log('set '..set..' saved.') +end + +function list_sets() + local chat = windower.add_to_chat + settings = config.load() + chat(1, 'Trusts - Saved sets:') + + for set, _ in pairs(settings.sets) do + if set ~= 'default' then + chat(207, set) + end + end +end + +function check_lang(entity) + return {japanese=entity.japanese,english=entity.english}[lang]; +end + +function check_limit() + for i,v in pairs(windower.ffxi.get_key_items()) do + --Trust permit,Rhapsody in.. + limit = S{2497,2499,2501}[v] and 3 or v==2884 and 4 or v==2886 and 5 or limit or 0 + end + return limit; +end + +function call_trust() + if #queue > 0 then + windower.chat.input('/ma "'..windower.to_shift_jis(check_lang(queue[1]))..'" ') + end +end + +function check_exist() + local party = {} --include only trusts. --['name']=models + local party_ind = {} -- index of trust's name in current party. {'name1','name2',...,'name5'} + local get_party = windower.ffxi.get_party() + for i=1,5 do + local member = get_party['p'..i] + if member and member.mob then + if member.mob.spawn_type == 14 then + party[member.name] = member.mob.models[1] + table.insert(party_ind,member.name) + end + end + end + return {party,party_ind}; +end + +function call_set(set) + queue = {} --trusts to be cast. + settings = config.load() + local party,party_ind = unpack(check_exist()) + local limit = check_limit() --upper limit # of calls trust in current player. + local time = os.clock() --window open + local get_spells = windower.ffxi.get_spells() + local get_spell_recasts = windower.ffxi.get_spell_recasts() + + if set == 'random' then + local checked = {} + local others = windower.ffxi.get_party().party1_count - #party_ind - 1 --# of human in party exept . + + if limit == #party_ind then + windower.chat.input('/retr all') + calls = limit + coroutine.sleep(settings.wait.retrall) + else + calls = limit - #party_ind - others + end + + repeat + local index = trusts[math.random(1,#trusts)] + if not table.find(checked,index.name) then + table.insert(checked,index.name) + if get_spells[index.id] and get_spell_recasts[index.id] == 0 then + table.insert(queue,index) + end + end + until #queue >= calls or #checked >= 103 --# of unique names w/o Cornelia + + elseif settings.sets[set] then + retr = {unpack(party_ind)} + for i=1,limit do + if settings.sets[set][tostring(i)] then + local entity = trusts:with(lang,settings.sets[set][tostring(i)]) + if not party[entity.name] + or party[entity.name] ~= entity.models then + if get_spell_recasts[entity.id] == 0 then + if get_spells[entity.id] then + table.insert(queue,entity) + else + table.remove(retr,table.find(retr,party_ind[i])) + error('You aren\'t trusted by '..entity.english..'.') + end + else + table.remove(retr,table.find(retr,party_ind[i])) + local recast = math.floor(get_spell_recasts[entity.id] / 6) / 10 + log(entity.english..' needs '..recast..' secs break.') + end + else + table.remove(retr,table.find(retr,entity.name)) + if settings.auto then + log(entity.english..' already exists.') + end + end + end + end + for index,name in pairs(retr) do + if #retr == #party_ind then + windower.chat.input('/retr all') + coroutine.sleep(settings.wait.retrall) + break; + else + windower.chat.input('/retr '..name) + coroutine.sleep(settings.wait.retr) + end + end + else + error('Unknown set name '..(set or '')) + end + --if /retr then wait at least 3secs. + local delay = (limit - #party_ind) == 0 and math.max(0,settings.wait.retrall + time - os.clock()) or 0 + coroutine.schedule(call_trust,delay) +end + +windower.register_event('action', function(act) + if settings.auto and act.actor_id == player.id and queue and #queue > 0 then + if act.category == 4 and act.param == table.remove(queue,1).id then + coroutine.schedule(call_trust,settings.wait.aftercast) + elseif act.category == 8 and act.param == 28787 and act.targets[1].actions[1].param == queue[1].id then + coroutine.schedule(call_trust,settings.wait.aftercast) + end + end +end) + +function check_learned() + local learned = {} + local get_spells = windower.ffxi.get_spells() + for i,value in ipairs(trusts) do + if get_spells[value.id] == false and not value.english:endswith('(UC)') then + table.insert(learned,value.id) + log(check_lang(value)) + end + end + log('You haven\'t trusted yet from '..#learned..' trusts.') +end + +trusts = T{ + [1]={id=896,japanese="シャントット",english="Shantotto",name="Shantotto",models=3000}, + [2]={id=897,japanese="ナジ",english="Naji",name="Naji",models=3001}, + [3]={id=898,japanese="クピピ",english="Kupipi",name="Kupipi",models=3002}, + [4]={id=899,japanese="エグセニミル",english="Excenmille",name="Excenmille",models=3003}, + [5]={id=900,japanese="アヤメ",english="Ayame",name="Ayame",models=3004}, + [6]={id=901,japanese="ナナー・ミーゴ",english="Nanaa Mihgo",name="NanaaMihgo",models=3005}, + [7]={id=902,japanese="クリルラ",english="Curilla",name="Curilla",models=3006}, + [8]={id=903,japanese="フォルカー",english="Volker",name="Volker",models=3007}, + [9]={id=904,japanese="アジドマルジド",english="Ajido-Marujido",name="Ajido-Marujido",models=3008}, + [10]={id=905,japanese="トリオン",english="Trion",name="Trion",models=3009}, + [11]={id=906,japanese="ザイド",english="Zeid",name="Zeid",models=3010}, + [12]={id=907,japanese="ライオン",english="Lion",name="Lion",models=3011}, + [13]={id=908,japanese="テンゼン",english="Tenzen",name="Tenzen",models=3012}, + [14]={id=909,japanese="ミリ・アリアポー",english="Mihli Aliapoh",name="MihliAliapoh",models=3013}, + [15]={id=910,japanese="ヴァレンラール",english="Valaineral",name="Valaineral",models=3014}, + [16]={id=911,japanese="ヨアヒム",english="Joachim",name="Joachim",models=3015}, + [17]={id=912,japanese="ナジャ・サラヒム",english="Naja Salaheem",name="NajaSalaheem",models=3016}, + [18]={id=913,japanese="プリッシュ",english="Prishe",name="Prishe",models=3017}, + [19]={id=914,japanese="ウルミア",english="Ulmia",name="Ulmia",models=3018}, + [20]={id=915,japanese="スカリーZ",english="Shikaree Z",name="ShikareeZ",models=3019}, + [21]={id=916,japanese="チェルキキ",english="Cherukiki",name="Cherukiki",models=3020}, + [22]={id=917,japanese="アイアンイーター",english="Iron Eater",name="IronEater",models=3021}, + [23]={id=918,japanese="ゲッショー",english="Gessho",name="Gessho",models=3022}, + [24]={id=919,japanese="ガダラル",english="Gadalar",name="Gadalar",models=3023}, + [25]={id=920,japanese="ライニマード",english="Rainemard",name="Rainemard",models=3024}, + [26]={id=921,japanese="イングリッド",english="Ingrid",name="Ingrid",models=3025}, + [27]={id=922,japanese="レコ・ハボッカ",english="Lehko Habhoka",name="LehkoHabhoka",models=3026}, + [28]={id=923,japanese="ナシュメラ",english="Nashmeira",name="Nashmeira",models=3027}, + [29]={id=924,japanese="ザザーグ",english="Zazarg",name="Zazarg",models=3028}, + [30]={id=925,japanese="アヴゼン",english="Ovjang",name="Ovjang",models=3029}, + [31]={id=926,japanese="メネジン",english="Mnejing",name="Mnejing",models=3030}, + [32]={id=927,japanese="サクラ",english="Sakura",name="Sakura",models=3031}, + [33]={id=928,japanese="ルザフ",english="Luzaf",name="Luzaf",models=3032}, + [34]={id=929,japanese="ナジュリス",english="Najelith",name="Najelith",models=3033}, + [35]={id=930,japanese="アルド",english="Aldo",name="Aldo",models=3034}, + [36]={id=931,japanese="モーグリ",english="Moogle",name="Moogle",models=3035}, + [37]={id=932,japanese="ファブリニクス",english="Fablinix",name="Fablinix",models=3036}, + [38]={id=933,japanese="マート",english="Maat",name="Maat",models=3037}, + [39]={id=934,japanese="D.シャントット",english="D. Shantotto",name="D.Shantotto",models=3038}, + [40]={id=935,japanese="星の神子",english="Star Sibyl",name="StarSibyl",models=3039}, + [41]={id=936,japanese="カラハバルハ",english="Karaha-Baruha",name="Karaha-Baruha",models=3040}, + [42]={id=937,japanese="シド",english="Cid",name="Cid",models=3041}, + [43]={id=938,japanese="ギルガメッシュ",english="Gilgamesh",name="Gilgamesh",models=3042}, + [44]={id=939,japanese="アレヴァト",english="Areuhat",name="Areuhat",models=3043}, + [45]={id=940,japanese="セミ・ラフィーナ",english="Semih Lafihna",name="SemihLafihna",models=3044}, + [46]={id=941,japanese="エリヴィラ",english="Elivira",name="Elivira",models=3045}, + [47]={id=942,japanese="ノユリ",english="Noillurie",name="Noillurie",models=3046}, + [48]={id=943,japanese="ルー・マカラッカ",english="Lhu Mhakaracca",name="LhuMhakaracca",models=3047}, + [49]={id=944,japanese="フェリアスコフィン",english="Ferreous Coffin",name="FerreousCoffin",models=3048}, + [50]={id=945,japanese="リリゼット",english="Lilisette",name="Lilisette",models=3049}, + [51]={id=946,japanese="ミュモル",english="Mumor",name="Mumor",models=3050}, + [52]={id=947,japanese="ウカ・トトゥリン",english="Uka Totlihn",name="UkaTotlihn",models=3051}, + [53]={id=948,japanese="クララ",english="Klara",name="Klara",models=3053}, + [54]={id=949,japanese="ロマー・ミーゴ",english="Romaa Mihgo",name="RomaaMihgo",models=3054}, + [55]={id=950,japanese="クイン・ハスデンナ",english="Kuyin Hathdenna",name="KuyinHathdenna",models=3055}, + [56]={id=951,japanese="ラーアル",english="Rahal",name="Rahal",models=3056}, + [57]={id=952,japanese="コルモル",english="Koru-Moru",name="Koru-Moru",models=3057}, + [58]={id=953,japanese="ピエージェ(UC)",english="Pieuje (UC)",name="Pieuje",models=3058}, + [59]={id=954,japanese="I.シールド(UC)",english="I. Shield (UC)",name="InvincibleShld",models=3060}, + [60]={id=955,japanese="アプルル(UC)",english="Apururu (UC)",name="Apururu",models=3061}, + [61]={id=956,japanese="ジャコ(UC)",english="Jakoh (UC)",name="JakohWahcondalo",models=3062}, + [62]={id=957,japanese="フラヴィリア(UC)",english="Flaviria (UC)",name="Flaviria",models=3059}, + [63]={id=958,japanese="ウェイレア",english="Babban",name="Babban",models=3067}, + [64]={id=959,japanese="アベンツィオ",english="Abenzio",name="Abenzio",models=3068}, + [65]={id=960,japanese="ルガジーン",english="Rughadjeen",name="Rughadjeen",models=3069}, + [66]={id=961,japanese="クッキーチェブキー",english="Kukki-Chebukki",name="Kukki-Chebukki",models=3070}, + [67]={id=962,japanese="マルグレート",english="Margret",name="Margret",models=3071}, + [68]={id=963,japanese="チャチャルン",english="Chacharoon",name="Chacharoon",models=3072}, + [69]={id=964,japanese="レイ・ランガヴォ",english="Lhe Lhangavo",name="LheLhangavo",models=3073}, + [70]={id=965,japanese="アシェラ",english="Arciela",name="Arciela",models=3074}, + [71]={id=966,japanese="マヤコフ",english="Mayakov",name="Mayakov",models=3075}, + [72]={id=967,japanese="クルタダ",english="Qultada",name="Qultada",models=3076}, + [73]={id=968,japanese="アーデルハイト",english="Adelheid",name="Adelheid",models=3077}, + [74]={id=969,japanese="アムチュチュ",english="Amchuchu",name="Amchuchu",models=3078}, + [75]={id=970,japanese="ブリジッド",english="Brygid",name="Brygid",models=3079}, + [76]={id=971,japanese="ミルドリオン",english="Mildaurion",name="Mildaurion",models=3080}, + [77]={id=972,japanese="ハルヴァー",english="Halver",name="Halver",models=3087}, + [78]={id=973,japanese="ロンジェルツ",english="Rongelouts",name="Rongelouts",models=3088}, + [79]={id=974,japanese="レオノアーヌ",english="Leonoyne",name="Leonoyne",models=3089}, + [80]={id=975,japanese="マクシミリアン",english="Maximilian",name="Maximilian",models=3090}, + [81]={id=976,japanese="カイルパイル",english="Kayeel-Payeel",name="Kayeel-Payeel",models=3091}, + [82]={id=977,japanese="ロベルアクベル",english="Robel-Akbel",name="Robel-Akbel",models=3092}, + [83]={id=978,japanese="クポフリート",english="Kupofried",name="Kupofried",models=3093}, + [84]={id=979,japanese="セルテウス",english="Selh\'teus",name="Selh\'teus",models=3094}, + [85]={id=980,japanese="ヨランオラン(UC)",english="Yoran-Oran (UC)",name="Yoran-Oran",models=3095}, + [86]={id=981,japanese="シルヴィ(UC)",english="Sylvie (UC)",name="Sylvie",models=3096}, + [87]={id=982,japanese="アブクーバ",english="Abquhbah",name="Abquhbah",models=3098}, + [88]={id=983,japanese="バラモア",english="Balamor",name="Balamor",models=3099}, + [89]={id=984,japanese="オーグスト",english="August",name="August",models=3100}, + [90]={id=985,japanese="ロスレーシャ",english="Rosulatia",name="Rosulatia",models=3101}, + [91]={id=986,japanese="テオドール",english="Teodor",name="Teodor",models=3103}, + [92]={id=987,japanese="ウルゴア",english="Ullegore",name="Ullegore",models=3105}, + [93]={id=988,japanese="マッキーチェブキー",english="Makki-Chebukki",name="Makki-Chebukki",models=3106}, + [94]={id=989,japanese="キング・オブ・ハーツ",english="King of Hearts",name="KingOfHearts",models=3107}, + [95]={id=990,japanese="モリマー",english="Morimar",name="Morimar",models=3108}, + [96]={id=991,japanese="ダラクァルン",english="Darrcuiln",name="Darrcuiln",models=3109}, + [97]={id=992,japanese="アークHM",english="AAHM",name="ArkHM",models=3113}, + [98]={id=993,japanese="アークEV",english="AAEV",name="ArkEV",models=3114}, + [99]={id=994,japanese="アークMR",english="AAMR",name="ArkMR",models=3115}, + [100]={id=995,japanese="アークTT",english="AATT",name="ArkTT",models=3116}, + [101]={id=996,japanese="アークGK",english="AAGK",name="ArkGK",models=3117}, + [102]={id=997,japanese="イロハ",english="Iroha",name="Iroha",models=3111}, + [103]={id=998,japanese="ユグナス",english="Ygnas",name="Ygnas",models=3118}, + [104]={id=1004,japanese="エグセニミルII",english="Excenmille [S]",name="Excenmille",models=3052}, + [105]={id=1005,japanese="アヤメ(UC)",english="Ayame (UC)",name="Ayame",models=3063}, + [106]={id=1006,japanese="マート(UC)",english="Maat (UC)",name="Maat",models=3064}, --expected models + [107]={id=1007,japanese="アルド(UC)",english="Aldo (UC)",name="Aldo",models=3065}, --expected models + [108]={id=1008,japanese="ナジャ(UC)",english="Naja (UC)",name="NajaSalaheem",models=3066}, + [109]={id=1009,japanese="ライオンII",english="Lion II",name="Lion",models=3081}, + [110]={id=1010,japanese="ザイドII",english="Zeid II",name="Zeid",models=3086}, + [111]={id=1011,japanese="プリッシュII",english="Prishe II",name="Prishe",models=3082}, + [112]={id=1012,japanese="ナシュメラII",english="Nashmeira II",name="Nashmeira",models=3083}, + [113]={id=1013,japanese="リリゼットII",english="Lilisette II",name="Lilisette",models=3084}, + [114]={id=1014,japanese="テンゼンII",english="Tenzen II",name="Tenzen",models=3097}, + [115]={id=1015,japanese="ミュモルII",english="Mumor II",name="Mumor",models=3104}, + [116]={id=1016,japanese="イングリッドII",english="Ingrid II",name="Ingrid",models=3102}, + [117]={id=1017,japanese="アシェラII",english="Arciela II",name="Arciela",models=3085}, + [118]={id=1018,japanese="イロハII",english="Iroha II",name="Iroha",models=3112}, + [119]={id=1019,japanese="シャントットII",english="Shantotto II",name="Shantotto",models=3110}, + [120]={id=1003,japanese="コーネリア",english="Cornelia",name="Cornelia",models=3119}, --goodbye, my love + [121]={id=999,japanese="モンブロー",english="Monberaux",name="Monberaux",models=3120}, + [122]={id=1003,japanese="マツイP",english="Matsui-P",name="Matsui-P",models=3121}, +} diff --git a/addons/Yush/ReadMe.md b/addons/Yush/ReadMe.md index 3a2818ab20..2e0adec1e5 100644 --- a/addons/Yush/ReadMe.md +++ b/addons/Yush/ReadMe.md @@ -29,6 +29,10 @@ The key which resets the current macro set to the previous set. If true, will display the current macro set you are in. The name it displays is the same name it has in the file it loads. +**VerboseKeys** + +If true, will append the list of keybinds for the current macro set (only effective if the *Verbose* setting is `true`). + **VerboseOutput** Determines where the current macro set will be displayed (only effective if the *Verbose* setting is `true`). The following options are available: diff --git a/addons/Yush/Yush.lua b/addons/Yush/Yush.lua index 78ac383f72..92853f22be 100644 --- a/addons/Yush/Yush.lua +++ b/addons/Yush/Yush.lua @@ -1,5 +1,5 @@ _addon.author = 'Arcon' -_addon.version = '2.1.1.0' +_addon.version = '2.2.0.0' _addon.language = 'English' _addon.command = 'yush' @@ -59,6 +59,7 @@ defaults.ResetKey = '`' defaults.BackKey = 'backspace' defaults.Verbose = false defaults.VerboseOutput = 'Text' +defaults.VerboseKeys = false defaults.Label = {} settings = config.load(defaults) @@ -67,20 +68,32 @@ label = texts.new(settings.Label, settings) binds = {} names = {} +key_combos = {} current = binds stack = L{binds} keys = S{} output = function() if settings.Verbose then - names[current] = names[current] or 'Unnamed ' .. tostring(current):sub(8) + names[current] = names[current] or 'Unnamed' + + local output_text_names = L{} + output_text_names:append(names[current]) + if settings.VerboseKeys then + for key, val in pairs(current) do + if type(val) ~= 'string' then + val = names[val] or 'Unnamed' + end + output_text_names:append(key_combos[key] .. ': ' .. val) + end + end if settings.VerboseOutput == 'Text' then - label:text(names[current]) + label:text(output_text_names:concat('\n')) elseif settings.VerboseOutput == 'Chat' then - log('Changing into macro set %s.':format(names[current])) + log('Changing into macro set %s.':format(output_text_names:concat(' | '))) elseif settings.VerboseOutput == 'Console' then - print('Changing into macro set %s.':format(names[current])) + print('Changing into macro set %s.':format(output_text_names:concat(' | '))) end end end @@ -107,6 +120,8 @@ check = function(keyset) if key <= keyset then if type(val) == 'string' then windower.send_command(val) + elseif type(val) == 'function' then + val() else current = val stack:append(current) @@ -125,12 +140,13 @@ parse_binds = function(fbinds, top) rawset(names, top, rawget(_innerG._names, fbinds)) for key, val in pairs(fbinds) do - key = S(key:split('+')):map(string.lower) - if type(val) == 'string' then - rawset(top, key, val) + local split_key = S(key:split('+')):map(string.lower) + rawset(key_combos, split_key, key) + if type(val) == 'string' or type(val) == 'function' then + rawset(top, split_key, val) else local sub = {} - rawset(top, key, sub) + rawset(top, split_key, sub) parse_binds(val, sub) end end @@ -138,29 +154,26 @@ end windower.register_event('load', 'login', 'job change', 'logout', function() local player = windower.ffxi.get_player() - local file, path + local file, path, filename, filepath, err local basepath = windower.addon_path .. 'data/' if player then - for filepath in L{ + for filepath_template in L{ {path = 'name_main_sub.lua', format = '%s\'s %s/%s'}, {path = 'name_main.lua', format = '%s\'s %s'}, {path = 'name.lua', format = '%s\'s'}, + {path = 'binds.lua', format = '"binds"'}, }:it() do - path = filepath.format:format(player.name, player.main_job, player.sub_job or '') - file = loadfile(basepath .. filepath.path:gsub('name', player.name):gsub('main', player.main_job):gsub('sub', player.sub_job or '')) - - if file then + path = filepath_template.format:format(player.name, player.main_job, player.sub_job or '') + filename = filepath_template.path:gsub('name', player.name):gsub('main', player.main_job):gsub('sub', player.sub_job or '') + filepath = basepath .. filename + if windower.file_exists(filepath) then + file, err = loadfile(filepath) break end end end - if not file then - path = 'Binds' - file = loadfile(basepath .. path) - end - - if file then + if file and not err then _innerG._names = {} _innerG._binds = {} binds = {} @@ -181,8 +194,11 @@ windower.register_event('load', 'login', 'job change', 'logout', function() reset() print('Yush: Loaded %s Lua file':format(path)) + elseif err then + print('\nYush: Error loading file: '..err:gsub('\\','/')) elseif player then print('Yush: No matching file found for %s (%s%s)':format(player.name, player.main_job, player.sub_job and '/' .. player.sub_job or '')) + end end) @@ -269,7 +285,14 @@ dikt = { -- Har har [80] = 'num2', [81] = 'num3', [82] = 'num0', - + + [87] = 'f11', + [88] = 'f12', + + [100] = 'f13', + [101] = 'f14', + [102] = 'f15', + [199] = 'home', [200] = 'up', [201] = 'pageup', diff --git a/addons/addons.xml b/addons/addons.xml index 6f4921afd9..d5ed626e24 100644 --- a/addons/addons.xml +++ b/addons/addons.xml @@ -1,4 +1,4 @@ - + Example @@ -15,7 +15,7 @@ AEcho Automatically uses echo drops when you get silenced. Also, uses send to send a message to an alt that you got debuffed. Nitrous (Shiva) - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/nitrous24/Lua/issues @@ -30,14 +30,21 @@ Byrth Stores tells that you receive for later recall. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk AutoControl Automated automaton equipment setting and burden tracker. Nitrous (Shiva) - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/nitrous24/Lua/issues + + + autoenterkey + Chiaia + Automatically hits the enter key twice when first starting so you don't timeout on the warning message. + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk autoinvite @@ -50,8 +57,8 @@ AutoJoin Arcon Automatically joins or declines party invites. Configurable with blacklist/whitelist mode and auto-decline settings. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk AutoRA @@ -63,7 +70,7 @@ AzureSets Automated blue magic spell setting. Nitrous (Shiva) - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/nitrous24/Lua/issues @@ -78,7 +85,14 @@ Byrth Customizes battle chat messages. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk + + + BattleStations + Sjshovan (Apogee) + Change or remove the default battle music. + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk Blist @@ -106,13 +120,13 @@ Byrth Mimics the cancel plugin, but also accepts buff names instead of just IDs. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk cBlock Blacklist addon for FFOChat. Nitrous (Shiva) - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/nitrous24/Lua/issues @@ -124,17 +138,17 @@ chars - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) Lets you input special chars using simple tags (ex.: <note> for ♪). - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno ChatLink Arcon Allows opening links posted into the FFXI chat. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk ChatPorter @@ -147,15 +161,15 @@ Clock Arcon Displays an on-screen clock in a custom format with options to display several different time zones. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk ConsoleBG Arcon Displays a dark (by default) background behind the Windower console to make it more readable. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk digger @@ -163,13 +177,20 @@ Displays Chocobo digging accuracy, fatigue and remaining greens after each dig. Also shows dig "recast" timer using the Timers plugin. https://github.com/svanheulen/digger-windower-addon/issues http://www.ffxiah.com/player/Odin/Acacia + + + Dimmer + Chiaia + Helps warp you to Reisenjima using (Dim) Rings. + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk Distance Arcon Shows the distance to your current target. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk DistancePlus @@ -180,10 +201,10 @@ DressUp - Cairthenn + Cair Emulates BlinkMeNot functionality. Allows for customization of gear display for you or anyone else. https://github.com/cairface/Lua/issues - http://www.bluegartr.com/members/34070-Cairthenn + https://discord.gg/aUrHCvk DynamisHelper @@ -191,6 +212,13 @@ https://github.com/tehkrizz/Lua/issues http://www.ffxiah.com/player/Bahamut/Krizz + + EmpyPopTracker + Dean James (Xurion of Bismarck) + Tracks items and key items for popping various NMs, such as Briareus, Apademak and Warder of Courage. + https://github.com/xurion/ffxi-empy-pop-tracker/issues + https://www.ffxiah.com/forum/topic/54376/empyrean-pop-tracker-addon-10-years-late/ + Enemybar mmckee @@ -199,38 +227,45 @@ http://www.ffxiah.com/player/Ragnarok/Pesche - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) enternity Enters "Enter" automatically when prompted during a cutscene or when talking to NPCs. It will not skip choice dialog boxes. - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno + + Equipviewer + Tako, Rubenator + Displays current equipment grid on screen. Also can show current Ammo count and current Encumbrance. + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk + eval Aureus Allows developers to run arbitrary lua code in the console. https://github.com/Windower/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk FastCS - Cairthenn + Cair Dramatically speeds up cutscenes by disabling the frame rate cap. Requires the config plugin. https://github.com/cairface/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk FFOColor Nitrous (Shiva) Allows you to show FFOChat text in one of the 5 game chat channels. As well as specify colors for the text https://github.com/nitrous24/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk findAll - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) Searches items stored on all your characters and allows live on-screen tracking of specified items. - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno @@ -258,14 +293,21 @@ Byrth Enables instant linkshell chat after zoning. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk + + + InfoBar + Kenshi + Displays a configurable bar showing information on your targets. + https://github.com/KenshiDRK/Lua/issues + https://www.ffxiah.com/player/Ragnarok/Kenshi InfoReplacer - Cairthenn + Cair Replaces outgoing text prefixed by % with respective game information. https://github.com/cairface/Lua/issues - http://www.bluegartr.com/members/34070-Cairthenn + https://discord.gg/aUrHCvk Itemizer @@ -274,6 +316,13 @@ https://github.com/Jayjs20/Lua/issues http://www.ffxiah.com/player/Bismarck/Ihina + + JobChange + Sammeh + Command line Job Changer + https://github.com/SammehFFXI/Lua/issues + http://www.ffxiah.com/player/Quetzalcoatl/Sammeh + latentchecker byrth,smd111 @@ -285,46 +334,81 @@ Linker Arcon Allows opening links to certain websites from within the game, with an optional search parameter. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk Logger Arcon Logs the chat log to a file. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk + + + Lookup + Karuberu + Lookup website information from an in-game command. Accepts auto-translate text and selectors like "<t>". Opens in a browser window. + https://github.com/Karuberu/Lua/issues + https://github.com/Karuberu/Lua/issues Lottery Arcon Automatically passes an item on all accounts if lotted by another. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk MacroChanger Banggugyangu Automatically switches Macro Book and Page according to job changes. https://github.com/banggugyangu/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk MobCompass A compass to show your position relative to the target (not players) for geo and has a setup for Sneak attack - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk + + + MountMuzzle + Sjshovan (Apogee) + Change or remove the default mount music. + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk + + + MountRoulette + Dean James (Xurion of Bismarck) + Summon a mount at random, similar to Mount Roulette in FFXIV. + https://github.com/xurion/ffxi-mount-roulette/issues + https://www.ffxiah.com/forum/topic/52094/randommount-a-random-mount-selector-for-windower/ + + + NoCampaignMusic + Prevents campaign battle music from playing in Shadowreign areas. + Dean James (Xurion of Bismarck) + https://github.com/xurion/ffxi-no-campaign-music/issues + https://www.ffxiah.com/forum/topic/52507/sick-of-campaign-music-prevent-it-with-this-addon/ Nostrum Creates a click-able on-screen macro to help avoid targeting problems while curing. trv - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/trv6/Lua/issues + + NyzulHelper + Glarin of Asura + Tracks and displays the Current Floor, Time Remaining, Objective, Floors Completed, Reward Rate, and Potenial Tokens. + https://github.com/GlarinAsura/Lua/issues + https://discord.gg/aUrHCvk + obiaway Automatically collect and remove elemental obi based on day/weather/storm conditions. - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk Omen @@ -337,14 +421,14 @@ OhShi Keeps track of various event related things. Such as, VW proc messages, mob casting, mob tp moves, TH procs and cor rolls, as well as others. Nitrous (Shiva) - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/nitrous24/Lua/issues Organizer A multi-purpose inventory management solution. Similar to GearCollector. Byrth, Rooks - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/Byrth/Lua-Byrth/issues @@ -352,27 +436,27 @@ Byrth Temporary addon that fixes a null pointer animation error with pets that is causing crashes. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk PetSchool Banggugyangu A helper addon for PUPs using spellcast, it informs spellcast of pet casting (healing or nuking). https://github.com/Windower/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk PetTP SnickySnacks Tracks pet vitals (HP/TP/MP) https://github.com/Windower/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk plasmon - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) tracks plasm, killed mobs and dropped airlixirs during a delve. - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno @@ -380,20 +464,20 @@ Byrth Allows you to specify which plugins and addons will be used with which characters. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk PointWatch Byrth Allows you to monitor your XP/CP gains and keep track of the Dynamis time limit. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk porter - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) Shows the slips' items highlighting those that are stored. - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno @@ -412,9 +496,9 @@ reive - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) Tracks exp, bayld, momentum scores and bonuses during a reive. - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno @@ -422,22 +506,29 @@ Byrth Should request spawn packets for players / mobile NPCs that failed to spawn. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk Respond Byrth Respond to tells and FFOchat PMs using //r. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk Rhombus Creates a highly customizable, click-able, on-screen menu. trv - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk https://github.com/trv6/Lua/issues + + ROE + Cair + Lets you save your Records of Eminence objectives to profiles for easily swapping out objectives. + https://github.com/cairface/Lua/issues + https://discord.gg/aUrHCvk + RollTracker Balloon @@ -457,14 +548,14 @@ Banggugyangu Informs Spellcast about changes to Sneak Attack and Trick Attack status. https://github.com/banggugyangu/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk Scoreboard Suji Basic in-game damage parser. It displays live DPS and works even when chat filters are enabled. https://github.com/jerryhebert/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk setbgm @@ -478,7 +569,7 @@ Byrth Applys spellcast-like command completion (interpretation and target completion) to commands. Includes emotes, /check, and /pcmd. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk Silence @@ -499,14 +590,21 @@ Byrth Sends commands between windower instances using IPC. https://github.com/Windower/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk + + + SetTarget + Arcon + Sets the target to a given ID. + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk SpeedChecker Arcon Displays a small box indicating your current movement speed modifier (+/- X%). - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/b275nMv SpellCheck @@ -515,19 +613,26 @@ https://github.com/DamienDennehy/Lua/issues http://www.ffxiah.com/player/Asura/Zubis + + SpellBook + Sigil Baram (Ravlyn@Asura) + List unknown spells by job or category. Can also limit results by level or spent jp required by the spell. + https://github.com/sigilbaram/SpellBook/issues + https://discord.gg/b275nMv + StaggerTrack Nitrous (Shiva) Catches voidwatch weakness messages and prints them to a textbox in case you miss them in the battle spam. https://github.com/nitrous24/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/b275nMv STNA Nitrous (Shiva) One-button status removal for dual boxing. https://github.com/nitrous24/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/b275nMv stopwatch @@ -541,7 +646,14 @@ Ihm A simple helper addon for Spellcast for Scholar Stratagems. It will automatically calculate the number of stratagems you have and push them into spellcast variables. https://github.com/Windower/Lua/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk + + + Stubborn + Arico + An addon to block accidental calls for help. + https://github.com/ianandersonlol/stubborn/issues + https://discord.gg/aUrHCvk subTarget @@ -554,22 +666,22 @@ TargetInfo Arcon Displays information about your current target in memory. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk Text Arcon Allows creating and manipulating on-screen text objects through Windower commands. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk Treasury Arcon Lots or passes items based on configurable lists, drops unwanted items from the inventory and automatically stacks items when they drop. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk thtracker @@ -580,24 +692,24 @@ timestamp - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) Prefixes any chat message with a timestamp. Based on Timestamp plugin. - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno TParty Arcon Shows a target's HP percentage next to their health bar as well as party/alliance members's TP. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk translate Byrth Gives a rough JP->EN translation using the resources and custom dictionaries. https://github.com/Byrth/Lua-Byrth/issues - http://mibbit.com/#windower@irc.ffochat.com + https://discord.gg/aUrHCvk TreasurePool @@ -610,8 +722,8 @@ Update Arcon Updates and reloads all plugins and addons when typing //update. - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk VisibleFavor @@ -622,9 +734,9 @@ vwhl - Giuliano Riccio (Zohno@Phoenix) + Giuliano Riccio (Zohno@Phoenix - R.I.P) Redirects the nm's weaknesses (VW or Abyssea) to the "tell" stream so that they can be held using the chat filters' function and highlights the important info. - https://github.com/giulianoriccio/Lua/issues + https://github.com/Windower/Lua/issues http://www.ffxiah.com/player/Phoenix/Zohno @@ -638,8 +750,8 @@ Yush Arcon A file-based macro engine - https://github.com/z16/Lua/issues - http://www.ffxiah.com/player/Leviathan/Arcon + https://github.com/Windower/Lua/issues + https://discord.gg/aUrHCvk zonetimer @@ -655,4 +767,95 @@ https://github.com/Snapsmojo/Lua/issues http://www.ffxiah.com/player/Fenrir/Snaps + + CapeTrader + Lygre, Burntwaffle + Automates the ambuscade cape augmentation process. + https://github.com/OdinBurntwaffle/Lua/issues + http://www.ffxiah.com/player/Odin/Burntwaffle + + + craft + Mojo + A Final Fantasy XI Crafting Addon + https://github.com/Snapsmojo/Lua/issues + http://www.ffxiah.com/player/Fenrir/Snaps + + + Checkparam + Centurio aka from20020516 + Displays the total of property of target player's current equipments. + https://github.com/from20020516/Lua/issues + https://twitter.com/from20020516 + + + Bonanza + Centurio aka from20020516 + Purchace and Judge Bonanza Marbles. + https://github.com/from20020516/Lua/issues + https://twitter.com/from20020516 + + + Trusts + Centurio aka from20020516 + Save and Summon trust sets. + https://github.com/from20020516/Lua/issues + https://twitter.com/from20020516 + + + MyHome + Centurio aka from20020516 + Automatically choose and use a warp spell or an item. + https://github.com/from20020516/Lua/issues + https://twitter.com/from20020516 + + + Debuffed + Auk + Tracks and displays debuffs on your current target. + https://github.com/aukon/Lua/issues + https://discord.gg/aUrHCvk + + + Tab + Centurio aka from20020516 + Simple addon Replace Tab key input to <stnpc> or X+Tab to <stpc>. + https://github.com/from20020516/Lua/issues + https://twitter.com/from20020516 + + + EasyNuke + FaceDesk + Unified commands to handle single target and AOE nukes and cures, plus Drain/Aspir and Absorbs. + https://github.com/deadman80/Lua/issues + https://www.ffxiah.com/user/Nyarlko + + + giltracker + Sylandro + Displays the current gil, similar to the FFXIV Gil HUD widget. + https://github.com/Windower/Lua/issues + https://github.com/azamorapl + + + invtracker + Sylandro + Displays a grid detailing empty and filled inventory slots, similar to the FFXIV Inventory Grid HUD widget. + https://github.com/Windower/Lua/issues + https://github.com/azamorapl + + + IndiNope + Lili + Blocks graphical effects from Geomancer's Indi- spells. + https://github.com/Windower/Lua/issues + https://github.com/lili-ffxi + + + position_manager + Lili + Allows you to set a screen position per character name. Each character will be moved to that screen position on login. Requires the WinControl plugin to be installed. + https://github.com/Windower/Lua/issues + https://github.com/lili-ffxi + diff --git a/addons/answeringmachine/answeringmachine.lua b/addons/answeringmachine/answeringmachine.lua index 7a86d27708..e73400b7cf 100644 --- a/addons/answeringmachine/answeringmachine.lua +++ b/addons/answeringmachine/answeringmachine.lua @@ -97,8 +97,8 @@ end) windower.register_event('outgoing chunk',function(id,original,modified,injected,blocked) if not blocked and id == 0x0B6 then - local name = trim(original:sub(0x6,0x14)) - local message = trim(original:sub(0x15)) + local name = trim(original:sub(0x07,0x15)) + local message = trim(original:sub(0x16)) if recording[name:upper()] then recording[name:upper()][#recording[name:upper()]+1] = {message=message,outgoing=true,timestamp=os.time(),seen=true} else diff --git a/addons/autocontrol/autoabils.lua b/addons/autocontrol/autoabils.lua new file mode 100644 index 0000000000..ea44bdc780 --- /dev/null +++ b/addons/autocontrol/autoabils.lua @@ -0,0 +1,73 @@ +autoabils = { + [1688] = {name = 'Shield Bash', recast = 180, icon = "00210"}, + [1689] = {name = 'Strobe', recast = 30, icon = "00210"}, + [1690] = {name = 'Shock Absorber', recast = 180, icon = "00210"}, + [1691] = {name = 'Flashbulb', recast = 45, icon = "00210"}, + [1692] = {name = 'Mana Converter', recast = 180, icon = "00210"}, + [1755] = {name = 'Reactive Shield', recast = 65, icon = "00210"}, + [1765] = {name = 'Eraser', recast = 30, icon = "00210"}, + [1812] = {name = 'Economizer', recast = 180, icon = "00210"}, + [1876] = {name = 'Replicator', recast = 60, icon = "00210"}, + [2489] = {name = 'Heat Capacitator', recast = 90, icon = "00210"}, + [2490] = {name = 'Barrage Turbine', recast = 180, icon = "00210"}, + [2491] = {name = 'Disruptor', recast = 60, icon = "00210"}, + [3485] = {name = 'Regulator', recast = 60, icon = "00210" } +} +attachments_to_abilities = { + [8225] = 1688, + [8449] = 1689, + [8454] = 1755, + [8456] = 2489, + [8457] = 1689, + [8461] = 2489, + [8519] = 1876, + [8520] = 2490, + [8545] = 1690, + [8553] = 1690, + [8557] = 1690, + [8642] = 1691, + [8645] = 1765, + [8674] = 1692, + [8678] = 1812, + [8680] = 2491, + [8682] = 3485, +} + +local player_id + +windower.register_event("login", function() + player_id = windower.ffxi.get_player().id +end) + +windower.register_event("load", function() + local player = windower.ffxi.get_player() + player_id = player and player.id +end) + +windower.register_event("action", function(act) + local abil_ID = act['param'] + local actor_id = act['actor_id'] + local pet_index = windower.ffxi.get_mob_by_id(player_id)['pet_index'] + + if act['category'] == 6 and actor_id == player_id and (abil_ID == 136 or abil_ID == 310 or abil_ID == 139) then + local avalible_abilities = {} + local automaton = windower.ffxi.get_mjob_data() + + if attachments_to_abilities[automaton.frame] then + table.insert(avalible_abilities, autoabils[attachments_to_abilities[automaton.frame]]) + end + + for _, id in pairs(automaton.attachments) do + if attachments_to_abilities[id] then + table.insert(avalible_abilities, autoabils[attachments_to_abilities[id]]) + end + end + + for _, ability in pairs(avalible_abilities) do -- if abil_ID is deactivate delete ability timers, otherwise create them. + windower.send_command('timers '.. (abil_ID == 139 and "d" or "c") .. ' "'..ability.name..'" ' .. (abil_ID == 139 and "" or ability.recast..' up abilities/' .. ability.icon)) + end + elseif autoabils[abil_ID-256] and windower.ffxi.get_mob_by_id(actor_id)['index'] == pet_index and pet_index ~= nil then + local abil = abil_ID - 256 + windower.send_command('@timers c "'..autoabils[abil].name..'" '..autoabils[abil].recast..' up') + end +end) diff --git a/addons/autocontrol/autocontrol.lua b/addons/autocontrol/autocontrol.lua index abb7ababe9..3c0d51c2cf 100644 --- a/addons/autocontrol/autocontrol.lua +++ b/addons/autocontrol/autocontrol.lua @@ -1,5 +1,5 @@ --[[ -Copyright © 2013-2014, Ricky Gall +Copyright © 2013, 2014, 2020 Ricky Gall, Nifim All rights reserved. Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ]] _addon.name = 'autocontrol' -_addon.version = '1.02' +_addon.version = '2.0.5' _addon.author = 'Nitrous (Shiva)' _addon.commands = {'autocontrol','acon'} @@ -59,11 +59,12 @@ defaults.autosets.default = T{ } defaults.AutoActivate = true defaults.AutoDeusExAutomata = false defaults.maneuvertimers = true - -settings = config.load(defaults) +defaults.burdentracker = true -require('maneuver') -- has to be loaded after settings are parsed. +settings = config.load(defaults) +burden_hud = require('burdometer') -- has to be loaded after settings are parsed. +require("autoabils") recast_ids = {} recast_ids.deactivate = res.job_abilities:with('english', 'Deactivate').recast_id recast_ids.activate = res.job_abilities:with('english', 'Activate').recast_id @@ -82,25 +83,24 @@ function initialize() mjob_id = player.main_job_id atts = res.items:category('Automaton') - decay = 1 - for key,_ in pairs(heat) do - heat[key] = 0 - Burden_tb[key] = 0 - Burden_tb['time' .. key] = 0 + + local playermob = windower.ffxi.get_mob_by_index(player.index) + while(playermob == nil) do + coroutine.sleep(1) + playermob = windower.ffxi.get_mob_by_index(player.index) end + if mjob_id == 18 then - if player.pet_index then - running = 1 - text_update_loop('start') - Burden_tb:show() + if playermob.pet_index then + if settings.burdentracker then + burden_hud:show() + end end end end windower.register_event('load', 'login', initialize) -windower.register_event('logout', 'unload', text_update_loop:prepare('stop')) - function attach_set(autoset) if windower.ffxi.get_player().main_job_id ~= 18 or not settings.autosets[autoset] then return @@ -109,8 +109,8 @@ function attach_set(autoset) log('The '..autoset..' set is already equipped.') return end - - local playermob = windower.ffxi.get_mob_by_id(windower.ffxi.get_player().id) + + local playermob = windower.ffxi.get_mob_by_index(windower.ffxi.get_player().index) if playermob.pet_index and playermob.pet_index ~= 0 then local recast = windower.ffxi.get_ability_recasts()[recast_ids.deactivate] if recast == 0 then @@ -265,15 +265,15 @@ windower.register_event('addon command', function(comm, ...) elseif comm == "maneuvertimers" or comm == "mt" then maneuvertimers = not maneuvertimers elseif S{'fonttype','fontsize','pos','bgcolor','txtcolor'}:contains(comm) then - if comm == 'fonttype' then Burden_tb:font(args[1]) - elseif comm == 'fontsize' then Burden_tb:size(args[1]) - elseif comm == 'pos' then Burden_tb:pos(args[1], args[2]) - elseif comm == 'bgcolor' then Burden_tb:bgcolor(args[1], args[2], args[3]) - elseif comm == 'txtcolor' then Burden_tb:color(args[1], args[2], args[3]) + if comm == 'fonttype' then burden_hud:font(args[1]) + elseif comm == 'fontsize' then burden_hud:size(args[1]) + elseif comm == 'pos' then burden_hud:pos(args[1], args[2]) + elseif comm == 'bgcolor' then burden_hud:bgcolor(args[1], args[2], args[3]) + elseif comm == 'txtcolor' then burden_hud:color(args[1], args[2], args[3]) end config.save(settings, 'all') - elseif comm == 'show' then Burden_tb:show() - elseif comm == 'hide' then Burden_tb:hide() + elseif comm == 'show' then burden_hud:show() + elseif comm == 'hide' then burden_hud:hide() elseif comm == 'settings' then log('BG: R: '..settings.bg.red..' G: '..settings.bg.green..' B: '..settings.bg.blue) log('Font: '..settings.text.font..' Size: '..settings.text.size) @@ -295,3 +295,11 @@ windower.register_event('addon command', function(comm, ...) log(' show/hide - toggles visibility of the tracker so you can make changes.') end end) + +windower.register_event("job change", function(main_job_id) + if main_job_id == 18 and settings.burdentracker then + burden_hud:show() + else + burden_hud:hide() + end +end) diff --git a/addons/autocontrol/burden.lua b/addons/autocontrol/burden.lua new file mode 100644 index 0000000000..51a8136a36 --- /dev/null +++ b/addons/autocontrol/burden.lua @@ -0,0 +1,186 @@ +local set = require("sets") +local packets = require("packets") + +local o = { + fire = 0, + earth = 0, + water = 0, + wind = 0, + ice = 0, + thunder = 0, + light = 0, + dark = 0, +} +local burden = {} +local mt = { + __index = burden +} +setmetatable(o, mt) +local updaters = {} +local heatsink + +windower.register_event('incoming chunk',function(id,org,modi,is_injected,is_blocked) + if id == 0x044 then + local attachments = windower.ffxi.get_mjob_data().attachments + if attachments then + for _, id in pairs(attachments) do + heatsink = (id == 8610) + if heatsink then + break + end + end + end + end +end) + +local thresholdModifiers = +{ + [11101] = 40, -- Cirque Farsetto +2 + [11201] = 20, -- Cirque Farsetto +1 + [14930] = 5, -- Pup. Dastanas + [15030] = 5, -- Pup. Dastanas +1 + [16281] = 5, -- Buffoon's Collar + [16282] = 5, -- Buffoon's Collar +1 + [20520] = 40, -- Midnights + [26263] = 10, -- Visucius's Mantle + [26932] = 40, -- Kara. Farsetto + [26933] = 40, -- Kara. Farsetto +1 + [27960] = 5, -- Foire Dastanas + [27981] = 5, -- Foire Dastanas +1 + [28634] = 5, -- Dispersal Mantle +} +burden.threshold = 30 + +local pet_actions = +{ + [136] = "activate", + [139] = "deactivate", + [141] = "fire", + [142] = "ice", + [143] = "wind", + [144] = "earth", + [145] = "thunder", + [146] = "water", + [147] = "light", + [148] = "dark", + [309] = "cooldown", + [310] = "deus_ex_automata", +} +function burden:update(action) + updaters[action](self) +end + +function burden:zone() + for k in pairs(self) do + self[k] = 15 + end +end + +function burden.set_decay_event(func) + burden.decay_event = func +end +function updaters.deactivate(self) + for k in pairs(self) do + self[k] = 0 + end +end + +function updaters.activate(self) + for _, id in pairs(windower.ffxi.get_mjob_data().attachments) do + heatsink = (id == 8610) + if heatsink then + break + end + end + burden.update_decay_rate() + for k in pairs(self) do + self[k] = 15 + end +end +updaters.deus_ex_automata = updaters.activate + +function updaters.cooldown(self) + for k in pairs(self) do + self[k] = self[k] / 2 + end +end + +function updaters.maneuver(self, type) + self[type] = self[type] + 15 + local inventory = windower.ffxi.get_items() + local equipment = { + sub = {}, + ammo = {}, + main = {}, + head = {}, + body = {}, + back = {}, + legs = {}, + feet = {}, + neck = {}, + hands = {}, + range = {}, + waist = {}, + left_ear = {}, + left_ring = {}, + right_ear = {}, + right_ring = {}, + } + for k, v in pairs(inventory.equipment) do + equipment[string.gsub(k ,"_bag","")][k] = v + end + burden.threshold = 30 + for k, v in pairs(equipment) do + item = windower.ffxi.get_items(v[k .. "_bag"], v[k]) + if thresholdModifiers[item.id] then + burden.threshold = burden.threshold + thresholdModifiers[item.id] + end + end +end + +function updaters.ice(self) updaters.maneuver(self, "ice") end +function updaters.fire(self) updaters.maneuver(self, "fire") end +function updaters.wind(self) updaters.maneuver(self, "wind") end +function updaters.dark(self) updaters.maneuver(self, "dark") end +function updaters.earth(self) updaters.maneuver(self, "earth") end +function updaters.water(self) updaters.maneuver(self, "water") end +function updaters.light(self) updaters.maneuver(self, "light") end +function updaters.thunder(self) updaters.maneuver(self, "thunder") end + +burden.decay_rate = 1 +function burden.decay() + for k in pairs(o) do + if o[k] > burden.decay_rate then + o[k] = o[k] - burden.decay_rate + elseif o[k] > 0 then + o[k] = 0 + end + end + if burden.decay_event then + burden.decay_event() + end + coroutine.schedule(burden.decay, 3) +end +coroutine.schedule(burden.decay, os.date("*t").sec % 3) + +local count_to_decay_rate = { + [0] = 2, + [1] = 4, + [2] = 5, + [3] = 6, +} +function burden.update_decay_rate() + if heatsink then + local count = 0 + for _, v in pairs(windower.ffxi.get_player().buffs) do + if v == 305 then + count = count + 1 + end + end + burden.decay_rate = count_to_decay_rate[count]; + else + burden.decay_rate = 1 + end +end + +return o diff --git a/addons/autocontrol/burdometer.lua b/addons/autocontrol/burdometer.lua new file mode 100644 index 0000000000..c36f64517e --- /dev/null +++ b/addons/autocontrol/burdometer.lua @@ -0,0 +1,96 @@ +local sets = require("sets") +local texts = require("texts") +local burden = require("burden") + +local pet_actions = +{ + [136] = "activate", + [139] = "deactivate", + [141] = "fire", + [142] = "ice", + [143] = "wind", + [144] = "earth", + [145] = "thunder", + [146] = "water", + [147] = "light", + [148] = "dark", + [309] = "cooldown", + [310] = "deus_ex_automata", +} + +local maneuvers = +S{ + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, +} + +str = 'Fire: \\cs(${color_fire|255,255,255})${fire|0}\\cr - ${time_fire|0}s - ${risk_fire|0}%' +str = str .. '\nIce: \\cs(${color_ice|255,255,255})${ice|0}\\cr - ${time_ice|0}s - ${risk_ice|0}%' +str = str .. '\nWind: \\cs(${color_wind|255,255,255})${wind|0}\\cr - ${time_wind|0}s - ${risk_wind|0}%' +str = str .. '\nEarth: \\cs(${color_earth|255,255,255})${earth|0}\\cr - ${time_earth|0}s - ${risk_earth|0}%' +str = str .. '\nThunder: \\cs(${color_thunder|255,255,255})${thunder|0}\\cr - ${time_thunder|0}s - ${risk_thunder|0}%' +str = str .. '\nWater: \\cs(${color_water|255,255,255})${water|0}\\cr - ${time_water|0}s - ${risk_water|0}%' +str = str .. '\nLight: \\cs(${color_light|255,255,255})${light|0}\\cr - ${time_light|0}s - ${risk_light|0}%' +str = str .. '\nDark: \\cs(${color_dark|255,255,255})${dark|0}\\cr - ${time_dark|0}s - ${risk_dark|0}%' + +local hud = texts.new(str, settings) + +function update_hud(element) + hud[element] = burden[element] + + risk = burden[element] - burden.threshold + hud["risk_" .. element] = risk > 0 and risk or 0 + hud["color_" .. element] = "255," .. (risk > 33 and 0 or 255) .. "," .. (risk > 0 and 0 or 255) + hud["time_" .. element] = (burden[element] / burden.decay_rate) * 3 +end + +windower.register_event("action", function(act) + local abil_id = act['param'] + local actor_id = act['actor_id'] + local player = windower.ffxi.get_player() + local pet_index = windower.ffxi.get_mob_by_index(player.index).pet_index + + if player.main_job_id ~= 18 then + return + end + + if act["category"] == 6 and actor_id == player.id and pet_actions[abil_id] then + burden:update(pet_actions[abil_id]) -- Always assumes good burden (+15). + if maneuvers:contains(abil_id) then + if act.targets[1].actions[1].param > 0 then + burden[pet_actions[abil_id]] = burden.threshold + act.targets[1].actions[1].param -- Corrects for bad burden when over threshold. + end + update_hud(pet_actions[abil_id]) + end + end +end) + +local function decay_event() + for element in pairs(burden) do + update_hud(element) + end +end +burden.set_decay_event(decay_event) + +windower.register_event("zone change", function() + burden:zone() +end) + +local function update_decay_rate(buff_id) + if buff_id == 305 then + burden:update_decay_rate() + end +end + +windower.register_event("gain buff", update_decay_rate) +windower.register_event("lose buff", update_decay_rate) + +decay_event() + +return hud diff --git a/addons/autocontrol/maneuver.lua b/addons/autocontrol/maneuver.lua deleted file mode 100644 index 44419829b3..0000000000 --- a/addons/autocontrol/maneuver.lua +++ /dev/null @@ -1,416 +0,0 @@ ---[[ -Copyright (c) 2013, Ricky Gall -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 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 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. -]] - - -local texts = require 'texts' -threshItems = T - {[16281]=5 -- Buffoon's Collar - ,[16282]=5 -- Buffoon's Collar +1 - ,[11101]=40 -- Cirque Farsetto +2 - ,[11201]=20 -- Cirque Farsetto +1 - ,[14930]=5 -- Pup. Dastanas - ,[15030]=5 -- Pup. Dastanas +1 - ,[27960]=5 -- Foire Dastanas - ,[27981]=5 -- Foire Dastanas +1 - ,[28634]=5 -- Dispersal Mantle - ,[26933]=40 -- Kara. Farsetto +1 - ,[26932]=40 -- Kara. Farsetto - } -heat = T{} -heat.Fire = 0 -heat.Ice = 0 -heat.Wind = 0 -heat.Earth = 0 -heat.Thunder = 0 -heat.Water = 0 -heat.Light = 0 -heat.Dark = 0 -timer = T{} -timer.Fire = 0 -timer.Ice = 0 -timer.Wind = 0 -timer.Earth = 0 -timer.Thunder = 0 -timer.Water = 0 -timer.Light = 0 -timer.Dark = 0 -threshold = 30 -running = 0 -maneuver = 1 -lastMan = 'none' -autoabils = T{} -autoabils[1688] = {name='Shield Bash', recast=180} -autoabils[1689] = {name='Strobe', recast=30} -autoabils[1690] = {name='Shock Absorber', recast=180} -autoabils[1691] = {name='Flashbulb', recast=45} -autoabils[1692] = {name='Mana Converter', recast=180} -autoabils[1755] = {name='Reactive Shield', recast=65} -autoabils[1765] = {name='Eraser', recast=30} -autoabils[1812] = {name='Economizer', recast=180} -autoabils[1876] = {name='Replicator', recast=60} -autoabils[2489] = {name='Heat Capacitator', recast=90} -autoabils[2490] = {name='Barrage Turbine', recast=180} -autoabils[2491] = {name='Disruptor', recast=60} - -str = 'Fire: \\cs(${colFire|255,255,255})${Fire|0}\\cr - ${timeFire|0}s - ${olFire|0}%' -str = str..'\nIce: \\cs(${colIce|255,255,255})${Ice|0}\\cr - ${timeIce|0}s - ${olIce|0}%' -str = str..'\nWind: \\cs(${colWind|255,255,255})${Wind|0}\\cr - ${timeWind|0}s - ${olWind|0}%' -str = str..'\nEarth: \\cs(${colEarth|255,255,255})${Earth|0}\\cr - ${timeEarth|0}s - ${olEarth|0}%' -str = str..'\nThunder: \\cs(${colThunder|255,255,255})${Thunder|0}\\cr - ${timeThunder|0}s - ${olThunder|0}%' -str = str..'\nWater: \\cs(${colWater|255,255,255})${Water|0}\\cr - ${timeWater|0}s - ${olWater|0}%' -str = str..'\nLight: \\cs(${colLight|255,255,255})${Light|0}\\cr - ${timeLight|0}s - ${olLight|0}%' -str = str..'\nDark: \\cs(${colDark|255,255,255})${Dark|0}\\cr - ${timeDark|0}s - ${olDark|0}%' - -Burden_tb = texts.new(str, settings) - -windower.register_event("action", function(act) - if mjob_id == 18 then - local abil_ID = act['param'] - local actor_id = act['actor_id'] - local player = T(windower.ffxi.get_player()) - local pet_index = windower.ffxi.get_mob_by_id(windower.ffxi.get_player()['id'])['pet_index'] - - if act['category'] == 6 and actor_id == player.id and S{136,139,141,142,143,144,145,146,147,148,309,310}:contains(abil_ID) then - if S{141, 142, 143, 144, 145, 146, 147, 148}:contains(abil_ID) and maneuvertimers then - windower.send_command('timers c "Maneuver: '..maneuver..'" 60 down') - if maneuver > 2 then - maneuver = 1 - else - maneuver = maneuver + 1 - end - end - if abil_ID == 141 then - lastMan = 'Fire' - heatupdate('Fire',1) - elseif abil_ID == 142 then - lastMan = 'Ice' - heatupdate('Ice',1) - elseif abil_ID == 143 then - lastMan = 'Wind' - heatupdate('Wind',1) - elseif abil_ID == 144 then - lastMan = 'Earth' - heatupdate('Earth',1) - elseif abil_ID == 145 then - lastMan = 'Thunder' - heatupdate('Thunder',1) - elseif abil_ID == 146 then - lastMan = 'Water' - heatupdate('Water',1) - elseif abil_ID == 147 then - lastMan = 'Light' - heatupdate('Light',1) - elseif abil_ID == 148 then - lastMan = 'Dark' - heatupdate('Dark',1) - elseif abil_ID == 309 then - windower.send_command('@timers d Overloaded!') - heatupdate() - elseif abil_ID == 136 or abil_ID == 310 then -- Activate or Deus Ex Automata - Burden_tb:show() - decay = get_decay() - activate_burden() - elseif abil_ID == 139 then - zero_all() - windower.send_command('@timers d Overloaded!') - text_update_loop('stop') - Burden_tb:hide() - end - elseif S{1688,1689,1690,1691,1692,1755,1765,1812,1876,2489,2490,2491}:contains(abil_ID-256) - and windower.ffxi.get_mob_by_id(actor_id)['index'] == pet_index - and pet_index ~= nil then - local abil = abil_ID - 256 - windower.send_command('@timers c "'..autoabils[abil].name..'" '..autoabils[abil].recast..' up') - end - - end -end) - -function heatupdate(element, maneuver) - if mjob_id == 18 then - local first = false - if maneuver ~= nil and element ~= nil then - decay = get_decay() - threshold = get_threshold() - if heat[element] == 0 then first = true end - heat[element] = heat[element] + get_jaheat() - - if heat[element] >= threshold then - Burden_tb['col'..element] = '255,0,255' - else - Burden_tb['col'..element] = '255,255,255' - end - Burden_tb[element] = heat[element] - timer[element] = math.ceil(heat[element]/decay)*3 - Burden_tb['time'..element] = math.round(timer[element]) - local tempol = (.05+(.01*(heat[element]-threshold)))*100 - if tempol < 0 or heat[element] < threshold then tempol = 0 end - Burden_tb['ol'..element] = tempol - if first then timer_start(element) end - else - for key,_ in pairs(timer) do - heat[key] = math.round(heat[key]/2) - Burden_tb[key] = heat[key] - timer[key] = math.ceil(heat[key]/decay)*3 - Burden_tb['time'..key] = math.round(timer[key]) - local tempol = (.05+(.01*(heat[key]-threshold)))*100 - if tempol < 0 or heat[key] < threshold then tempol = 0 end - Burden_tb['ol'..key] = tempol - end - end - end -end - -function get_decay() - if mjob_id == 18 then - local newdecay - if T(windower.ffxi.get_mjob_data().attachments):contains(8610) then - local mans = 0 - local buffs = windower.ffxi.get_player().buffs - for z = 1, #buffs do - if buffs[z] == 305 then - mans = mans + 1 - end - end - if mans == 3 then newdecay = 6 - elseif mans == 2 then newdecay = 5 - elseif mans == 1 then newdecay = 4 - else newdecay = 2 - end - else - newdecay = 1 - end - return newdecay - end -end - -function get_jaheat() - if mjob_id == 18 then - local baseheat = 20 - local updatedheat = 0 - local bonusheat = 0 - if T(windower.ffxi.get_mjob_data()['attachments']):contains(8485) then - local mans = 0 - local buffs = windower.ffxi.get_player()['buffs'] - for z = 1, #buffs do - if buffs[z] == 301 then - mans = mans + 1 - end - end - if mans == 3 then bonusheat = 10 - elseif mans == 2 then bonusheat = 9 - elseif mans == 1 then bonusheat = 8 - else bonusheat = 3 - end - end - updatedheat = baseheat + bonusheat - return updatedheat - end -end - -function get_threshold() - if mjob_id == 18 then - local newthreshold = 0 - local basethreshold = 30 - local items = windower.ffxi.get_items() - local bonus = 0 - local slots = {'hands', 'body', 'neck', 'back'} - for i, s in ipairs(slots) do - if items.equipment[s] ~= 0 then - local item = threshItems[items.inventory[items.equipment[s]].id] or threshItems[items.wardrobe[items.equipment[s]].id] - if item ~= nil then - bonus = bonus + item - end - end - end - newthreshold = basethreshold + bonus - return newthreshold - end -end - -function update_element(ele) - if mjob_id == 18 then - heat[ele] = heat[ele] - decay - if heat[ele] < 0 then heat[ele] = 0 end - - if heat[ele] > threshold then - Burden_tb['col'..ele] = '255,0,255' - else - Burden_tb['col'..ele] = '255,255,255' - end - Burden_tb[ele] = heat[ele] - timer[ele] = math.ceil(heat[ele]/decay)*3 - Burden_tb['time'..ele] = math.round(timer[ele]) - local tempol = (.05+(.01*(heat[ele]-threshold)))*100 - if tempol < 0 or heat[ele] < threshold then tempol = 0 end - Burden_tb['ol'..ele] = tempol - if heat[ele] > 0 then - windower.send_command('@wait 3;lua i autocontrol update_element '..ele) - end - end -end - -function activate_burden() - if mjob_id == 18 then - threshold = 30 - for key, _ in pairs(heat) do - heat[key] = 35 - Burden_tb[key] = 35 - - if heat[key] > threshold then - Burden_tb['col'..key] = '255,0,255' - else - Burden_tb['col'..key] = '255,255,255' - end - timer[key] = math.ceil(35/decay) * 3 - Burden_tb['time'..key] = math.round(timer[key]) - local tempol = (.05+(.01*(heat[key]-threshold)))*100 - if tempol < 0 or heat[key] < threshold then tempol = 0 end - Burden_tb['ol'..key] = tempol - - windower.send_command('lua i autocontrol timer_start '..key) - end - if running ~= 1 then text_update() end - end -end - -function text_update() - if mjob_id == 18 then - Burden_tb:update() - windower.send_command('@wait 1;lua i autocontrol text_update_loop start') - running = 1 - end -end - -function text_update_loop(str) - if mjob_id == 18 then - if str == 'start' and running == 1 and not petlessZones:contains(windower.ffxi.get_info().zone) then - for key, _ in pairs(heat) do - timer[key] = timer[key] - 1 - if timer[key] < 1 then timer[key] = 0 end - - if heat[key] > threshold then - Burden_tb['col'..key] = '255,0,255' - else - Burden_tb['col'..key] = '255,255,255' - end - Burden_tb['time'..key] = timer[key] - local tempol = (.05+(.01*(heat[key]-threshold)))*100 - if tempol < 0 or heat[key] < threshold then tempol = 0 end - Burden_tb['ol'..key] = tempol - end - Burden_tb:update() - - local player_mob = windower.ffxi.get_mob_by_id(windower.ffxi.get_player()['id']) - if player_mob then - if player_mob['pet_index'] - and player_mob['pet_index'] ~= 0 then - windower.send_command('@wait 1;lua i autocontrol text_update_loop start') - running = 1 - end - end - elseif str == 'stop' then running = 0 end - end -end - -windower.register_event('gain buff', function(id) - if mjob_id == 18 then - if id == 305 then - decay = get_decay() - end - if id == 299 then - windower.send_command('@timers c Overloaded! '..heat[lastMan]-threshold..' down') - end - end -end) - -windower.register_event('lose buff', function(id) - if mjob_id == 18 then - if id == 305 then - decay = get_decay() - end - if id == 299 then - windower.send_command('@timers d Overloaded!') - end - end -end) - -function timer_start(ele) - if mjob_id == 18 then - windower.send_command('@wait 3;lua i autocontrol update_element '..ele) - end -end - -windower.register_event('job change', function(mj) - mjob_id = mj - if mjob_id ~= 18 or petlessZones:contains(windower.ffxi.get_info().zone) then - Burden_tb:hide() - text_update_loop('stop') - end -end) - -function zero_all() - for key,val in pairs(heat) do - Burden_tb[key] = 0 - timer[key] = 0 - Burden_tb['time'..key] = 0 - Burden_tb['col'..key] = '255,255,255' - Burden_tb['ol'..key] = tempol - end -end - -function zone_check(to) - to = tonumber(to) - if mjob_id == 18 then - if petlessZones:contains(to) then - text_update_loop('stop') - zero_all() - Burden_tb:hide() - return - else - local player_mob = windower.ffxi.get_mob_by_target('me') - if player_mob then - if player_mob.pet_index - and player_mob.pet_index ~= 0 then - Burden_tb:show() - activate_burden() - end - else - windower.send_command('@wait 10;lua i autocontrol zone_check ' .. to) - end - end - end -end - -windower.register_event('zone change', zone_check) - -windower.register_event('time change', function() - if mjob_id == 18 then - decay = get_decay() - end -end) diff --git a/addons/autocontrol/readme.md b/addons/autocontrol/readme.md index e9cd100251..eb14bce0ed 100644 --- a/addons/autocontrol/readme.md +++ b/addons/autocontrol/readme.md @@ -1,5 +1,5 @@ **Author:** Ricky Gall -**Version:** 0.21 +**Version:** 2.0.4 **Description:** Addon to make setting automaton attachments easier. Currently only works as pup main. Includes burden tracker. diff --git a/addons/autoenterkey/README.md b/addons/autoenterkey/README.md new file mode 100644 index 0000000000..d8e7f3db3b --- /dev/null +++ b/addons/autoenterkey/README.md @@ -0,0 +1,9 @@ +Author: Chiaia +Version: 1.0 +Automatically hits the enter key twice as you first load up the game so you don't timeout on the warning message if you happen to like to tab out as it launches. +It take about 5 to 10 seconds to start to do this. If you happen to manually do it faster if will just unload itself since it serves no other purpose. + +Abbreviation: //ake, //autoinvite + +Commands: +* There are currently no commands. diff --git a/addons/autoenterkey/autoenterkey.lua b/addons/autoenterkey/autoenterkey.lua new file mode 100644 index 0000000000..fa3cdb245d --- /dev/null +++ b/addons/autoenterkey/autoenterkey.lua @@ -0,0 +1,46 @@ +--Copyright (c) 2019, Chiaia +--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 Auto Enter Key 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 Chiaia 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 = 'Auto Enter Key' +_addon.version = '1.0' +_addon.author = 'Chiaia (Asura)' +_addon.commands = {'ake',} + +windower.register_event('load', function() + if windower.ffxi.get_info().logged_in then + windower.send_command('lua u autoenterkey') + else + coroutine.sleep(5) + windower.send_command('setkey enter down;') + coroutine.sleep(0.3) + windower.send_command('setkey enter up;') + coroutine.sleep(5) + windower.send_command('setkey enter down;') + coroutine.sleep(0.3) + windower.send_command('setkey enter up;') + windower.send_command('lua u autoenterkey') + end +end) diff --git a/addons/azureSets/azuresets.lua b/addons/azureSets/azuresets.lua index 898a49b8ae..41bab2951d 100644 --- a/addons/azureSets/azuresets.lua +++ b/addons/azureSets/azuresets.lua @@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'AzureSets' -_addon.version = '1.22' +_addon.version = '1.23' _addon.author = 'Nitrous (Shiva)' _addon.commands = {'aset','azuresets','asets'} @@ -210,6 +210,16 @@ function save_set(setname) notice('Set '..setname..' saved.') end +function delete_set(setname) + if settings.spellsets[setname] == nil then + error('Please choose an existing spellset.') + return + end + settings.spellsets[setname] = nil + settings:save('all') + notice('Deleted '..setname..'.') +end + function get_spellset_list() log("Listing sets:") for key,_ in pairs(settings.spellsets) do @@ -248,7 +258,10 @@ windower.register_event('addon command', function(...) if args[1] ~= nil then save_set(args[1]) end - + elseif comm == 'delete' then + if args[1] ~= nil then + delete_set(args[1]) + end elseif comm == 'spellset' or comm == 'set' then if args[1] ~= nil then set_spells(args[1], args[2] or settings.setmode) @@ -272,10 +285,11 @@ windower.register_event('addon command', function(...) 3. set (clearfirst|preservetraits) -- Same as spellset 4. add -- Set (spell) to slot (slot (number)). 5. save -- Saves current spellset as (setname). - 6. currentlist -- Lists currently set spells. - 7. setlist -- Lists all spellsets. - 8. spelllist -- List spells in (setname) - 9. help --Shows this menu.]] + 6. delete -- Delete (setname) spellset. + 7. currentlist -- Lists currently set spells. + 8. setlist -- Lists all spellsets. + 9. spelllist -- List spells in (setname) + 10. help --Shows this menu.]] for _, line in ipairs(helptext:split('\n')) do windower.add_to_chat(207, line..chat.controls.reset) end diff --git a/addons/battlemod/README.md b/addons/battlemod/README.md index fbcced3b01..2a9a823b1f 100644 --- a/addons/battlemod/README.md +++ b/addons/battlemod/README.md @@ -8,16 +8,23 @@ Battlemod, packet version Abbreviation: //bm -Commands: +Commands: + Toggles: -* simplify - Condenses battle text using custom messages, Default = True -* condensetargets - Collapse similar messages with multiple targets, Default = True -** targetnumber - Toggle condensed target number display, Default = True -* condensedamage - Collapses similar damage messages with the same target, Default = True -** swingnumber - Toggle condensed damage number display, Default = True -* cancelmulti - Cancels multiple consecutive identical lines, Default = True -* oxford - Toggle use of oxford comma, Default = True -* commamode - Toggle comma-only mode, Default = False +* simplify - Condenses battle text using custom messages (Default: True) +* condensetargets - Collapse similar messages with multiple targets (Default: True) + * targetnumber - Toggle condensed target number display (Default: True) + * condensetargetname - Toggle target name condensation (Default: False) + * oxford - Toggle use of oxford comma (Default: True) + * commamode - Toggle comma-only mode (Default: False) +* condensedamage - Collapses similar damage messages with the same target (Default: True) + * swingnumber - Toggle condensed damage number display (Default: True) + * sumdamage - Sums condensed damage if true, comma-separated if false (Default: True) + * condensecrits - Condenses critical hits and normal hits together (Default: False) +* cancelmulti - Cancels multiple consecutive identical lines (Default: True) +* showonernames - Shows the name of the owner on pet messages (Default: False) +* crafting - Toggle early display of crafting results (Default: True) + Utilities: * colortest - Shows the 509 possible colors for use with the settings file * reload - Reloads the settings file @@ -32,4 +39,4 @@ The settings files for battlemod are composed of 3 to 25 xml files (depending on * data/settings.xml - contains basic flags that control the features of the program. * data/colors.xml - contains all the color codes relevant to the program, which can be adjusted using colors from the colortext command. * filters/filters.xml - contains the chat filter settings and is explained more thoroughly therein. -* filters/filters-.xml - Several examples are provided, but these are specific filter files that will load for your individual jobs. You can use this to, for instance, make sure your healing jobs can always see damage taken (by unfiltering the section or make sure your zerg jobs don't have to see the entire alliance's damage spam. The filter file is organized by actor, so if you wanted to filter by target you would have to go through each class of actor and change the setting that affected the given target. \ No newline at end of file +* filters/filters-.xml - Several examples are provided, but these are specific filter files that will load for your individual jobs. You can use this to, for instance, make sure your healing jobs can always see damage taken (by unfiltering the section or make sure your zerg jobs don't have to see the entire alliance's damage spam. The filter file is organized by actor, so if you wanted to filter by target you would have to go through each class of actor and change the setting that affected the given target. diff --git a/addons/battlemod/battlemod.lua b/addons/battlemod/battlemod.lua index e5e18b7c46..5ae3426899 100644 --- a/addons/battlemod/battlemod.lua +++ b/addons/battlemod/battlemod.lua @@ -12,7 +12,7 @@ require 'generic_helpers' require 'parse_action_packet' require 'statics' -_addon.version = '3.23' +_addon.version = '3.31' _addon.name = 'BattleMod' _addon.author = 'Byrth, maintainer: SnickySnacks' _addon.commands = {'bm','battlemod'} @@ -24,7 +24,7 @@ end) windower.register_event('login',function (name) if debugging then windower.debug('login') end - windower.send_command('@wait 10;lua i battlemod options_load;') + options_load:schedule(10) end) windower.register_event('addon command', function(command, ...) @@ -41,6 +41,9 @@ windower.register_event('addon command', function(command, ...) elseif command:lower() == 'targetnumber' then targetnumber = not targetnumber windower.add_to_chat(121,'Battlemod: Target Number flipped! - '..tostring(targetnumber)) + elseif command:lower() == 'condensetargetname' then + condensetargetname = not condensetargetname + windower.add_to_chat(121,'Battlemod: Target Name Condensation flipped! - '..tostring(condensetargetname)) elseif command:lower() == 'swingnumber' then swingnumber = not swingnumber windower.add_to_chat(121,'Battlemod: Round Number flipped! - '..tostring(swingnumber)) @@ -54,6 +57,7 @@ windower.register_event('addon command', function(command, ...) cancelmulti = not cancelmulti windower.add_to_chat(121,'Battlemod: Multi-canceling flipped! - '..tostring(cancelmulti)) elseif command:lower() == 'reload' then + current_job = 'NONE' options_load() elseif command:lower() == 'unload' then windower.send_command('@lua u battlemod') @@ -66,6 +70,24 @@ windower.register_event('addon command', function(command, ...) elseif command:lower() == 'condensetargets' then condensetargets = not condensetargets windower.add_to_chat(121,'Battlemod: Condensed Targets flipped! - '..tostring(condensetargets)) + elseif command:lower() == 'showownernames' then + showownernames = not showownernames + windower.add_to_chat(121,'Battlemod: Show pet owner names flipped! - '..tostring(showownernames)) + elseif command:lower() == 'crafting' then + crafting = not crafting + windower.add_to_chat(121,'Battlemod: Display crafting results flipped! - '..tostring(crafting)) + elseif command:lower() == 'showblocks' then + showblocks = not showblocks + windower.add_to_chat(121,'Battlemod: Show blocks with shield flipped! - '..tostring(showblocks)) + elseif command:lower() == 'showguards' then + showguards = not showguards + windower.add_to_chat(121,'Battlemod: Show guarding on hits flipped! - '..tostring(showguards)) + elseif command:lower() == 'showcritws' then + showcritws = not showcritws + windower.add_to_chat(121,'Battlemod: Show critical hit on ws/mob tp flipped! - '..tostring(showcritws)) + elseif command:lower() == 'showrollinfo' then + showrollinfo = not showrollinfo + windower.add_to_chat(121,'Battlemod: Show lucky/unlucky rolls flipped! - '..tostring(showrollinfo)) elseif command:lower() == 'colortest' then local counter = 0 local line = '' @@ -89,24 +111,31 @@ windower.register_event('addon command', function(command, ...) elseif command:lower() == 'help' then print(' ::: '.._addon.name..' ('.._addon.version..') :::') print('Toggles: (* subtoggles)') - print(' 1. simplify --- Condenses battle text using custom messages ('..tostring(simplify)..')') - print(' 2. condensetargets --- Collapse similar messages with multiple targets ('..tostring(condensetargets)..')') - print(' * targetnumber --- Toggle target number display ('..tostring(targetnumber)..')') - print(' * oxford --- Toggle use of oxford comma ('..tostring(oxford)..')') - print(' * commamode --- Toggle comma-only mode ('..tostring(commamode)..')') - print(' 3. condensedamage --- Condenses damage messages within attack rounds ('..tostring(condensedamage)..')') - print(' * swingnumber --- Show # of attack rounds ('..tostring(swingnumber)..')') - print(' * sumdamage --- Sums condensed damage, if false damage is comma separated ('..tostring(sumdamage)..')') - print(' * condensecrits --- Condenses critical hits and normal hits together ('..tostring(condensecrits)..')') - print(' 4. cancelmulti --- Cancles multiple consecutive identical lines ('..tostring(cancelmulti)..')') - print('Utilities: 1. colortest --- Shows the 509 possible colors for use with the settings file') - print(' 2. reload --- Reloads settings file') - print(' 3. unload --- Unloads Battlemod') + print(' 1. simplify - Condenses battle text using custom messages ('..tostring(simplify)..')') + print(' 2. condensetargets - Collapse similar messages with multiple targets ('..tostring(condensetargets)..')') + print(' * targetnumber - Toggle target number display ('..tostring(targetnumber)..')') + print(' * condensetargetname - Toggle target name condensation ('..tostring(condensetargetname)..')') + print(' * oxford - Toggle use of oxford comma ('..tostring(oxford)..')') + print(' * commamode - Toggle comma-only mode ('..tostring(commamode)..')') + print(' 3. condensedamage - Condenses damage messages within attack rounds ('..tostring(condensedamage)..')') + print(' * swingnumber - Show # of attack rounds ('..tostring(swingnumber)..')') + print(' * sumdamage - Sums condensed damage if true, comma-separated if false ('..tostring(sumdamage)..')') + print(' * condensecrits - Condenses critical hits and normal hits together ('..tostring(condensecrits)..')') + print(' 4. cancelmulti - Cancels multiple consecutive identical lines ('..tostring(cancelmulti)..')') + print(' 5. showonernames - Shows the name of the owner on pet messages ('..tostring(showownernames)..')') + print(' 6. crafting - Enables early display of crafting results ('..tostring(crafting)..')') + print(' 7. showblocks - Shows if a hit was blocked with shield ('..tostring(showblocks)..')') + print(' 8. showguards - Shows if a hit was guarded ('..tostring(showguards)..')') + print(' 9. showcritws - Shows if a ws or mob ability was a critical hit (shows on multihit if atleast 1 hit was a crit) ('..tostring(showcritws)..')') + print(' 10. showrollinfo - Shows lucky/unlucky rolls ('..tostring(showrollinfo)..')') + print('Utilities: 1. colortest - Shows the 509 possible colors for use with the settings file') + print(' 2. reload - Reloads settings file') + print(' 3. unload - Unloads Battlemod') end end end) -windower.register_event('incoming text',function (original, modified, color) +windower.register_event('incoming text',function (original, modified, color, color_m, blocked) if debugging then windower.debug('incoming text') end local redcol = color%256 @@ -114,7 +143,7 @@ windower.register_event('incoming text',function (original, modified, color) a,z = string.find(original,'Equipment changed') if a and not block_equip then - windower.send_command('@wait 1;lua i battlemod flip_block_equip') + flip_block_equip:schedule(1) block_equip = true elseif a and block_equip then modified = true @@ -125,16 +154,35 @@ windower.register_event('incoming text',function (original, modified, color) c,z = string.find(original,'You must close the currently open window to use that command') if (a or b or c) and not block_cannot then - windower.send_command('@wait 1;lua i battlemod flip_block_cannot') + flip_block_cannot:schedule(1) block_cannot = true elseif (a or b or c) and block_cannot then modified = true end end + if block_modes:contains(color) then + local endline = string.char(0x7F, 0x31) + local item = string.char(0x1E) + if not bm_message(original) then + if original:endswith(endline) then --allow add_to_chat messages with the modes we blocking + return true + end + elseif original:endswith(endline) and string.find(original, item) then --block items action messages + return true + end + end return modified,color end) +function bm_message(original) + local check = string.char(0x1E) + local check2 = string.char(0x1F) + if string.find(original, check) or string.find(original, check2) then + return true + end +end + function flip_block_equip() block_equip = not block_equip end @@ -198,7 +246,7 @@ function options_load() end function filterload(job) - if Current_job == job then return end + if current_job == job then return end if file.exists('data\\filters\\filters-'..job..'.xml') then default_filt = false filter = config.load('data\\filters\\filters-'..job..'.xml',default_filter_table,false) @@ -210,34 +258,96 @@ function filterload(job) config.save(filter) windower.add_to_chat(4,'Loaded default Battlemod filters') end - Current_job = job + current_job = job end ActionPacket.open_listener(parse_action_packet) windower.register_event('incoming chunk',function (id,original,modified,is_injected,is_blocked) if debugging then windower.debug('incoming chunk '..id) end + +------- ITEM QUANTITY ------- + if id == 0x020 and parse_quantity then + --local packet = packets.parse('incoming', original) + local item = original:unpack('H',0x0D) + local count = original:unpack('I',0x05) + if item == 0 then return end + if item_quantity.id == item then + item_quantity.count = count..' ' + end -------- ACTION MESSAGE ------- - if id == 0x29 then +------- NOUNS AND PLURAL ENTITIES ------- + elseif id == 0x00E then + local mob_id = original:unpack('I',0x05) + local mask = original:unpack('C',0x0B) + local chat_info = original:unpack('C',0x28) + if bit.band(mask,4) == 4 then + if bit.band(chat_info,32) == 0 and not common_nouns:contains(mob_id) then + table.insert(common_nouns, mob_id) + elseif bit.band(chat_info,64) == 64 and not plural_entities:contains(mob_id) then + table.insert(plural_entities, mob_id) + elseif bit.band(chat_info,64) == 0 and plural_entities:contains(mob_id) then --Gears can change their grammatical number when they lose 2 gear? + for i, v in pairs(plural_entities) do + if v == mob_id then + table.remove(plural_entities, i) + break + end + end + end + end + elseif id == 0x00B then --Reset tables on Zoning + common_nouns = T{} + plural_entities = T{} + +------- ACTION MESSAGE ------- + elseif id == 0x29 then local am = {} - am.actor_id = original:unpack("I",0x05) - am.target_id = original:unpack("I",0x09) - am.param_1 = original:unpack("I",0x0D) - am.param_2 = original:unpack("H",0x11)%2^9 -- First 7 bits - am.param_3 = math.floor(original:unpack("I",0x11)/2^5) -- Rest - am.actor_index = original:unpack("H",0x15) - am.target_index = original:unpack("H",0x17) - am.message_id = original:unpack("H",0x19)%2^15 -- Cut off the most significant bit + am.actor_id = original:unpack('I',0x05) + am.target_id = original:unpack('I',0x09) + am.param_1 = original:unpack('I',0x0D) + am.param_2 = original:unpack('H',0x11)%2^9 -- First 7 bits + am.param_3 = math.floor(original:unpack('I',0x11)/2^5) -- Rest + am.actor_index = original:unpack('H',0x15) + am.target_index = original:unpack('H',0x17) + am.message_id = original:unpack('H',0x19)%2^15 -- Cut off the most significant bit local actor = player_info(am.actor_id) local target = player_info(am.target_id) + local actor_article = common_nouns:contains(am.actor_id) and 'The ' or '' + local target_article = common_nouns:contains(am.target_id) and 'The ' or '' + targets_condensed = false -- Filter these messages if not check_filter(actor,target,0,am.message_id) then return true end if not actor or not target then -- If the actor or target table is nil, ignore the packet - elseif T{206}:contains(am.message_id) and condensetargets then -- Wears off messages + elseif am.message_id == 800 then -- Spirit bond message + local status = color_it(res.buffs[am.param_1][language],color_arr.statuscol) + local targ = color_it(target.name or '',color_arr[target.owner or target.type]) + local number = am.param_2 + local color = color_filt(res.action_messages[am.message_id].color, am.target_id==Self.id) + if simplify then + local msg = line_noactor + :gsub('${abil}',status or '') + :gsub('${target}',targ) + :gsub('${numb}',number or '') + windower.add_to_chat(color, msg) + else + local msg = res.action_messages[am.message_id][language] + msg = grammatical_number_fix(msg, number, am.message_id) + if plural_entities:contains(am.actor_id) then + msg = plural_actor(msg, am.message_id) + end + if plural_entities:contains(am.target_id) then + msg = plural_target(msg, am.message_id) + end + local msg = clean_msg(msg + :gsub('${status}',status or '') + :gsub('${target}',target_article..targ) + :gsub('${number}',number or ''), am.message_id) + windower.add_to_chat(color, msg) + end + elseif am.message_id == 206 and condensetargets then -- Wears off messages -- Condenses across multiple packets local status @@ -255,7 +365,7 @@ windower.register_event('incoming chunk',function (id,original,modified,is_injec if not multi_targs[status] and not stat_ignore:contains(am.param_1) then multi_targs[status] = {} multi_targs[status][1] = target - windower.send_command('@wait 0.5;lua i battlemod multi_packet '..status) + multi_packet:schedule(0.5, status) elseif not (stat_ignore:contains(am.param_1)) then multi_targs[status][#multi_targs[status]+1] = target else @@ -263,16 +373,23 @@ windower.register_event('incoming chunk',function (id,original,modified,is_injec -- Sneak, Invis, etc. that you don't want to see on a delay multi_targs[status] = {} multi_targs[status][1] = target - windower.send_command('@lua i battlemod multi_packet '..status) + multi_packet(status) end am.message_id = false elseif passed_messages:contains(am.message_id) then local item,status,spell,skill,number,number2 + local outstr = res.action_messages[am.message_id][language] + if plural_entities:contains(am.actor_id) then + outstr = plural_actor(outstr, am.message_id) + end + if plural_entities:contains(am.target_id) then + outstr = plural_target(outstr, am.message_id) + end - local fields = fieldsearch(res.action_messages[am.message_id][language]) + local fields = fieldsearch(outstr) if fields.status then - if log_form_debuffs:contains(am.param_1) then + if log_form_messages:contains(am.message_id) then status = res.buffs[am.param_1].english_log else status = nf(res.buffs[am.param_1],language) @@ -312,23 +429,24 @@ windower.register_event('incoming chunk',function (id,original,modified,is_injec if am.message_id > 169 and am.message_id <179 then if am.param_1 > 2147483647 then - skill = 'like level -1 ('..ratings_arr[am.param_2-63]..')' + skill = 'to be level -1 ('..ratings_arr[am.param_2-63]..')' else - skill = 'like level '..am.param_1..' ('..ratings_arr[am.param_2-63]..')' + skill = 'to be level '..am.param_1..' ('..ratings_arr[am.param_2-63]..')' end end - - local outstr = (res.action_messages[am.message_id][language] - :gsub('$\123actor\125',color_it(actor.name or '',color_arr[actor.owner or actor.type])) - :gsub('$\123status\125',status or '') - :gsub('$\123item\125',color_it(item or '',color_arr.itemcol)) - :gsub('$\123target\125',color_it(target.name or '',color_arr[target.owner or target.type])) - :gsub('$\123spell\125',color_it(spell or '',color_arr.spellcol)) - :gsub('$\123skill\125',color_it(skill or '',color_arr.abilcol)) - :gsub('$\123number\125',number or '') - :gsub('$\123number2\125',number2 or '') - :gsub('$\123skill\125',skill or '') - :gsub('$\123lb\125','\7')) + outstr = (clean_msg(outstr + :gsub('${actor}\'s',actor_article..color_it(actor.name or '',color_arr[actor.owner or actor.type])..'\'s'..actor.owner_name) + :gsub('${actor}',actor_article..color_it(actor.name or '',color_arr[actor.owner or actor.type])..actor.owner_name) + :gsub('${status}',status or '') + :gsub('${item}',color_it(item or '',color_arr.itemcol)) + :gsub('${target}\'s',target_article..color_it(target.name or '',color_arr[target.owner or target.type])..'\'s'..target.owner_name) + :gsub('${target}',target_article..color_it(target.name or '',color_arr[target.owner or target.type])..target.owner_name) + :gsub('${spell}',color_it(spell or '',color_arr.spellcol)) + :gsub('${skill}',color_it(skill or '',color_arr.abilcol)) + :gsub('${number}',number or '') + :gsub('${number2}',number2 or '') + :gsub('${skill}',skill or '') + :gsub('${lb}','\7'), am.message_id)) windower.add_to_chat(res.action_messages[am.message_id]['color'],outstr) am.message_id = false elseif debugging and res.action_messages[am.message_id] then @@ -343,9 +461,9 @@ windower.register_event('incoming chunk',function (id,original,modified,is_injec end ------------ SYNTHESIS ANIMATION -------------- - elseif id == 0x030 then - if windower.ffxi.get_player().id == original:unpack("I",5) or windower.ffxi.get_mob_by_target('t') and windower.ffxi.get_mob_by_target('t').id == original:unpack("I",5) then - local crafter_name = (windower.ffxi.get_player().id == original:unpack("I",5) and windower.ffxi.get_player().name) or windower.ffxi.get_mob_by_target('t').name + elseif id == 0x030 and crafting then + if windower.ffxi.get_player().id == original:unpack('I',5) or windower.ffxi.get_mob_by_target('t') and windower.ffxi.get_mob_by_target('t').id == original:unpack('I',5) then + local crafter_name = (windower.ffxi.get_player().id == original:unpack('I',5) and windower.ffxi.get_player().name) or windower.ffxi.get_mob_by_target('t').name local result = original:byte(13) if result == 0 then windower.add_to_chat(8,' ------------- NQ Synthesis ('..crafter_name..') -------------') @@ -357,8 +475,8 @@ windower.register_event('incoming chunk',function (id,original,modified,is_injec windower.add_to_chat(8,'Craftmod: Unhandled result '..tostring(result)) end end - elseif id == 0x06F then - if original:byte(5) == 0 then + elseif id == 0x06F and crafting then + if original:byte(5) == 0 or original:byte(5) == 12 then local result = original:byte(6) if result == 1 then windower.add_to_chat(8,' -------------- HQ Tier 1! --------------') @@ -378,9 +496,11 @@ end) function multi_packet(...) local ind = table.concat({...},' ') local targets = assemble_targets(multi_actor[ind],multi_targs[ind],0,multi_msg[ind]) - local outstr = res.action_messages[multi_msg[ind]][language] - :gsub('$\123target\125',targets) - :gsub('$\123status\125',ind) + local outstr = targets_condensed and plural_target(res.action_messages[multi_msg[ind]][language], multi_msg[ind]) or res.action_messages[multi_msg[ind]][language] + outstr = clean_msg(outstr + :gsub('${target}\'s',targets) + :gsub('${target}',targets) + :gsub('${status}',ind), multi_msg[ind]) windower.add_to_chat(res.action_messages[multi_msg[ind]].color,outstr) multi_targs[ind] = nil multi_msg[ind] = nil diff --git a/addons/battlemod/generic_helpers.lua b/addons/battlemod/generic_helpers.lua index 0bf277009f..1f015ae554 100644 --- a/addons/battlemod/generic_helpers.lua +++ b/addons/battlemod/generic_helpers.lua @@ -1,4 +1,4 @@ ---Copyright (c) 2013, Byrthnoth +--Copyright © 2013, Byrthnoth --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -39,9 +39,10 @@ end function colconv(str,key) -- Used in the options_load() function local out - strnum = tonumber(str) + local strnum = tonumber(str) if strnum >= 256 and strnum < 509 then strnum = strnum - 254 + if strnum == 4 then strnum = 3 end --color 258 can bug chatlog out = string.char(0x1E,strnum) elseif strnum >0 then out = string.char(0x1F,strnum) @@ -83,7 +84,7 @@ end function fieldsearch(message) local fieldarr = {} - string.gsub(message,"{(.-)}", function(a) fieldarr[a] = true end) + string.gsub(message,'{(.-)}', function(a) fieldarr[a] = true end) return fieldarr end @@ -114,3 +115,275 @@ function check_filter(actor,target,category,msg) return true end + +function actor_noun(msg) + if msg then + msg = msg + :gsub('${actor}', 'The ${actor}') + end + return msg +end + +function plural_actor(msg, msg_id) + if msg then + if msg_id == 6 then + msg = msg:gsub('${actor} defeats ', '${actor} defeat ') + elseif msg_id == 9 then + msg = msg:gsub('${actor} attains ', '${actor} attain ') + elseif msg_id == 10 then + msg = msg:gsub('${actor} loses ', '${actor} lose ') + elseif msg_id == 11 then + msg = msg:gsub('${actor} falls ', '${actor} fall ') + elseif msg_id == 19 then + msg = msg:gsub('${actor} calls ' , '${actor} call ') + elseif msg_id == 35 then + msg = msg:gsub('${actor} lacks ' , '${actor} lack ') + elseif msg_id == 67 then + msg = msg:gsub('${actor} scores ' , '${actor} score ') + elseif msg_id == 124 then + msg = msg:gsub('${actor} achieves ' , '${actor} achieve ') + elseif msg_id == 129 then + msg = msg:gsub('${actor} mugs ' , '${actor} mug ') + elseif msg_id == 244 then + msg = msg:gsub('${actor} fails ' , '${actor} fail ') + elseif msg_id == 311 then + msg = msg:gsub('${actor} covers ' , '${actor} cover ') + elseif msg_id == 315 then + msg = msg:gsub('${actor} already has ' , '${actor} already have ') + elseif msg_id ==411 then + msg = msg + :gsub('${actor} attempts ' , '${actor} attempt ') + :gsub(' but lacks ' , ' but lack ') + elseif msg_id == 536 then + msg = msg:gsub('${actor} takes ' , '${actor} take ') + elseif msg_id == 563 then + msg = msg:gsub('${actor} destroys ' , '${actor} destroy ') + elseif msg_id == 772 then + msg = msg:gsub('${actor} stands ', '${actor} stand ') + elseif replacements_map.actor.hits:contains(msg_id) then + msg = msg:gsub('${actor} hits ', '${actor} hit ') + elseif replacements_map.actor.misses:contains(msg_id) then + msg = msg:gsub('${actor} misses ' , '${actor} miss ') + elseif replacements_map.actor.starts:contains(msg_id) then + msg = msg:gsub('${actor} starts ', '${actor} start ') + elseif replacements_map.actor.casts:contains(msg_id) then + msg = msg:gsub('${actor} casts ', '${actor} cast ') + if msg_id == 83 then + msg = msg:gsub('${actor} successfully removes ' , '${actor} successfully remove ') + elseif msg_id == 572 or msg_id == 642 then + msg = msg:gsub('${actor} absorbs ' , '${actor} absorb ') + end + elseif replacements_map.actor.readies:contains(msg_id) then + msg = msg:gsub('${actor} readies ' , '${actor} ready ') + elseif replacements_map.actor.recovers:contains(msg_id) then + msg = msg:gsub('${actor} recovers ' , '${actor} recover ') + elseif replacements_map.actor.gains:contains(msg_id) then + msg = msg:gsub('${actor} gains ', '${actor} gain ') + elseif replacements_map.actor.apos:contains(msg_id) then + msg = msg:gsub('${actor}\'s ', '${actor}\' ') + if msg_id == 33 then + msg = msg:gsub('${actor} takes ' , '${actor} take ') + elseif msg_id == 606 then + msg = msg:gsub('${actor} recovers ' , '${actor} recover ') + elseif msg_id == 799 then + msg = msg:gsub('${actor} is ' , '${actor} are ') + end + elseif replacements_map.actor.uses:contains(msg_id) then + msg = msg:gsub('${actor} uses ' , '${actor} use ') + if msg_id == 122 then + msg = msg:gsub('${actor} recovers ' , '${actor} recover ') + elseif msg_id == 123 then + msg = msg:gsub('${actor} successfully removes ' , '${actor} successfully remove ') + elseif msg_id == 126 or msg_id == 136 or msg_id == 528 then + msg = msg:gsub('${actor}\'s ', '${actor}\' ') + elseif msg_id == 137 or msg_id == 153 then + msg = msg:gsub('${actor} fails ' , '${actor} fail ') + elseif msg_id == 139 then + msg = msg:gsub(' but finds nothing' , ' but find nothing') + elseif msg_id == 140 then + msg = msg:gsub(' and finds a ${item2}' , ' and find a ${item2}') + elseif msg_id == 158 then + msg = msg:gsub('${ability}, but misses' , '${ability}, but miss') + elseif msg_id == 585 then + msg = msg:gsub('${actor} is ' , '${actor} are ') + elseif msg_id == 674 then + msg = msg:gsub(' and finds ${number}' , ' and find ${number}') + elseif msg_id == 780 then + msg = msg:gsub('${actor} takes ' , '${actor} take ') + elseif replacements_map.actor.steals:contains(msg_id) then + msg = msg:gsub('${actor} steals ' , '${actor} steal ') + elseif replacements_map.actor.butmissestarget:contains(msg_id) then + msg = msg:gsub(' but misses ${target}' , ' but miss ${target}') + end + elseif replacements_map.actor.is:contains(msg_id) then + msg = msg:gsub('${actor} is ' , '${actor} are ') + elseif replacements_map.actor.learns:contains(msg_id) then + msg = msg:gsub('${actor} learns ' , '${actor} learn ') + elseif replacements_map.actor.has:contains(msg_id) then + msg = msg:gsub('${actor} has ' , '${actor} have ') + elseif replacements_map.actor.obtains:contains(msg_id) then + msg = msg:gsub('${actor} obtains ' , '${actor} obtain ') + elseif replacements_map.actor.does:contains(msg_id) then + msg = msg:gsub('${actor} does ' , '${actor} do ') + elseif replacements_map.actor.leads:contains(msg_id) then + msg = msg:gsub('${actor} leads ' , '${actor} lead ') + elseif replacements_map.actor.eats:contains(msg_id) then + msg = msg:gsub('${actor} eats ' , '${actor} eat ') + if msg_id == 604 then + msg = msg:gsub(' but finds nothing' , ' but find nothing') + end + elseif replacements_map.actor.earns:contains(msg_id) then + msg = msg:gsub('${actor} earns ' , '${actor} earn ') + end + end + return msg +end + +function plural_target(msg, msg_id) + if msg then + if msg_id == 282 then + msg = msg:gsub('${target} evades', '${target} evade') + elseif msg_id == 359 then + msg = msg:gsub('${target} narrowly escapes ', '${target} narrowly escape ') + elseif msg_id == 419 then + msg = msg:gsub('${target} learns ', '${target} learn ') + elseif msg_id == 671 then + msg = msg:gsub('${target} now has ', '${target} now have ') + elseif msg_id == 764 then + msg = msg:gsub('${target} feels ', '${target} feel ') + elseif replacements_map.target.takes:contains(msg_id) then + msg = msg:gsub('${target} takes ', '${target} take ') + if msg_id == 197 then + msg = msg:gsub('${target} resists', '${target} resist') + end + elseif replacements_map.target.is:contains(msg_id) then + msg = msg:gsub('${target} is ', '${target} are ') + elseif replacements_map.target.recovers:contains(msg_id) then + msg = msg:gsub('${target} recovers ', '${target} recover ') + elseif replacements_map.target.apos:contains(msg_id) then --coincidence in 439 and 440 + msg = msg:gsub('${target}\'s ', targets_condensed and '${target} ' or '${target}\' ') + if msg_id == 439 or msg_id == 440 then + msg = msg:gsub('${target} regains ', '${target} regain ') + end + elseif replacements_map.target.falls:contains(msg_id) then + msg = msg:gsub('${target} falls ', '${target} fall ') + elseif replacements_map.target.uses:contains(msg_id) then + msg = msg:gsub('${target} uses ', '${target} use ') + elseif replacements_map.target.resists:contains(msg_id) then + msg = msg:gsub('${target} resists', '${target} resist') + elseif replacements_map.target.vanishes:contains(msg_id) then + msg = msg:gsub('${target} vanishes', '${target} vanish') + elseif replacements_map.target.receives:contains(msg_id) then + msg = msg:gsub('${target} receives ', '${target} receive ') + elseif replacements_map.target.seems:contains(msg_id) then + msg = msg:gsub('${target} seems ${skill}', '${target} seem ${skill}') + if msg_id ~= 174 then + msg = msg:gsub('${lb}It seems to have ', '${lb}They seem to have ') + end + elseif replacements_map.target.gains:contains(msg_id) then + msg = msg:gsub('${target} gains ', '${target} gain ') + elseif replacements_map.target.regains:contains(msg_id) then + msg = msg:gsub('${target} regains ', '${target} regain ') + elseif replacements_map.target.obtains:contains(msg_id) then + msg = msg:gsub('${target} obtains ', '${target} obtain ') + elseif replacements_map.target.loses:contains(msg_id) then + msg = msg:gsub('${target} loses ', '${target} lose ') + elseif replacements_map.target.was:contains(msg_id) then + msg = msg:gsub('${target} was ', '${target} were ') + elseif replacements_map.target.has:contains(msg_id) then + msg = msg:gsub('${target} has ', '${target} have ') + elseif replacements_map.target.compresists:contains(msg_id) then + msg = msg:gsub('${target} completely resists ', '${target} completely resist ') + end + end + return msg +end + +function clean_msg(msg, msg_id) + if msg then + msg = msg + :gsub(' The ', ' the ') + :gsub(': the ', ': The ') + :gsub('! the ', '! The ') + if replacements_map.the.point:contains(msg_id) then + msg = msg:gsub('%. the ', '. The ') + end + end + return msg +end + +function grammatical_number_fix(msg, number, msg_id) + if msg then + if number == 1 then + if replacements_map.number.points:contains(msg_id) then + msg = msg:gsub(' points', ' point') + elseif msg_id == 411 then + msg = msg:gsub('${number} Ballista Points', '${number} Ballista Point') + elseif msg_id == 589 then + msg = msg:gsub('healed of ${number} status ailments', 'healed of ${number} status ailment') + elseif msg_id == 778 then + msg = msg:gsub('magical effects from', 'magical effect from') + end + else + if replacements_map.number.absorbs:contains(msg_id) then + msg = msg:gsub(' absorbs', ' absorb') + elseif msg_id == 133 then + msg = msg:gsub(' Petra', ' Petras') + elseif replacements_map.number.attributes:contains(msg_id) then + msg = msg:gsub('attributes is', 'attributes are') + elseif replacements_map.number.status:contains(msg_id) then + msg = msg:gsub('status effect is', 'status effects are') + elseif msg_id == 557 then + msg = msg:gsub('piece', 'pieces') + elseif msg_id == 560 then + msg = msg:gsub('Finishing move now ', 'Finishing moves now ') + end + if replacements_map.number.disappears:contains(msg_id) then + msg = msg:gsub('disappears', 'disappear') + end + end + end + return msg +end + +function item_article_fix(id,id2,msg) + if id then + if string.gmatch(msg, ' a ${item}') then + local article = res.items_grammar[id] and res.items_grammar[id].article + if article == 1 then + msg = string.gsub(msg,' a ${item}',' an ${item}') + end + end + end + if id2 then + if string.gmatch(msg, ' a ${item2}') then + local article = res.items_grammar[id2] and res.items_grammar[id2].article + if article == 1 then + msg = string.gsub(msg,' a ${item2}',' an ${item2}') + end + end + end + return msg +end + +function add_item_article(id) + local article = '' + local article_type = res.items_grammar[id] and res.items_grammar[id].article or nil + if id then + if article_type == 2 then + article = 'pair of ' + elseif article_type == 3 then + article = 'suit of ' + end + end + return article +end + +function send_delayed_message(color,msg) + local message = msg + :gsub('${count}', item_quantity.count) + windower.add_to_chat(color,message) + item_quantity.id = 0 + item_quantity.count = '' + parse_quantity = false +end diff --git a/addons/battlemod/parse_action_packet.lua b/addons/battlemod/parse_action_packet.lua index 4200b1e589..f7736d703d 100644 --- a/addons/battlemod/parse_action_packet.lua +++ b/addons/battlemod/parse_action_packet.lua @@ -10,6 +10,8 @@ function parse_action_packet(act) end act.actor = player_info(act.actor_id) act.action = get_spell(act) -- Pulls the resources line for the action + act.actor.name = act.actor and act.actor.name and string.gsub(act.actor.name,'[- ]', {['-'] = string.char(0x81,0x7C), [' '] = string.char(0x81,0x3F)}) --fix for ffxi chat splits on trusts with - and spaces + targets_condensed = false if not act.action then return act @@ -52,8 +54,8 @@ function parse_action_packet(act) if r.message ~= 0 and m.message ~= 0 then if m.message == r.message or (condensecrits and S{1,67}:contains(m.message) and S{1,67}:contains(r.message)) then - if (m.effect == r.effect) or (S{1,67}:contains(m.message) and S{0,2,4}:contains(m.effect) and S{0,2,4}:contains(r.effect)) then -- combine kicks and crits - if m.reaction == r.reaction or (S{8,10}:contains(m.reaction) and S{8,10}:contains(r.reaction)) then -- combine hits and guards + if (m.effect == r.effect) or (S{1,67}:contains(m.message) and S{0,1,2,3}:contains(m.effect) and S{0,1,2,3}:contains(r.effect)) then -- combine kicks and crits + if m.reaction == r.reaction then --or (S{8,10}:contains(m.reaction) and S{8,10}:contains(r.reaction)) then -- combine hits and guards -- windower.add_to_chat(8, 'Condensed: '..m.message..':'..r.message..' - '..m.effect..':'..r.effect..' - '..m.reaction..':'..r.reaction) r.number = r.number + 1 if not sumdamage then @@ -144,7 +146,7 @@ function parse_action_packet(act) if condensetargets and i > 1 then for n=1,i-1 do local m = act.targets[n] --- windower.add_to_chat(8,m.actions[1].message..' '..v.actions[1].message) + --windower.add_to_chat(8,m.actions[1].message..' '..v.actions[1].message) if (v.actions[1].message == m.actions[1].message and v.actions[1].param == m.actions[1].param) or (message_map[m.actions[1].message] and message_map[m.actions[1].message]:contains(v.actions[1].message) and v.actions[1].param == m.actions[1].param) or (message_map[m.actions[1].message] and message_map[m.actions[1].message]:contains(v.actions[1].message) and v.actions[1].param == m.actions[1].param) then @@ -159,18 +161,21 @@ function parse_action_packet(act) for i,v in pairs(act.targets) do for n,m in pairs(v.actions) do if m.message ~= 0 and res.action_messages[m.message] ~= nil then + local col = res.action_messages[m.message].color local targ = assemble_targets(act.actor,v.target,act.category,m.message) - local color = color_filt(res.action_messages[m.message].color,v.target[1].id==Self.id) + local color = color_filt(col,v.target[1].id==Self.id) if m.reaction == 11 and act.category == 1 then m.simp_name = 'parried by' - elseif m.reaction == 12 and act.category == 1 then m.simp_name = 'blocked by' - elseif m.message == 1 then m.simp_name = 'hit' + --elseif m.reaction == 12 and act.category == 1 then m.simp_name = 'blocked by' + elseif m.message == 1 and (act.category == 1 or act.category == 11) then m.simp_name = 'hit' elseif m.message == 15 then m.simp_name = 'missed' elseif m.message == 29 or m.message == 84 then m.simp_name = 'is paralyzed' elseif m.message == 30 then m.simp_name = 'anticipated by' elseif m.message == 31 then m.simp_name = 'absorbed by' elseif m.message == 32 then m.simp_name = 'dodged by' - elseif m.message == 67 then m.simp_name = 'critical hit' + elseif m.message == 67 and (act.category == 1 or act.category == 11) then m.simp_name = 'critical hit' elseif m.message == 106 then m.simp_name = 'intimidated by' + elseif m.message == 153 then m.simp_name = act.action.name..' fails' + elseif m.message == 244 then m.simp_name = 'Mug fails' elseif m.message == 282 then m.simp_name = 'evaded by' elseif m.message == 373 then m.simp_name = 'absorbed by' elseif m.message == 352 then m.simp_name = 'RA' @@ -179,26 +184,62 @@ function parse_action_packet(act) elseif m.message == 576 then m.simp_name = 'RA hit squarely' elseif m.message == 577 then m.simp_name = 'RA struck true' elseif m.message == 157 then m.simp_name = 'Barrage' + elseif m.message == 76 then m.simp_name = 'No targets within range' elseif m.message == 77 then m.simp_name = 'Sange' elseif m.message == 360 then m.simp_name = act.action.name..' (JA reset)' elseif m.message == 426 or m.message == 427 then m.simp_name = 'Bust! '..act.action.name elseif m.message == 435 or m.message == 436 then m.simp_name = act.action.name..' (JAs)' elseif m.message == 437 or m.message == 438 then m.simp_name = act.action.name..' (JAs and TP)' elseif m.message == 439 or m.message == 440 then m.simp_name = act.action.name..' (SPs, JAs, TP, and MP)' - elseif T{252,265,268,269,271,272,274,275,379,650}:contains(m.message) then m.simp_name = 'Magic Burst! '..act.action.name - elseif not act.action then + elseif T{252,265,268,269,271,272,274,275,379,650,747}:contains(m.message) then m.simp_name = 'Magic Burst! '..act.action.name + elseif not act.action then m.simp_name = '' act.action = {} else m.simp_name = act.action.name or '' end --- if m.message == 93 or m.message == 273 then m.status=color_it('Vanish',color_arr['statuscol']) end + -- Debuff Application Messages + if simplify and message_map[82]:contains(m.message) then + if m.status == 'Evasion Down' then + m.message = 237 + end + if m.status == 'addle' then m.status = 'addled' + elseif m.status == 'bind' then m.status = 'bound' + elseif m.status == 'blindness' then m.status = 'blinded' + elseif m.status == 'Inundation' then m.status = 'inundated' + elseif m.status == 'paralysis' then m.status = 'paralyzed' + elseif m.status == 'petrification' then m.status = 'petrified' + elseif m.status == 'poison' then m.status = 'poisoned' + elseif m.status == 'silence' then m.status = 'silenced' + elseif m.status == 'sleep' then m.status = 'asleep' + elseif m.status == 'slow' then m.status = 'slowed' + elseif m.status == 'stun' then m.status = 'stunned' + elseif m.status == 'weight' then m.status = 'weighed down' + end + end + + -- Some messages uses the english log version of the buff + if not simplify and log_form_messages:contains(m.message) then + m.status = res.buffs[m.param].enl + end + + -- if m.message == 93 or m.message == 273 then m.status=color_it('Vanish',color_arr['statuscol']) end -- Special Message Handling if m.message == 93 or m.message == 273 then m.status=color_it('Vanish',color_arr['statuscol']) elseif m.message == 522 and simplify then - targ = targ..' (stunned)' + targ = targ..' ('..color_it('stunned',color_arr['statuscol'])..')' + elseif m.message == 416 and simplify then + targ = targ..' ('..color_it('Magic Attack Boost and Magic Defense Boost',color_arr['statuscol'])..')' + elseif m.message == 1023 and simplify then + targ = targ..' ('..color_it('attacks and defenses enhanced',color_arr['statuscol'])..')' + elseif m.message == 762 and simplify then + targ = targ..' ('..color_it('all status parameters boosted',color_arr['statuscol'])..')' + elseif m.message == 779 and simplify then + targ = 'A barrier pulsates around '..targ + elseif m.message == 780 and simplify then + targ = 'Takes aim on '..targ elseif T{158,188,245,324,592,658}:contains(m.message) and simplify then -- When you miss a WS or JA. Relevant for condensed battle. m.status = 'Miss' --- This probably doesn't work due to the if a==nil statement below. @@ -207,9 +248,13 @@ function parse_action_packet(act) elseif m.message == 655 or m.message == 656 then m.status = color_it('Completely Resists',color_arr['statuscol']) elseif m.message == 85 or m.message == 284 then - m.status = color_it('Resists',color_arr['statuscol']) + if m.unknown == 2 then + m.status = color_it('Resists!',color_arr['statuscol']) + else + m.status = color_it('Resists',color_arr['statuscol']) + end elseif m.message == 351 then - m.status = color_it('status ailments',color_arr['statscol']) + m.status = color_it('status ailments',color_arr['statuscol']) m.simp_name = color_it('remedy',color_arr['itemcol']) elseif T{75,114,156,189,248,283,312,323,336,355,408,422,423,425,659}:contains(m.message) then m.status = color_it('No effect',color_arr['statuscol']) -- The status code for "No Effect" is 255, so it might actually work without this line @@ -223,95 +268,178 @@ function parse_action_packet(act) end local msg,numb = simplify_message(m.message) if not color_arr[act.actor.owner or act.actor.type] then windower.add_to_chat(123,'Battlemod error, missing filter:'..tostring(act.actor.owner)..' '..tostring(act.actor.type)) end - if m.fields.status then numb = m.status else numb = pref_suf((m.cparam or m.param),m.message) end + if m.fields.status then numb = m.status else numb = pref_suf((m.message == 674 and m.add_effect_param or m.cparam or m.param),m.message,act.actor.damage,col) end if msg and m.message == 70 and not simplify then -- fix pronoun on parry - if act.actor.race == 0 then + if v.target[1].race == 0 then msg = msg:gsub(' his ',' its ') - elseif female_races:contains(act.actor.race) then + elseif female_races:contains(v.target[1].race) then msg = msg:gsub(' his ',' her ') end end - local prefix = (bit.band(m.unknown,1)==1 and "Cover! " or "")..(bit.band(m.unknown,2)==1 and "Resist! " or "")..(bit.band(m.unknown,4)==1 and "Magic Burst! " or "")..(bit.band(m.unknown,8)==1 and "Immunobreak! " or "")..(bit.band(m.unknown,16)==1 and "Critical Hit! " or "") - windower.add_to_chat(color,prefix..make_condensedamage_number(m.number)..( (msg or tostring(m.message)) - :gsub('${spell}',color_it(act.action.spell or 'ERROR 111',color_arr.spellcol)) + + local count = '' + if m.message == 377 and act.actor_id == Self.id then + parse_quantity = true + item_quantity.id = act.action.item2_id + count = '${count}' + end + + if not simplify then + if col == 'D' or grammar_numb_msg:contains(m.message) then + msg = grammatical_number_fix(msg, (m.cparam or m.param), m.message) + end + if act.action.item_id or act.action.item2_id then + msg = item_article_fix(act.action.item_id,act.action.item2_id,msg) + end + if common_nouns:contains(act.actor.id) then + msg = actor_noun(msg) + end + if plural_entities:contains(act.actor.id) then + msg = plural_actor(msg, m.message) + end + if targets_condensed or plural_entities:contains(v.target[1].id) then + msg = plural_target(msg, m.message) + end + end + + local roll = showrollinfo and act.category == 6 and corsair_rolls[act.param] and corsair_rolls[act.param][m.param] or '' + local reaction_lookup = reaction_offsets[act.category] and (m.reaction - reaction_offsets[act.category]) or 0 + local has_line_break = string.find(res.action_messages[m.message].en, '${lb}') and true or false + local prefix = (not has_line_break or simplify) and get_prefix(act.category, m.effect, m.message, m.unknown, reaction_lookup) or '' + local prefix2 = has_line_break and get_prefix(act.category, m.effect, m.message, m.unknown, reaction_lookup) or '' + local message = prefix..make_condensedamage_number(m.number)..( clean_msg((msg or tostring(m.message)) + :gsub('${spell}',act.action.spell or 'ERROR 111') :gsub('${ability}',color_it(act.action.ability or 'ERROR 112',color_arr.abilcol)) :gsub('${item}',color_it(act.action.item or 'ERROR 113',color_arr.itemcol)) - :gsub('${item2}',color_it(act.action.item2 or 'ERROR 121',color_arr.itemcol)) - :gsub('${weapon_skill}',color_it(act.action.weapon_skill or 'ERROR 114',color_arr.wscol)) + :gsub('${item2}',count..color_it(act.action.item2 or 'ERROR 121',color_arr.itemcol)) + :gsub('${weapon_skill}',act.action.weapon_skill or 'ERROR 114') :gsub('${abil}',m.simp_name or 'ERROR 115') - :gsub('${numb}',numb or 'ERROR 116') - :gsub('${actor}',color_it(act.actor.name or 'ERROR 117',color_arr[act.actor.owner or act.actor.type])) + :gsub('${numb}',numb..roll or 'ERROR 116') + :gsub('${actor}\'s',color_it(act.actor.name or 'ERROR 117',color_arr[act.actor.owner or act.actor.type])..'\'s'..act.actor.owner_name) + :gsub('${actor}',color_it(act.actor.name or 'ERROR 117',color_arr[act.actor.owner or act.actor.type])..act.actor.owner_name) + :gsub('${target}\'s',targ) :gsub('${target}',targ) - :gsub('${lb}','\7') - :gsub('${number}',act.action.number or m.param) + :gsub('${lb}','\7'..prefix2) + :gsub('${number}',(act.action.number or m.param)..roll) :gsub('${status}',m.status or 'ERROR 120') - :gsub('${gil}',m.param..' gil'))) - m.message = 0 + :gsub('${gil}',m.param..' gil'), m.message)) + if m.message == 377 and act.actor_id == Self.id then + send_delayed_message:schedule(0.5,color,message) + else + windower.add_to_chat(color,message) + end + if not non_block_messages:contains(m.message) then + m.message = 0 + end end if m.has_add_effect and m.add_effect_message ~= 0 and add_effect_valid[act.category] then - local targ = assemble_targets(act.actor,v.target,act.category,m.add_effect_message) - local color = color_filt(res.action_messages[m.add_effect_message].color,v.target[1].id==Self.id) + local targ = assemble_targets(act.actor,v.target,act.category,m.add_effect_message,m.has_add_effect) + local col = res.action_messages[m.add_effect_message].color + local color = color_filt(col,v.target[1].id==Self.id) if m.add_effect_message > 287 and m.add_effect_message < 303 then m.simp_add_name = skillchain_arr[m.add_effect_message-287] elseif m.add_effect_message > 384 and m.add_effect_message < 399 then m.simp_add_name = skillchain_arr[m.add_effect_message-384] elseif m.add_effect_message > 766 and m.add_effect_message < 769 then m.simp_add_name = skillchain_arr[m.add_effect_message-752] elseif m.add_effect_message > 768 and m.add_effect_message < 771 then m.simp_add_name = skillchain_arr[m.add_effect_message-754] - elseif m.add_effect_message ==603 then m.simp_add_name = 'TH' + elseif m.add_effect_message == 603 then m.simp_add_name = 'AE: TH' + elseif m.add_effect_message == 605 then m.simp_add_name = 'AE: Death' + elseif m.add_effect_message == 776 then m.simp_add_name = 'AE: Chainbound' else m.simp_add_name = 'AE' end local msg,numb = simplify_message(m.add_effect_message) - if m.add_effect_fields.status then numb = m.add_effect_status else numb = pref_suf((m.cadd_effect_param or m.add_effect_param),m.add_effect_message) end + if not simplify then + if col == 'D' or grammar_numb_msg:contains(m.add_effect_message) then + msg = grammatical_number_fix(msg, (m.cparam or m.param), m.add_effect_message) + end + if common_nouns:contains(act.actor.id) then + msg = actor_noun(msg) + end + if plural_entities:contains(act.actor.id) then + msg = plural_actor(msg, m.add_effect_message) + end + if targets_condensed or plural_entities:contains(v.target[1].id) then + msg = plural_target(msg, m.add_effect_message) + end + end + if m.add_effect_fields.status then numb = m.add_effect_status else numb = pref_suf((m.cadd_effect_param or m.add_effect_param),m.add_effect_message,act.actor.damage,col) end if not act.action then -- windower.add_to_chat(color, 'act.action==nil : '..m.message..' - '..m.add_effect_message..' - '..msg) else - windower.add_to_chat(color,make_condensedamage_number(m.add_effect_number)..(msg + windower.add_to_chat(color,make_condensedamage_number(m.add_effect_number)..(clean_msg(msg :gsub('${spell}',act.action.spell or 'ERROR 127') :gsub('${ability}',act.action.ability or 'ERROR 128') :gsub('${item}',act.action.item or 'ERROR 129') :gsub('${weapon_skill}',act.action.weapon_skill or 'ERROR 130') :gsub('${abil}',m.simp_add_name or act.action.name or 'ERROR 131') :gsub('${numb}',numb or 'ERROR 132') - :gsub('${actor}',color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])) + :gsub('${actor}\'s',color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..'\'s'..act.actor.owner_name) + :gsub('${actor}',color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..act.actor.owner_name) + :gsub('${target}\'s',targ) :gsub('${target}',targ) :gsub('${lb}','\7') :gsub('${number}',m.add_effect_param) - :gsub('${status}',m.add_effect_status or 'ERROR 178'))) - m.add_effect_message = 0 + :gsub('${status}',m.add_effect_status or 'ERROR 178'), m.add_effect_message))) + if not non_block_messages:contains(m.add_effect_message) then + m.add_effect_message = 0 + end end end if m.has_spike_effect and m.spike_effect_message ~= 0 and spike_effect_valid[act.category] then - local targ = assemble_targets(act.actor,v.target,act.category,m.spike_effect_message) - local color = color_filt(res.action_messages[m.spike_effect_message].color,act.actor.id==Self.id) + local targ = assemble_targets(act.actor,v.target,act.category,m.spike_effect_message, m.has_spike_effect) + local col = res.action_messages[m.spike_effect_message].color + local color = color_filt(col,act.actor.id==Self.id) + local actor = act.actor if m.spike_effect_message == 14 then m.simp_spike_name = 'from counter' elseif T{33,606}:contains(m.spike_effect_message) then m.simp_spike_name = 'counter' + actor = v.target[1] --Counter dmg is done by the target, fix for coloring the dmg elseif m.spike_effect_message == 592 then m.simp_spike_name = 'missed counter' elseif m.spike_effect_message == 536 then m.simp_spike_name = 'retaliation' + actor = v.target[1] --Retaliation dmg is done by the target, fix for coloring the dmg elseif m.spike_effect_message == 535 then m.simp_spike_name = 'from retaliation' else m.simp_spike_name = 'spikes' + actor = v.target[1] --Spikes dmg is done by the target, fix for coloring the dmg end local msg = simplify_message(m.spike_effect_message) - if m.spike_effect_fields.status then numb = m.spike_effect_status else numb = pref_suf((m.cspike_effect_param or m.spike_effect_param),m.spike_effect_message) end - windower.add_to_chat(color,make_condensedamage_number(m.spike_effect_number)..(msg + if not simplify then + if col == 'D' or grammar_numb_msg:contains(m.spike_effect_message) then + msg = grammatical_number_fix(msg, (m.cparam or m.param), m.spike_effect_message) + end + if common_nouns:contains(act.actor.id) then + msg = actor_noun(msg) + end + if plural_entities:contains(act.actor.id) then + msg = plural_actor(msg, m.spike_effect_message) + end + if targets_condensed or plural_entities:contains(v.target[1].id) then + msg = plural_target(msg, m.spike_effect_message) + end + end + if m.spike_effect_fields.status then numb = m.spike_effect_status else numb = pref_suf((m.cspike_effect_param or m.spike_effect_param),m.spike_effect_message,actor.damage,col) end + windower.add_to_chat(color,make_condensedamage_number(m.spike_effect_number)..(clean_msg(msg :gsub('${spell}',act.action.spell or 'ERROR 142') :gsub('${ability}',act.action.ability or 'ERROR 143') :gsub('${item}',act.action.item or 'ERROR 144') :gsub('${weapon_skill}',act.action.weapon_skill or 'ERROR 145') :gsub('${abil}',m.simp_spike_name or act.action.name or 'ERROR 146') :gsub('${numb}',numb or 'ERROR 147') - :gsub((simplify and '${target}' or '${actor}'),color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])) + :gsub('${actor}\'s',color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..'\'s'..act.actor.owner_name) + :gsub((simplify and '${target}' or '${actor}'),color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..act.actor.owner_name) + :gsub('${target}\'s',targ) :gsub((simplify and '${actor}' or '${target}'),targ) :gsub('${lb}','\7') :gsub('${number}',m.spike_effect_param) - :gsub('${status}',m.spike_effect_status or 'ERROR 150'))) - m.spike_effect_message = 0 + :gsub('${status}',m.spike_effect_status or 'ERROR 150'), m.spike_effect_message))) + if not non_block_messages:contains(m.spike_effect_message) then + m.spike_effect_message = 0 + end end end end @@ -319,13 +447,46 @@ function parse_action_packet(act) return act end -function pref_suf(param,msg_ID) - local outstr = tostring(param) - if res.action_messages[msg_ID] and res.action_messages[msg_ID].prefix then - outstr = res.action_messages[msg_ID].prefix..' '..outstr - end - if res.action_messages[msg_ID] and res.action_messages[msg_ID].suffix then - outstr = outstr..' '..res.action_messages[msg_ID].suffix +function pref_suf(param,msg_ID,actor_dmg,col) + local outstr = (col == 'D' or dmg_drain_msg:contains(msg_ID)) and color_it(tostring(param),color_arr[actor_dmg]) or tostring(param) + local msg = res.action_messages[msg_ID] or nil + if msg then + if msg.prefix then + outstr = msg.prefix..' '..outstr + end + if msg.suffix then + if msg.suffix == 'shadow' and param ~= 1 then + outstr = outstr..' shadows' + elseif msg.suffix == 'Petra' and param ~= 1 then + outstr = outstr..' Petras' + elseif msg.suffix == 'effects disappears' and param ~= 1 then + outstr = outstr..' effects disappear' + elseif msg_ID == 641 then + outstr = outstr..' 1 attribute drained' + elseif msg.suffix == 'attributes drained' and param == 1 then + outstr = outstr..' attribute drained' + elseif msg.suffix == 'status effect drained' and param ~= 1 then + outstr = outstr..' status effects drained' + elseif msg.suffix == 'status ailments disappears' and param ~= 1 then + outstr = outstr..' status ailments disappear' + elseif msg.suffix == 'status ailments absorbed' and param == 1 then + outstr = outstr..' status ailment absorbed' + elseif msg.suffix == 'status ailments healed' and param == 1 then + outstr = outstr..' status ailment healed' + elseif msg.suffix == 'status benefits absorbed' and param == 1 then + outstr = outstr..' status benefit absorbed' + elseif msg.suffix == 'status effects removed' and param == 1 then + outstr = outstr..' status effect removed' + elseif msg.suffix == 'magic effects drained' and param == 1 then + outstr = outstr..' magic effect drained' + elseif msg.suffix == 'magical effects received' and param == 1 then + outstr = outstr..' magical effect received' + elseif msg.suffix == 'magical effects copied' and param == 1 then + outstr = outstr..' magical effect copied' + else + outstr = outstr..' '..msg.suffix + end + end end return outstr end @@ -334,23 +495,33 @@ function simplify_message(msg_ID) local msg = res.action_messages[msg_ID][language] local fields = fieldsearch(msg) - if simplify and not T{23,64,125,129,133,139,140,153,204,210,211,212,213,214,244,350,442,453,516,531,557,565,582,593,594,595,596,597,598,599,674}:contains(msg_ID) then - if T{93,273,522,653,654,655,656,85,284,75,114,156,189,248,283,312,323,336,351,355,408,422,423,425,659,158,245,324,658}:contains(msg_ID) then + if simplify and not T{23,64,133,204,210,211,212,213,214,350,442,516,531,557,565,582}:contains(msg_ID) then + if T{93,273,522,653,654,655,656,85,284,75,114,156,189,248,283,312,323,336,351,355,408,422,423,425,453,659,158,245,324,658}:contains(msg_ID) then fields.status = true end - if msg_ID == 31 then + if msg_ID == 31 or msg_ID == 798 or msg_ID == 799 then fields.actor = true - end + end if (msg_ID > 287 and msg_ID < 303) or (msg_ID > 384 and msg_ID < 399) or (msg_ID > 766 and msg_ID < 771) or - T{152,161,162,163,165,229,384,603,652}:contains(msg_ID) then + T{129,152,161,162,163,165,229,384,453,603,652,798}:contains(msg_ID) then fields.ability = true end - if T{152,160,161,162,163,164,165,166,167,168,229,652}:contains(msg_ID) then + if T{125,593,594,595,596,597,598,599}:contains(msg_ID) then + fields.ability = true + fields.item = true + end + + if T{129,152,153,160,161,162,163,164,165,166,167,168,229,244,652}:contains(msg_ID) then fields.actor = true fields.target = true end + + if msg_ID == 139 then + fields.number = true + end + local Despoil_msg = {[593] = 'Attack Down', [594] = 'Defense Down', [595] = 'Magic Atk. Down', [596] = 'Magic Def. Down', [597] = 'Evasion Down', [598] = 'Accuracy Down', [599] = 'Slow',} if line_full and fields.number and fields.target and fields.actor then msg = line_full elseif line_aoebuff and fields.status and fields.target then --and fields.actor then -- and (fields.spell or fields.ability or fields.item or fields.weapon_skill) then @@ -361,6 +532,12 @@ function simplify_message(msg_ID) else msg = line_item end + elseif line_steal and fields.item and fields.ability then + if T{593,594,595,596,597,598,599}:contains(msg_ID) then + msg = line_steal..''..string.char(0x07)..'AE: '..color_it(Despoil_msg[msg_ID],color_arr['statuscol']) + else + msg = line_steal + end elseif line_nonumber and not fields.number then msg = line_nonumber elseif line_aoe and T{264}:contains(msg_ID) then @@ -369,35 +546,66 @@ function simplify_message(msg_ID) msg = line_noactor elseif line_noability and not fields.actor then msg = line_noability + elseif line_notarget and fields.actor and fields.number then + if msg_ID == 798 then --Maneuver message + msg = line_notarget..'%' + elseif msg_ID == 799 then --Maneuver message with overload + msg = line_notarget..'% (${actor} overloaded)' + else + msg = line_notarget + end end end return msg end -function assemble_targets(actor,targs,category,msg) +function assemble_targets(actor,targs,category,msg,add_effect) local targets = {} + local samename = {} + local total = 0 for i,v in pairs(targs) do -- Done in two loops so that the ands and commas don't get out of place. -- This loop filters out unwanted targets. - if check_filter(actor,v,category,msg) then - targets[#targets+1] = v + if check_filter(actor,v,category,msg) or check_filter(v,actor,category,msg) then + if samename[v.name] and condensetargetname then + samename[v.name] = samename[v.name] + 1 + else + targets[#targets+1] = v + samename[v.name] = 1 + end + total = total + 1 end + if add_effect then break end end - local out_str - if targetnumber and #targets > 1 then - out_str = '{'..#targets..'} ' + if targetnumber and total > 1 then + out_str = '{'..total..'}: ' else out_str = '' end for i,v in pairs(targets) do + local name = string.gsub(v.name,' ', string.char(0x81,0x3F)) --fix for ffxi chat splits on space + local article = common_nouns:contains(v.id) and (not simplify or msg == 206) and 'The ' or '' + local numb = condensetargetname and samename[v.name] > 1 and ' {'..samename[v.name]..'}' or '' if i == 1 then - out_str = out_str..color_it(v.name,color_arr[v.owner or v.type]) + name = color_it(name,color_arr[v.owner or v.type])..v.owner_name + if samename[v.name] > 1 then + targets_condensed = true + else + if (not simplify or msg == 206) and #targets == 1 and string.find(res.action_messages[msg][language], '${target}\'s') then + name = color_it(name,color_arr[v.owner or v.type])..(plural_entities:contains(v.id) and '\'' or '\'s')..v.owner_name + end + targets_condensed = false + end + out_str = out_str..article..name..numb else - out_str = conjunctions(out_str,color_it(v.name,color_arr[v.owner or v.type]),#targets,i) + targets_condensed = true + name = color_it(name,color_arr[v.owner or v.type])..v.owner_name + out_str = conjunctions(out_str,article..name..numb,#targets,i) end end + out_str = string.gsub(out_str,'-', string.char(0x81,0x7C)) --fix for ffxi chat splits on trusts with - return out_str end @@ -411,10 +619,10 @@ end function player_info(id) local player_table = windower.ffxi.get_mob_by_id(id) - local typ,owner,filt + local typ,dmg,owner,filt,owner_name if player_table == nil then - return {name=nil,id=nil,is_npc=nil,type='debug',owner=nil,race=nil} + return {name=nil,id=nil,is_npc=nil,type='debug',owner=nil, owner_name=nil,race=nil} end for i,v in pairs(windower.ffxi.get_party()) do @@ -422,40 +630,49 @@ function player_info(id) typ = i if i == 'p0' then filt = 'me' + dmg = 'mydmg' elseif i:sub(1,1) == 'p' then filt = 'party' + dmg = 'partydmg' else filt = 'alliance' + dmg = 'allydmg' end end end if not filt then if player_table.is_npc then - if player_table.id%4096>2047 then + if player_table.index>1791 or player_table.charmed then typ = 'other_pets' filt = 'other_pets' owner = 'other' + dmg = 'otherdmg' for i,v in pairs(windower.ffxi.get_party()) do if type(v) == 'table' and v.mob and v.mob.pet_index and v.mob.pet_index == player_table.index then if i == 'p0' then typ = 'my_pet' filt = 'my_pet' + dmg = 'mydmg' end owner = i + owner_name = showownernames and ' ('..color_it(v.mob.name, color_arr[owner or typ])..')' break elseif type(v) == 'table' and v.mob and v.mob.fellow_index and v.mob.fellow_index == player_table.index then if i == 'p0' then typ = 'my_fellow' filt = 'my_fellow' + dmg = 'mydmg' end owner = i + owner_name = showownernames and ' ('..color_it(v.mob.name, color_arr[owner or typ])..')' break end end else typ = 'mob' filt = 'monsters' + dmg = 'mobdmg' if filter.enemies then for i,v in pairs(Self.buffs) do @@ -480,10 +697,11 @@ function player_info(id) else typ = 'other' filt = 'others' + dmg = 'otherdmg' end end if not typ then typ = 'debug' end - return {name=player_table.name,id=id,is_npc = player_table.is_npc,type=typ,filter=filt,owner=(owner or nil),race = player_table.race} + return {name=player_table.monstrosity_name or player_table.name,id=id,is_npc = player_table.is_npc,type=typ,damage=dmg,filter=filt,owner=(owner or nil), owner_name=(owner_name or ''),race = player_table.race} end function get_spell(act) @@ -519,6 +737,16 @@ function get_spell(act) spell.japanese = spell.english spell.french = spell.english end + elseif msg_ID == 673 then + spell.english = 'Mweya Plasm' + spell.german = spell.english + spell.japanese = spell.english + spell.french = spell.english + elseif msg_ID == 105 then + spell.english = 'Experience Points' + spell.german = spell.english + spell.japanese = spell.english + spell.french = spell.english else if not res.action_messages[msg_ID] then if T{4,8}:contains(act['category']) then @@ -544,14 +772,17 @@ function get_spell(act) if fields.spell then spell = res.spells[abil_ID] if spell then - spell.name = color_it(spell[language],color_arr.spellcol) - spell.spell = color_it(spell[language],color_arr.spellcol) + spell.name = color_it(spell[language],act.actor.type == 'mob' and color_arr.mobspellcol or color_arr.spellcol) + spell.spell = color_it(spell[language],act.actor.type == 'mob' and color_arr.mobspellcol or color_arr.spellcol) end elseif fields.ability then spell = res.job_abilities[abil_ID] if spell then spell.name = color_it(spell[language],color_arr.abilcol) spell.ability = color_it(spell[language],color_arr.abilcol) + if msg_ID == 139 then + spell.number = 'Nothing' + end end elseif fields.weapon_skill then if abil_ID > 256 then -- WZ_RECOVER_ALL is used by chests in Limbus @@ -563,8 +794,8 @@ function get_spell(act) spell = res.weapon_skills[abil_ID] end if spell then - spell.name = color_it(spell[language],color_arr.wscol) - spell.weapon_skill = color_it(spell[language],color_arr.wscol) + spell.name = color_it(spell[language],act.actor.type == 'mob' and color_arr.mobwscol or color_arr.wscol) + spell.weapon_skill = color_it(spell[language],act.actor.type == 'mob' and color_arr.mobwscol or color_arr.wscol) end elseif msg_ID == 303 then spell = res.job_abilities[74] -- Divine Seal @@ -600,19 +831,25 @@ function get_spell(act) if fields.item then if T{125,593,594,595,596,597,598,599}:contains(msg_ID) then - spell.item = color_it(res.items[effect_val]['english_log'], color_arr.itemcol) + local item_article = not simplify and add_item_article(effect_val) or '' + spell.item = color_it(item_article..res.items[effect_val]['english_log'], color_arr.itemcol) + spell.item_id = res.items[effect_val].id else spell = res.items[abil_ID] + local item_article = not simplify and add_item_article(spell.id) or '' if spell then - spell.name = color_it(spell['english_log'],color_arr.itemcol) - spell.item = color_it(spell['english_log'],color_arr.itemcol) + spell.name = color_it(item_article..spell['english_log'],color_arr.itemcol) + spell.item = color_it(item_article..spell['english_log'],color_arr.itemcol) + spell.item_id = abil_ID end end end if fields.item2 then - local tempspell = res.items[effect_val] - spell.item2 = color_it(tempspell.english_log,color_arr.itemcol) + local item_article = not simplify and add_item_article(effect_val) or '' + local tempspell = (msg_ID == 377 or msg_ID == 674) and res.items_grammar[effect_val] and res.items_grammar[effect_val].plural or item_article..res.items[effect_val].english_log + spell.item2 = color_it(tempspell,color_arr.itemcol) + spell.item2_id = effect_val if fields.number then spell.number = act.targets[1].actions[1].add_effect_param end @@ -629,37 +866,37 @@ function color_filt(col,is_me) --Depends on whether or not the target is you, the same as using in-game colors -- Returns a color code for windower.add_to_chat() -- Does not currently support a Debuff/Buff distinction - if col == "D" then -- Damage + if col == 'D' then -- Damage if is_me then return 28 else return 20 end - elseif col == "M" then -- Misses + elseif col == 'M' then -- Misses if is_me then return 29 else return 21 end - elseif col == "H" then -- Healing + elseif col == 'H' then -- Healing if is_me then return 30 else return 22 end - elseif col == "B" then -- Beneficial effects + elseif col == 'B' then -- Beneficial effects if is_me then return 56 else return 60 end - elseif col == "DB" then -- Detrimental effects (I don't know how I'd split these) + elseif col == 'DB' then -- Detrimental effects (I don't know how I'd split these) if is_me then return 57 else return 61 end - elseif col == "R" then -- Resists + elseif col == 'R' then -- Resists if is_me then return 59 else @@ -670,6 +907,17 @@ function color_filt(col,is_me) end end +function get_prefix(category, effect, message, unknown, reaction_lookup) + local prefix = S{1,3,4,6,11,13,14,15}:contains(category) and (bit.band(unknown,1)==1 and 'Cover! ' or '') + ..(bit.band(unknown,4)==4 and 'Magic Burst! ' or '') --Used on Swipe/Lunge MB + ..(bit.band(unknown,8)==8 and 'Immunobreak! ' or '') --Unused? Displayed directly on message + ..(showcritws and bit.band(effect,2)==2 and S{1,3,11}:contains(category) and message~=67 and 'Critical Hit! ' or '') --Unused? Crits have their own message + ..(showblocks and reaction_lookup == 4 and 'Blocked! ' or '') + ..(showguards and reaction_lookup == 2 and 'Guarded! ' or '') + ..(reaction_lookup == 3 and S{3,4,6,11,13,14,15}:contains(category) and 'Parried! ' or '') --Unused? They are send the same as missed + return prefix +end + function condense_actions(action_array) for i,v in pairs(action_array) do local comb_table = {} diff --git a/addons/battlemod/statics.lua b/addons/battlemod/statics.lua index 7acf2ac55a..8abe43eb63 100644 --- a/addons/battlemod/statics.lua +++ b/addons/battlemod/statics.lua @@ -1,4 +1,4 @@ - --Copyright (c) 2013, Byrthnoth + --Copyright © 2013, Byrthnoth --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -25,15 +25,113 @@ --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. language = 'english' skillchain_arr = {'Light:','Darkness:','Gravitation:','Fragmentation:','Distortion:','Fusion:','Compression:','Liquefaction:','Induration:','Reverberation:','Transfixion:','Scission:','Detonation:','Impaction:','Radiance:','Umbra:'} -ratings_arr = {'TW','EEP','EP','DC','EM','T','VT','IT'} +ratings_arr = {'TW','IEP','EP','DC','EM','T','VT','IT'} current_job = 'NONE' default_filt = false +parse_quantity = false +targets_condensed = false +common_nouns = T{} +plural_entities = T{} +item_quantity = {id = 0, count = ''} rcol = string.char(0x1E,0x01) -passed_messages = T{4,5,6,16,17,18,20,34,35,36,40,47,48,49,64,78,87,88,89,90,112,116,154,170,171,172,173,174,175,176,177,178,191,192,198,204,215,217,218,219,234,246,249,307,315,328,350,336,523,530,531,558,561,563,575,584,601,609,562,610,611,612,613,614,615,616,617,618,619,620,625,626,627,628,629,630,631,632,633,634,635,636,643,660,661,662,62,94,251,308,313,372,8,105,253,679,97,62,94,251,313,308,206,72,38,53} +non_block_messages = T{1,2,7,14,15,24,25,26,30,31,32,33,44,63,67,69,70,77,102,103,110,122,132,152,157,158,161,162,163,165,167,185,187,188,196,197,223,224,225,226,227,228,229,238,245,252,263,264,265,274,275,276,281,282,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,306,317,318,324,352,353,354,357,358,366,367,373,379,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,409,413,451,452,454,522,535,536,537,539,576,577,587,588,592,603,606,648,650,651,658,732,736,746,747,748,749,750,751,752,753,767,768,769,770,781} +passed_messages = T{4,5,6,16,17,18,20,34,35,36,38,40,47,48,49,53,62,64,72,78,87,88,89,90,94,97,112,116,154,170,171,172,173,174,175,176,177,178,191,192,198,204,206,215,217,218,219,234,246,249,251,307,308,313,315,328,336,350,523,530,531,558,561,563,575,584,601,609,562,610,611,612,613,614,615,616,617,618,619,620,625,626,627,628,629,630,631,632,633,634,635,636,643,660,661,662,679} agg_messages = T{85,653,655,75,156,189,248,323,355,408,422,425,82,93,116,127,131,134,151,144,146,148,150,166,186,194,230,236,237,242,243,268,271,319,320,364,375,412,414,416,420,424,426,432,433,441,602,645,668,435,437,439} color_redundant = T{26,33,41,71,72,89,94,109,114,164,173,181,184,186,70,84,104,127,128,129,130,131,132,133,134,135,136,137,138,139,140,64,86,91,106,111,175,178,183,81,101,16,65,87,92,107,112,174,176,182,82,102,67,68,69,170,189,15,208,18,25,32,40,163,185,23,24,27,34,35,42,43,162,165,187,188,30,31,14,205,144,145,146,147,148,149,150,151,152,153,190,13,9,253,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,284,285,286,287,292,293,294,295,300,301,301,303,308,309,310,311,316,317,318,319,324,325,326,327,332,333,334,335,340,341,342,343,344,345,346,347,348,349,350,351,355,357,358,360,361,363,366,369,372,374,375,378,381,384,395,406,409,412,415,416,418,421,424,437,450,453,456,458,459,462,479,490,493,496,499,500,502,505,507,508,10,51,52,55,58,62,66,80,83,85,88,90,93,100,103,105,108,110,113,122,168,169,171,172,177,179,180,12,11,37,291} -- 37 and 291 might be unique colors, but they are not gsubbable. block_messages = T{12} +block_modes = T{20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,40,41,42,43,56,57,59,60,61,63,104,109,114,162,163,164,165,181,185,186,187,188} black_colors = T{}--352,354,356,388,390,400,402,430,432,442,444,472,474,484,486} +dmg_drain_msg = T{132,161,187,227,274,281,736,748,749,802,803} +grammar_numb_msg = T{14,31,133,231,369,370,382,385,386,387,388,389,390,391,392,393,394,395,396,397,398,400,401,403,404,405,411,417,535,536,557,570,571,589,607,651,757,769,770,778,792} + +replacements_map = { + actor = { + hits = T{1,373}, + casts = T{2,7,42,82,83,85,86,93,113,114,227,228,230,236,237,252,268,271,274,275,309,329,330,331,332,333,334,335,341,342,430,431,432,433,454,533,534,570,572,642,647,653,655}, + starts = T{3,327,716}, + gains = T{8,54,105,166,253,371,372,718,735}, + apos = T{14,16,33,69,70,75,248,310,312,352,353,354,355,382,493,535,574,575,576,577,592,606,798,799}, + misses = T{15,63}, + learns = T{23,45,442}, + uses = T{28,77,100,101,102,103,108,109,110,115,116,117,118,119,120,121,122,123,125,126,127,129,131,133,134,135,136,137,138,139,140,141,142,143,144,146,148,150,153,156,157,158,159,185,186,187,188,189,194,197,221,224,225,226,231,238,242,243,245,303,304,305,306,317,318,319,320,321,322,323,324,360,362,364,369,370,375,376,377,378,379,399,400,401,402,405,406,407,408,409,412,413,414,416,417,418,420,422,424,425,426,435, + 437,439,441,451,452,453,519,520,521,522,526,527,528,529,532,539,560,585,591,593,594,595,596,597,598,599,602,607,608,644,645,646,657,658,663,664,667,668,670,671,672,674,730,734,736,737,738,743,746,747,748,750,752,754,755,758,762,763,764,765,766,778,779,780,792,802,803,804,805,1023}, + is = T{29,49,84,106,191}, + does = T{34,91,192}, + readies = T{43,326,675}, + earns = T{50,368,719}, + steals = T{125,133,453,593,594,595,596,597,598,599}, + recovers = T{152,167}, + butmissestarget = T{188,245,324,658}, + eats = T{600,604}, + leads = T{648,650,651}, + has = T{515,661,665,688}, + obtains = T{582,673}, + }, + target = { + takes = T{2,67,77,110,157,185,196,197,229,252,264,265,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,317,353,379,413,522,648,650,732,747,767,768,800}, + is = T{4,13,64,78,82,86,107,127,128,130,131,134,136,141,148,149,150,151,154,198,203,204,232,236,242,246,270,271,272,277,279,286,287,313,328,350,519,520,521,529,531,586,591,593,594,595,596,597,598,599,645,754,776}, + recovers = T{7,24,25,26,74,102,103,224,238,263,276,306,318,367,373,382,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,651,769,770}, + apos = T{31,38,44,53,73,83,106,112,116,120,121,123,132,159,168,206,221,231,249,285,308,314,321,322,329,330,331,332,333,334,335,341,342,343,344,351,360,361,362,363,364,365,369,374,378,383,399,400,401,402,403,405,407,409,417,418,430,431,435,436,437,438,439,440,459,530,533,534,537,570,571,572,585,606,607,641,642,644,647,676,730,743,756,757,762,792,805,806,1023}, + falls = T{20,113,406,605,646}, + uses = T{79,80}, + resists = T{85,197,284,653,654}, + vanishes = T{93,273}, + receives = T{142,144,145,146,147,237,243,267,268,269,278,320,375,412,414,415,416,420,421,424,432,433,441,532,557,602,668,672,739,755,804}, + seems = T{170,171,172,173,174,175,176,177,178}, + gains = T{186,194,205,230,266,280,319}, + regains = T{357,358,439,440,451,452,539,587,588}, + obtains = T{376,377,565,566,765,766}, + loses = T{426,427,652}, + was = T{97,564}, + has = T{589,684,763}, + compresists = T{655,656}, + }, + number = { + points = T{1,2,8,10,33,38,44,54,67,77,105,110,157,163,185,196,197,223,229,252,253,264,265,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,310,317,352,353,371,372,373,379,382,385,386,387,388,389,390,391,392,393,394,395,396,397,398,413,522,536,576,577,648,650,651,718,721,722,723,724,725,726,727,728,729,732,735,747,767,768,769,770,800}, + absorbs = T{14,31,535}, + disappears = T{14,31,231,400,401,405,535,570,571,607,757,792,}, + attributes = T{369,403,417}, + status = T{370,404}, + + }, + the = { + point = T{33,308,536,800}, + } +} + +corsair_rolls = { + [98] = {[5] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Fighter's Roll + [99] = {[3] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Monk's Roll + [100] = {[3] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Healer's Roll + [101] = {[5] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Wizard's Roll + [102] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Warlock's Roll + [103] = {[5] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Rogue's Roll + [104] = {[3] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Gallant's Roll + [105] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Chaos Roll + [106] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Beast Roll + [107] = {[2] = ' (Lucky Roll!)', [6] = ' (Unlucky Roll!)'}, -- Choral Roll + [108] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Hunter's Roll + [109] = {[2] = ' (Lucky Roll!)', [6] = ' (Unlucky Roll!)'}, -- Samurai Roll + [110] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Ninja Roll + [111] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Drachen Roll + [112] = {[5] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Evoker's Roll + [113] = {[2] = ' (Lucky Roll!)', [6] = ' (Unlucky Roll!)'}, -- Magus's Roll + [114] = {[5] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Corsair's Roll + [115] = {[3] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Puppet Roll + [116] = {[3] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Dancer's Roll + [117] = {[2] = ' (Lucky Roll!)', [6] = ' (Unlucky Roll!)'}, -- Scholar's Roll + [118] = {[3] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Bolter's Roll + [119] = {[2] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Caster's Roll + [120] = {[3] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Courser's Roll + [121] = {[4] = ' (Lucky Roll!)', [9] = ' (Unlucky Roll!)'}, -- Blitzer's Roll + [122] = {[5] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Tactician's Roll + [302] = {[3] = ' (Lucky Roll!)', [10] = ' (Unlucky Roll!)'}, -- Allies' Roll + [303] = {[5] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Miser's Roll + [304] = {[2] = ' (Lucky Roll!)', [10] = ' (Unlucky Roll!)'}, -- Companion's Roll + [305] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Avenger's Roll + [390] = {[3] = ' (Lucky Roll!)', [7] = ' (Unlucky Roll!)'}, -- Naturalit's Roll + [391] = {[4] = ' (Lucky Roll!)', [8] = ' (Unlucky Roll!)'}, -- Runeist's Roll +} domain_buffs = S{ 250, -- EF Badge @@ -57,6 +155,17 @@ receives_map = T{0,0,186,82,375,116,0,0,0,0,186,0,127,116,116} stat_ignore = T{66,69,70,71,444,445,446} enfeebling = T{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,155,156,157,158,159,167,168,174,175,177,186,189,192,193,194,223,259,260,261,262,263,264,298,378,379,380,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,404,448,449,450,451,452,473,540,557,558,559,560,561,562,563,564,565,566,567} +reaction_offsets = { + [1] = 8, + [3] = 24, + [4] = 0, + [6] = 16, + [11] = 24, + [13] = 24, + [14] = 16, + [15] = 24, +} + female_races = T{2,4,6,7} male_races = T{1,3,5,8} @@ -77,9 +186,11 @@ line_aoebuff = '${actor} ${abil} '..string.char(129,168)..' ${target} (${statu line_full = '[${actor}] ${numb} ${abil} '..string.char(129,168)..' ${target}' line_itemnum = '[${actor}] ${abil} '..string.char(129,168)..' ${target} (${numb} ${item2})' line_item = '[${actor}] ${abil} '..string.char(129,168)..' ${target} (${item2})' +line_steal = '[${actor}] ${abil} '..string.char(129,168)..' ${target} (${item})' line_noability = '${numb} '..string.char(129,168)..' ${target}' line_noactor = '${abil} ${numb} '..string.char(129,168)..' ${target}' line_nonumber = '[${actor}] ${abil} '..string.char(129,168)..' ${target}' +line_notarget = '[${actor}] ${abil} '..string.char(129,168)..' ${number}' line_roll = '${actor} ${abil} '..string.char(129,168)..' ${target} '..string.char(129,170)..' ${number}' default_settings_table = {line_aoe = 'AOE ${numb} '..string.char(129,168)..' ${target}', @@ -87,11 +198,13 @@ default_settings_table = {line_aoe = 'AOE ${numb} '..string.char(129,168). line_full = '[${actor}] ${numb} ${abil} '..string.char(129,168)..' ${target}', line_itemnum = '[${actor}] ${abil} '..string.char(129,168)..' ${target} (${numb} ${item2})', line_item = '[${actor}] ${abil} '..string.char(129,168)..' ${target} (${item2})', + line_steal = '[${actor}] ${abil} '..string.char(129,168)..' ${target} (${item})', line_noability = '${numb} '..string.char(129,168)..' ${target}', line_noactor = '${abil} ${numb} '..string.char(129,168)..' ${target}', line_nonumber = '[${actor}] ${abil} '..string.char(129,168)..' ${target}', + line_notarget = '[${actor}] ${abil} '..string.char(129,168)..' ${number}', line_roll = '${actor} ${abil} '..string.char(129,168)..' ${target} '..string.char(129,170)..' ${number}', - condensedamage=true,condensetargets=true,cancelmulti=true,oxford=true,commamode=false,targetnumber=true,swingnumber=true,sumdamage=true,condensecrits=false} + condensedamage=true,condensetargets=true,cancelmulti=true,oxford=true,commamode=false,targetnumber=true,condensetargetname=false,swingnumber=true,sumdamage=true,condensecrits=false,showownernames=false,crafting=true,showblocks=true,showguards=true,showcritws=false,showrollinfo=false} message_map = {} for n=1,700,1 do @@ -110,7 +223,7 @@ message_map[75] = T{283} -- No Effect: Spell, Target message_map[248] = T{355} -- no ability of any kind message_map['No effect'] = T{283,423,659} -- generic "no effect" messages for sorting by category message_map[432] = T{433} -- Receives: Spell, Target -message_map[82] = T{230,236,237,268,271} -- Receives: Spell, Target, Status +message_map[82] = T{230,236,237,267,268,271} -- Receives: Spell, Target, Status message_map[230] = T{266} -- Receives: Spell, Target, Status message_map[319] = T{266} -- Receives: Spell, Target, Status (Generic for avatar buff BPs) message_map[134] = T{287} -- Receives: Spell, Target, Status @@ -147,12 +260,20 @@ message_map[194] = T{280} message_map[185] = T{264} message_map[243] = T{278} message_map[2] = T{264} +message_map[668] = T{669} -- Valiance +message_map[762] = T{365} -- Mix: Samson's Strength +message_map[242] = T{277} +message_map[238] = T{367} -- Phototrophic Blessing +message_map[188] = T{282} -- Misses +message_map[342] = T{344} -- Dispelga +message_map[369] = T{403} -- Ultimate Terror spike_effect_valid = {true,false,false,false,false,false,false,false,false,false,false,false,false,false,false} add_effect_valid = {true,true,true,true,false,false,false,false,false,false,true,false,true,false,false} --- These are the debuffs that are expressed in their log form by battlemod -log_form_debuffs = T{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,28,29,30,31,134,135,155,156,157,168,176,177,259,260,261,262,263,264,309,474} +-- These are the debuffs that are expressed in their log form by battlemod (The status variable when using english log is code 14 while the other one is code 13 so it should be handled by messages) +--log_form_debuffs = T{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,28,29,30,31,134,135,155,156,157,168,176,177,259,260,261,262,263,264,309,474} +log_form_messages = T{64,73,82,127,128,130,141,203,204,236,242,270,271,272,277,279,350,374,531,645,754} default_filters = [[ @@ -501,11 +622,18 @@ default_settings = [[ true false true + false true true false true true + false + true + true + true + false + false AOE ${numb} ]]..string.char(129,168)..[[ ${target} ${actor} ${abil} ]]..string.char(129,168)..[[ ${target} (${status}) [${actor}] ${numb} ${abil} ]]..string.char(129,168)..[[ ${target} @@ -514,6 +642,7 @@ default_settings = [[ ${numb} ]]..string.char(129,168)..[[ ${target} ${abil} ${numb} ]]..string.char(129,168)..[[ ${target} [${actor}] ${abil} ]]..string.char(129,168)..[[ ${target} + [${actor}] ${abil} ]]..string.char(129,168)..[[ ${number} ${actor} ${abil} ]]..string.char(129,168)..[[ ${target} ]]..string.char(129,170)..[[ ${number} diff --git a/addons/blist/blist.lua b/addons/blist/blist.lua index a04dfd4976..220629d58a 100644 --- a/addons/blist/blist.lua +++ b/addons/blist/blist.lua @@ -33,13 +33,14 @@ _addon.version = '1.2.0.1' require 'tables' require 'strings' -require 'colors' +require 'chat/colors' local config = require 'config' require 'logger' local defaults = T{} defaults.useblist = true defaults.linkshell = true +defaults.linkshell2 = true defaults.party = true defaults.tell = true defaults.emote = true @@ -47,6 +48,7 @@ defaults.say = true defaults.shout = true defaults.bazaar = true defaults.examine = true +defaults.yell = true defaults.mutedcolor = 57 settings = T{} @@ -83,7 +85,7 @@ function addon_command(...) windower.add_to_chat(160,' '..string.color('//bl help',204,160)..' : Lists this menu.') windower.add_to_chat(160,' '..string.color('//bl status',204,160)..' : Shows current configuration.') windower.add_to_chat(160,' '..string.color('//bl list',204,160)..' : Displays blacklist.') - windower.add_to_chat(160,' '..string.color('//bl useblist|linkshell|party|tell|emote|say|shout|bazaar|examine',204,160)..' : Toggles using '.._addon.name..' for said chat mode.') + windower.add_to_chat(160,' '..string.color('//bl useblist|linkshell|linkshell2|party|tell|emote|say|shout|yell|bazaar|examine',204,160)..' : Toggles using '.._addon.name..' for said chat mode.') windower.add_to_chat(160,' '..string.color('//bl mutedcolor #',204,160)..' : Sets color for muted communication. Valid values 1-255.') windower.add_to_chat(160,' '..string.color('//bl add|update name # hidetype reason',204,160)..' : Adds to or updates a user on your blist.') windower.add_to_chat(160,' '..string.color(' name',204,160)..' = name of person you want to blist') @@ -188,7 +190,7 @@ function addon_command(...) settings:save() -- current character only windower.add_to_chat(55,"Saving "..string.color(_addon.name,204,55).." settings.") end - elseif S({'useblist','linkshell','party','tell','emote','say','shout','bazaar','examine'}):contains(comm) then + elseif S({'useblist','linkshell','linkshell2','party','tell','emote','say','shout','yell','bazaar','examine'}):contains(comm) then settings[comm] = not settings[comm] showStatus(comm) if tostring(com2) ~= tostring(dummysettings[comm]) then @@ -220,11 +222,13 @@ function showStatus(var) else windower.add_to_chat(160," UseBlist: " .. string.color(onOffPrint(settings.useblist),204,160)) windower.add_to_chat(160," UseBlistOnLinkshell: " .. string.color(onOffPrint(settings.linkshell),204,160)) + windower.add_to_chat(160," UseBlistOnLinkshell2: " .. string.color(onOffPrint(settings.linkshell2),204,160)) windower.add_to_chat(160," UseBlistOnParty: " .. string.color(onOffPrint(settings.party),204,160)) windower.add_to_chat(160," UseBlistOnTell: " .. string.color(onOffPrint(settings.tell),204,160)) windower.add_to_chat(160," UseBlistOnEmote: " .. string.color(onOffPrint(settings.emote),204,160)) windower.add_to_chat(160," UseBlistOnSay: " .. string.color(onOffPrint(settings.say),204,160)) windower.add_to_chat(160," UseBlistOnShout: " .. string.color(onOffPrint(settings.shout),204,160)) + windower.add_to_chat(160," UseBlistOnYell: " .. string.color(onOffPrint(settings.yell),204,160)) windower.add_to_chat(160," UseBlistOnBazaar: " .. string.color(onOffPrint(settings.bazaar),204,160)) windower.add_to_chat(160," UseBlistOnExamine: " .. string.color(onOffPrint(settings.examine),204,160)) windower.add_to_chat(160," Muted"..string.color("Color",settings.mutedcolor,160)..": " .. string.color(tostring(settings.mutedcolor),204,160)) @@ -256,6 +260,8 @@ windower.register_event('incoming text',function (original, modified, mode) name = "blist" if mode == 14 and settings.linkshell == true then -- linkshell (others) a,z,name = string.find(original,'<(%a+)> ') + elseif mode == 214 and settings.linkshell2 == true then -- linkshell2 (others) + a,z,name = string.find(original,'<(%a+)> ') elseif mode == 13 and settings.party == true then -- party (others) a,z,name = string.find(original,'%((%a+)%) ') elseif mode == 12 and settings.tell == true then -- tell (in) @@ -263,9 +269,11 @@ windower.register_event('incoming text',function (original, modified, mode) elseif (mode == 15 or mode == 7) and settings.emote == true then -- emote a,z,name = string.find(original,'(%a+) ') elseif mode == 1 and settings.say == true then -- say - a,z,name = string.find(original,'(%a+) ') + a,z,name = string.find(original,'(%a+) :') elseif mode == 2 and settings.shout == true then -- shout a,z,name = string.find(original,'(%a+) ') + elseif mode == 11 and settings.yell == true then -- yell + a,z,name = string.find(original,'([%l%u]+).*%[') elseif mode == 121 and settings.bazaar == true then -- bazaar a,z,name,filler = string.find(original,'(%a+) (.*) bazaar%.') elseif mode == 208 and settings.examine == true then -- examine diff --git a/addons/bluguide/bluguide.lua b/addons/bluguide/bluguide.lua index eaa8824eb8..e541b98895 100644 --- a/addons/bluguide/bluguide.lua +++ b/addons/bluguide/bluguide.lua @@ -6,7 +6,7 @@ traitboxes = require("ui/traitboxes") spellboxes = require("ui/spellboxes") setspells = require("masterlist") -_addon.version = '1.1' +_addon.version = '1.2' _addon.name = 'bluGuide' _addon.author = 'Anissa of Cerberus' @@ -118,12 +118,15 @@ function build_columns() traitpage:add(traitboxes.new(traits['Defense Bonus'])) traitpage:add(traitboxes.new(traits['Magic Defense Bonus'])) traitpage:add(traitboxes.new(traits['Magic Evasion Bonus'])) + traitpage:add(traitboxes.new(traits['Evasion Bonus'])) traitpage:add(traitboxes.new(traits['Inquartata'])) traitpage:add(traitboxes.new(traits['Auto Regen'])) traitpage:add(traitboxes.new(traits['Max HP Boost'])) traitpage:add(traitboxes.new(traits['Tenacity'])) traitpage:add(traitboxes.new(traits['Resist Gravity'])) + traitpage:add(traitboxes.new(traits['Resist Silence'])) traitpage:add(traitboxes.new(traits['Resist Sleep'])) + traitpage:add(traitboxes.new(traits['Resist Slow'])) traitpage:add(traitboxes.new(traits['Gilfinder/TH'])) traitpage:add(traitboxes.new(traits['Beast Killer'])) traitpage:add(traitboxes.new(traits['Lizard Killer'])) @@ -260,7 +263,7 @@ function close() windower.send_command('lua unload bluguide') end ---Copyright 2015, Anissa +--Copyright © 2015, Anissa --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -284,4 +287,4 @@ end --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. \ No newline at end of file +--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/addons/bluguide/masterlist.lua b/addons/bluguide/masterlist.lua index 0c1dcd6682..eaed220323 100644 --- a/addons/bluguide/masterlist.lua +++ b/addons/bluguide/masterlist.lua @@ -31,10 +31,7 @@ local function get_limits() level = player.sub_job_level end - local jobpointsspent = 0 - for k, v in pairs(player.job_points.blu) do - jobpointsspent = jobpointsspent + (v^2 + v)/2 - end + local jobpointsspent = player.job_points.blu.jp_spent if jobpointsspent >= 1200 then gifts = 2 elseif jobpointsspent >= 100 then @@ -168,7 +165,7 @@ end return spelllist ---Copyright 2015, Anissa +--Copyright © 2015, Anissa --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -192,4 +189,4 @@ return spelllist --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. \ No newline at end of file +--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/addons/bluguide/res/traits.lua b/addons/bluguide/res/traits.lua index 1cf5c0e3c7..b4d8175149 100644 --- a/addons/bluguide/res/traits.lua +++ b/addons/bluguide/res/traits.lua @@ -36,13 +36,13 @@ return { { name = "Self-Destruct", points = 2, cost = 3, id = 533 }, { name = "Cold Wave", points = 1, cost = 1, id = 535 }, { name = "Light of Penance", points = 2, cost = 5, id = 634 }, - { name = "Voracious Trunk", points = 3, cost = 4, id = 576 }, + { name = "Voracious Trunk", points = 3, cost = 4, id = 579 }, { name = "Actinic Burst", points = 4, cost = 4, id = 612 }, { name = "Plasma Charge", points = 4, cost = 5, id = 615 }, { name = "Winds of Promy.", points = 4, cost = 5, id = 681 }, }, tiers = { [8] = 1 }, - subs = { ['PLD'] = 8, ['SNM'] = 8 }, + subs = { ['PLD'] = 8, ['SMN'] = 8 }, }, ['Auto Regen'] = { name = "Auto Regen", @@ -176,12 +176,12 @@ return { ['Gilfinder/TH'] = { name = "Gilfinder/TH", spells = { - { name = "Charged Whisker", points = 4, cost = 5, id = 680 }, - { name = "Evryone. Grudge", points = 4, cost = 4, id = 683 }, - { name = "Amorphic Spikes", points = 4, cost = 4, id = 697 }, + { name = "Charged Whisker", points = 6, cost = 5, id = 680 }, + { name = "Evryone. Grudge", points = 6, cost = 4, id = 683 }, + { name = "Amorphic Spikes", points = 6, cost = 4, id = 697 }, }, - tiers = { [8] = "GF", [12] = "TH" }, - subs = { ['THF'] = 12 }, + tiers = { [8] = "GF", [16] = "TH" }, + subs = { ['THF'] = 16 }, }, ['Lizard Killer'] = { name = "Lizard Killer", @@ -214,12 +214,12 @@ return { ['Magic Burst Bonus'] = { name = "Magic Burst Bonus", spells = { - { name = "Leafstorm", points = 4, cost = 4, id = 663 }, - { name = "Cimicine Discharge", points = 4, cost = 3, id = 660 }, - { name = "Reaving Wind", points = 4, cost = 4, id = 684 }, + { name = "Leafstorm", points = 6, cost = 4, id = 663 }, + { name = "Cimicine Discharge", points = 6, cost = 3, id = 660 }, + { name = "Reaving Wind", points = 6, cost = 4, id = 684 }, { name = "Rail Cannon", points = 8, cost = 6, id = 712 }, }, - tiers = { [8] = 5, [16] = 7, [24] = 9, [32] = 11 }, + tiers = { [8] = 5, [16] = 7, [24] = 9, [32] = 11, [40] = 13 }, subs = { ['BLM'] = 8 }, }, ['Magic Defense Bonus'] = { @@ -312,12 +312,12 @@ return { ['Skillchain Bonus'] = { name = "Skillchain Bonus", spells = { - { name = "Goblin Rush", points = 4, cost = 3, id = 666 }, - { name = "Benthic Typhoon", points = 4, cost = 4, id = 670 }, - { name = "Quadrastrike", points = 4, cost = 5, id = 693 }, + { name = "Goblin Rush", points = 6, cost = 3, id = 666 }, + { name = "Benthic Typhoon", points = 6, cost = 4, id = 670 }, + { name = "Quadrastrike", points = 6, cost = 5, id = 693 }, { name = "Paralyzing Triad", points = 8, cost = 6, id = 704 }, }, - tiers = { [8] = 8, [16] = 12, [24] = 16, [32] = 20 }, + tiers = { [8] = 8, [16] = 12, [24] = 16, [32] = 20, [40] = 23 }, subs = { ['DNC'] = 8 }, }, ['Store TP'] = { @@ -399,7 +399,7 @@ return { subs = { ['PUP'] = 16, ['BST'] = 16, ['SMN'] = 16, ['DNC'] = 8, }, }, } ---Copyright 2015, Anissa +--Copyright © 2015, Anissa --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -423,4 +423,4 @@ return { --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. \ No newline at end of file +--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/addons/boxdestroyer/README b/addons/boxdestroyer/README index a34f5b9833..a8d0983c69 100644 --- a/addons/boxdestroyer/README +++ b/addons/boxdestroyer/README @@ -8,5 +8,6 @@ Donations are welcome in the form of Alexandrite: Acacia on Odin (http://www.ffxiah.com/player/Odin/Acacia) With this addon loaded, just click on any brown treasure casket and it -will display info about possible combinations, the best number to guess -and the worst case chance of guessing correctly. +will recommend whether to examine the chest or guess a number. When it +recommends guessing a number, your probability of success with an +optimal guess-only strategy is also displayed. diff --git a/addons/boxdestroyer/boxdestroyer.lua b/addons/boxdestroyer/boxdestroyer.lua index 60c7b28bbf..7b538a774d 100644 --- a/addons/boxdestroyer/boxdestroyer.lua +++ b/addons/boxdestroyer/boxdestroyer.lua @@ -28,18 +28,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- addon information _addon.name = 'boxdestroyer' -_addon.version = '1.0.2' +_addon.version = '1.0.6' _addon.command = 'boxdestroyer' _addon.author = 'Seth VanHeulen (Acacia@Odin)' -- modules require('pack') +require('tables') +require('chat') -- load message constants require('messages') +-- config + +config = require('config') +defaults = { + HighlightResult = false, + HighlightColor = 36, + DisplayRemainingCombinations = false, +} +settings = config.load(defaults) -- global constants default = { @@ -54,16 +65,27 @@ default = { 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 } +observed_default = { + ['second_even_odd'] = false, + ['first_even_odd'] = false, + ['range'] = false, + ['equal'] = false, + ['second_multiple'] = false, + ['first_multiple'] = false, + ['thief_tools_active'] = false +} + +thief_tools = {[1022] = true} + -- global variables box = {} +observed = {} +zone_id = windower.ffxi.get_info().zone -- filter helper functions function greater_less(id, greater, num) - if box[id] == nil then - box[id] = default - end local new = {} for _,v in pairs(box[id]) do if greater and v > num or not greater and v < num then @@ -74,9 +96,6 @@ function greater_less(id, greater, num) end function even_odd(id, div, rem) - if box[id] == nil then - box[id] = default - end local new = {} for _,v in pairs(box[id]) do if (math.floor(v / div) % 2) == rem then @@ -87,9 +106,6 @@ function even_odd(id, div, rem) end function equal(id, first, num) - if box[id] == nil then - box[id] = default - end local new = {} for _,v in pairs(box[id]) do if first and math.floor(v / 10) == num or not first and (v % 10) == num then @@ -99,19 +115,188 @@ function equal(id, first, num) return new end +function exclusive_mean(counts) + total = 0 + for _,v in pairs(counts) do + total = total + v + end + weighted_mean = 0 + for _,v in pairs(counts) do + weighted_mean = weighted_mean + (total - v) * v / total + end + return weighted_mean +end + +function calculate_odds(id,chances) + local reductions = {} + if not observed[id].first_even_odd then + local counter = {0} + counter[0] = 0 + for _,v in pairs(box[id]) do + counter[math.floor(v / 10) % 2] = counter[math.floor(v / 10) % 2] + 1 + end + reductions[#reductions+1] = exclusive_mean(counter) + end + if not observed[id].second_even_odd then + local counter = {0} + counter[0] = 0 + for _,v in pairs(box[id]) do + counter[v % 2] = counter[v % 2] + 1 + end + reductions[#reductions+1] = exclusive_mean(counter) + end + if not observed[id].range then + local new = {} + local reduction = 0 + for i,v in pairs(box[id]) do + new[i] = 0 + for _,m in pairs(box[id]) do + if m-v > 16 then break end + new[i] = new[i] + math.max(16-math.abs(m - v),0)^2/256 + end + reduction = reduction + (#box[id] - new[i])/#box[id] + end + + reductions[#reductions+1] = reduction + end + if not observed[id].equal then + local counter = {0,0,0,0,0,0,0,0,0} + counter[0] = 0 + local eliminated = {0,0,0,0,0,0,0,0,0} + eliminated[0] = 0 + for _,v in pairs(box[id]) do + counter[math.floor(v / 10)] = counter[math.floor(v / 10)] + 1/2 + counter[v % 10] = counter[v % 10] + 1/2 + for i = 0,9 do + if i ~= v % 10 and i ~= math.floor(v / 10) then + eliminated[i] = eliminated[i] + 1 + end + end + end + + reduction = 0 + for i,v in pairs(counter) do + reduction = reduction + eliminated[i] * v / #box[id] + end + + reductions[#reductions+1] = reduction + end + if not observed[id].second_multiple then + local counter = {0,0,0,0,0,0,0,0,0} + counter[0] = 0 + for _,v in pairs(box[id]) do + counter[v % 10] = counter[v % 10] + 1 + end + + local weights = { + counter[0] + counter[1]/2 + counter[2]/3, + counter[1]/2 + counter[2]/3 + counter[3]/3, + counter[2]/3 + counter[3]/3 + counter[4]/3, + counter[3]/3 + counter[4]/3 + counter[5]/3, + counter[4]/3 + counter[5]/3 + counter[6]/3, + counter[5]/3 + counter[6]/3 + counter[7]/3, + counter[6]/3 + counter[7]/3 + counter[8]/2, + counter[7]/3 + counter[8]/2 + counter[9] + } + + local eliminated = { + counter[3] + counter[4] + counter[5] + counter[6] + counter[7] + counter[8] + counter[9], + counter[0] + counter[4] + counter[5] + counter[6] + counter[7] + counter[8] + counter[9], + counter[0] + counter[1] + counter[5] + counter[6] + counter[7] + counter[8] + counter[9], + counter[0] + counter[1] + counter[2] + counter[6] + counter[7] + counter[8] + counter[9], + counter[0] + counter[1] + counter[2] + counter[3] + counter[7] + counter[8] + counter[9], + counter[0] + counter[1] + counter[2] + counter[3] + counter[4] + counter[8] + counter[9], + counter[0] + counter[1] + counter[2] + counter[3] + counter[4] + counter[5] + counter[9], + counter[0] + counter[1] + counter[2] + counter[3] + counter[4] + counter[5] + counter[6] + } + + local reduction = 0 + for i,v in pairs(weights) do + reduction = reduction + eliminated[i] * v / #box[id] + end + + reductions[#reductions + 1] = reduction + end + if not observed[id].first_multiple then + local counter = {0,0,0,0,0,0,0,0,0} + for _,v in pairs(box[id]) do + counter[math.floor(v / 10)] = counter[math.floor(v / 10)] + 1 + end + + local weights = { + counter[1] + counter[2]/2 + counter[3]/3, + counter[2]/2 + counter[3]/3 + counter[4]/3, + counter[3]/3 + counter[4]/3 + counter[5]/3, + counter[4]/3 + counter[5]/3 + counter[6]/3, + counter[5]/3 + counter[6]/3 + counter[7]/3, + counter[6]/3 + counter[7]/3 + counter[8]/2, + counter[7]/3 + counter[8]/2 + counter[9] + } + + local eliminated = { + counter[4] + counter[5] + counter[6] + counter[7] + counter[8] + counter[9], + counter[1] + counter[5] + counter[6] + counter[7] + counter[8] + counter[9], + counter[1] + counter[2] + counter[6] + counter[7] + counter[8] + counter[9], + counter[1] + counter[2] + counter[3] + counter[7] + counter[8] + counter[9], + counter[1] + counter[2] + counter[3] + counter[4] + counter[8] + counter[9], + counter[1] + counter[2] + counter[3] + counter[4] + counter[5] + counter[9], + counter[1] + counter[2] + counter[3] + counter[4] + counter[5] + counter[6] + } + + local reduction = 0 + for i,v in pairs(weights) do + reduction = reduction + eliminated[i] * v / #box[id] + end + + reductions[#reductions + 1] = reduction + end + + local expected_examine_value = 0 + for _,v in pairs(reductions) do + expected_examine_value = expected_examine_value + v/#reductions + end + + local optimal_guess = math.ceil(#box[id] / 2) + + local expected_guess_value = 2*optimal_guess - 2*optimal_guess^2 / #box[id] + 2*optimal_guess/#box[id] - 1 / #box[id] + + return expected_examine_value, expected_guess_value +end + -- display helper function function display(id, chances) - if #box[id] == 90 then - windower.add_to_chat(207, 'possible combinations: 10~99') - else - windower.add_to_chat(207, 'possible combinations: ' .. table.concat(box[id], ' ')) + if settings.DisplayRemainingCombinations then + if #box[id] == 90 then + windower.add_to_chat(207, 'Possible combinations: 10~99') + else + windower.add_to_chat(207, 'Possible combinations: ' .. table.concat(box[id], ' ')) + end end - local remaining = math.floor(#box[id] / math.pow(2, (chances - 1))) + local probability = math.min(100, math.floor(100 * (math.pow(2, chances) - 1) / #box[id] )) + local remaining = math.floor(#box[id] / math.pow(2, chances - 1)) if remaining == 0 then remaining = 1 end - windower.add_to_chat(207, 'best guess: %d (%d%%)':format(box[id][math.ceil(#box[id] / 2)], 1 / remaining * 100)) + + local guess_number = box[id][math.ceil(#box[id] / 2)] + + if chances == 1 and observed[id].equal then + -- The "equal" message (== "X") for X in 1..9 gives an unequal probability to the remaining options + -- because "XX" is twice as likely to be indicated by the "equal" message. + -- This is too annoying to propagate to the rest of the addon, although it should be some day. + for _,v in pairs(box[id]) do + if math.floor(v/10) == v%10 then + guess_number = v + break + end + end + end + local clue_value,guess_value = calculate_odds(id,chances) + local result = clue_value > guess_value and remaining ~= 1 and 'examining the lock' or 'guessing %d (%d%%)':format(guess_number, probability) + local formatted_result = settings.HighlightResult and result:color(settings.HighlightColor) or result + windower.add_to_chat(207, 'boxdestroyer recommends ' .. formatted_result) + end -- ID obtaining helper function @@ -122,30 +307,81 @@ end -- event callback functions function check_incoming_chunk(id, original, modified, injected, blocked) - local zone_id = windower.ffxi.get_info().zone - if messages[zone_id] then + if id == 0x0A then + zone_id = original:unpack('H', 49) + elseif messages[zone_id] then if id == 0x0B then box = {} + observed = {} elseif id == 0x2A then local box_id = original:unpack('I', 5) local param0 = original:unpack('I', 9) local param1 = original:unpack('I', 13) local param2 = original:unpack('I', 17) local message_id = original:unpack('H', 27) % 0x8000 + + if box[box_id] == nil then + box[box_id] = table.copy(default) + end + if observed[box_id] == nil then + observed[box_id] = table.copy(observed_default) + end + if get_id(zone_id,'greater_less') == message_id then box[box_id] = greater_less(box_id, param1 == 0, param0) elseif get_id(zone_id,'second_even_odd') == message_id then + -- tells whether the second digit is even or odd box[box_id] = even_odd(box_id, 1, param0) + observed[box_id].second_even_odd = true elseif get_id(zone_id,'first_even_odd') == message_id then + -- tells whether the first digit is even or odd box[box_id] = even_odd(box_id, 10, param0) + observed[box_id].first_even_odd = true elseif get_id(zone_id,'range') == message_id then - box[box_id] = greater_less(box_id, true, param0) - box[box_id] = greater_less(box_id, false, param1) + if observed[box_id].thief_tools_active then + -- Thief tools are the same as normal ranges but with larger bounds. + -- lower bound (param0) = solution - RANDINT(8,32) + -- upper bound (param1) = solution + RANDINT(8,32) + -- param0 + 33 > solution > param0 + 7 + -- param1 - 7 > solution > param1 - 33 + -- if the bound is less than 11 or greater than 98, the message changes to "greater" or "less" respectively + box[box_id] = greater_less(box_id, true, math.max(param1-33,param0+7) ) + box[box_id] = greater_less(box_id, false, math.min(param0+33,param1-7) ) + observed[box_id].thief_tools_active = false + else + -- lower bound (param0) = solution - RANDINT(5,20) + -- upper bound (param1) = solution + RANDINT(5,20) + -- param0 + 21 > solution > param0 + 4 + -- param1 - 4 > solution > param1 - 21 + -- if the bound is less than 11 or greater than 98, the message changes to "greater" or "less" respectively + box[box_id] = greater_less(box_id, true, math.max(param1-21,param0+4) ) + box[box_id] = greater_less(box_id, false, math.min(param0+21,param1-4) ) + observed[box_id].range = true + end elseif get_id(zone_id,'less') == message_id then - box[box_id] = greater_less(box_id, false, param0) + -- Less is a range with 9 as the lower bound + if observed[box_id].thief_tools_active then + box[box_id] = greater_less(box_id, true, math.max(9, param0-33) ) + box[box_id] = greater_less(box_id, false, math.min(10+33,param0-7) ) + observed[box_id].thief_tools_active = false + else + box[box_id] = greater_less(box_id, true, math.max(9, param0-21) ) + box[box_id] = greater_less(box_id, false, math.min(10+21,param0-4) ) + observed[box_id].range = true + end elseif get_id(zone_id,'greater') == message_id then - box[box_id] = greater_less(box_id, true, param0) + -- Greater is a range with 100 as the upper bound + if observed[box_id].thief_tools_active then + box[box_id] = greater_less(box_id, true, math.max(99-33,param0+7) ) + box[box_id] = greater_less(box_id, false, math.min(100,param0+33) ) + observed[box_id].thief_tools_active = false + else + box[box_id] = greater_less(box_id, true, math.max(99-21,param0+4) ) + box[box_id] = greater_less(box_id, false, math.min(100,param0+21) ) + observed[box_id].range = true + end elseif get_id(zone_id,'equal') == message_id then + -- single number that is either the first or second digit of the solution local new = equal(box_id, true, param0) local duplicate = param0 * 10 + param0 for k,v in pairs(new) do @@ -156,27 +392,35 @@ function check_incoming_chunk(id, original, modified, injected, blocked) for _,v in pairs(equal(box_id, false, param0)) do table.insert(new, v) end table.sort(new) box[box_id] = new + observed[box_id].equal = true elseif get_id(zone_id,'second_multiple') == message_id then + -- three digit range including the second digit of the solution local new = equal(box_id, false, param0) for _,v in pairs(equal(box_id, false, param1)) do table.insert(new, v) end for _,v in pairs(equal(box_id, false, param2)) do table.insert(new, v) end table.sort(new) box[box_id] = new + observed[box_id].second_multiple = true elseif get_id(zone_id,'first_multiple') == message_id then + -- three digit range including the first digit of the solution local new = equal(box_id, true, param0) for _,v in pairs(equal(box_id, true, param1)) do table.insert(new, v) end for _,v in pairs(equal(box_id, true, param2)) do table.insert(new, v) end table.sort(new) box[box_id] = new + observed[box_id].first_multiple = true elseif get_id(zone_id,'success') == message_id or get_id(zone_id,'failure') == message_id then box[box_id] = nil + elseif get_id(zone_id,'tool_failure') == message_id then + observed[box_id].thief_tools_active = false end elseif id == 0x34 then local box_id = original:unpack('I', 5) if windower.ffxi.get_mob_by_id(box_id).name == 'Treasure Casket' then local chances = original:byte(9) if box[box_id] == nil then - box[box_id] = default + box[box_id] = table.copy(default) + observed[box_id] = table.copy(observed_default) end if chances > 0 and chances < 7 then display(box_id, chances) @@ -184,10 +428,38 @@ function check_incoming_chunk(id, original, modified, injected, blocked) end elseif id == 0x5B then box[original:unpack('I', 17)] = nil + observed[original:unpack('I', 17)] = nil + end + end +end + +function watch_for_keys(id, original, modified, injected, blocked) + if blocked then + elseif (id == 0x036 or id == 0x037) and + windower.ffxi.get_mob_by_id(modified:unpack('I',0x05)).name == 'Treasure Casket' and + (windower.ffxi.get_player().main_job == 'THF' or windower.ffxi.get_player().sub_job == 'THF') then + + local box_id = modified:unpack('I',0x05) + if not box[box_id] then + box[box_id] = table.copy(default) + observed[box_id] = table.copy(observed_default) + end + + if id == 0x037 and thief_tools[windower.ffxi.get_items(modified:byte(0x11))[modified:byte(0xF)].id] then + observed[box_id].thief_tools_active = true + elseif id == 0x036 then + for i = 1,9 do + if thief_tools[windower.ffxi.get_items(0)[modified:byte(0x30+i)].id] then + observed[box_id].thief_tools_active = true + break + end + end end end end -- register event callbacks -windower.register_event('incoming chunk', check_incoming_chunk) \ No newline at end of file +windower.register_event('incoming chunk', check_incoming_chunk) + +windower.register_event('outgoing chunk', watch_for_keys) diff --git a/addons/boxdestroyer/make_messages/make_messages.py b/addons/boxdestroyer/make_messages/make_messages.py new file mode 100644 index 0000000000..932ea3b7f8 --- /dev/null +++ b/addons/boxdestroyer/make_messages/make_messages.py @@ -0,0 +1,77 @@ +# Python 3 +import array +import os +import struct +import winreg + +from settings import search, zones + + +def find_dat(dat_id): + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\WOW6432Node\\PlayOnlineUS\\InstallFolder') + ffxi_path = winreg.QueryValueEx(key, '0001')[0] + key.Close() + for i in range(1, 10): + vtable = None + if i == 1: + vtable = open(os.path.join(ffxi_path, 'VTABLE.DAT'), 'rb') + else: + vtable = open(os.path.join(ffxi_path, 'ROM{}'.format(i), 'VTABLE{}.DAT'.format(i)), 'rb') + vtable.seek(dat_id) + temp = vtable.read(1)[0] + vtable.close() + if temp != i: + continue + ftable = None + if i == 1: + ftable = open(os.path.join(ffxi_path, 'FTABLE.DAT'), 'rb') + else: + ftable = open(os.path.join(ffxi_path, 'ROM{}'.format(i), 'FTABLE{}.DAT'.format(i)), 'rb') + ftable.seek(dat_id * 2) + path = struct.unpack('H', ftable.read(2))[0] + ftable.close() + if i == 1: + return os.path.join(ffxi_path, 'ROM', '{}'.format(path >> 7), '{}.DAT'.format(path & 0x7f)) + else: + return os.path.join(ffxi_path, 'ROM{}'.format(i), '{}'.format(path >> 7), '{}.DAT'.format(path & 0x7f)) + return None + +def decipher_dialog(dat_file): + dat = open(dat_file, 'rb') + dat_size, first_entry = struct.unpack('II', dat.read(8)) + dat_size -= 0x10000000 + first_entry ^= 0x80808080 + dat.seek(4) + data = bytearray(dat.read()) + dat.close() + for i in range(len(data)): + data[i] ^= 0x80 + offsets = array.array('I', data[:first_entry]) + offsets.append(dat_size) + for i in range(len(offsets)): + offsets[i] -= first_entry + return offsets, bytes(data[first_entry:]) + +def search_dialog(zones, search): + messages = {} + for zone_id, dat_id in zones.items(): + offsets, data = decipher_dialog(find_dat(dat_id)) + for i in range(len(offsets) - 1): + message = data[offsets[i]:offsets[i+1]] + if message == search: + messages[zone_id] = str(i) + return messages + +def write_lua(messages): + o = open('messages.lua', 'w') + print('messages = { -- These dialogue IDs match "You were unable to enter a combination" for the associated zone IDs', file=o) + zone_ids = list(messages.keys()) + zone_ids.sort() + for zone_id in zone_ids: + line = messages[zone_id]+',' + print(" [{}] = {}".format(zone_id, line), file=o) + print('}',file=o) + print('offsets = {greater_less=1, failure=2, success=4, second_even_odd=5, first_even_odd=6, range=7, less=8, greater=9, equal=10, second_multiple=11, first_multiple=12, tool_failure=13}',file=o) + o.close() + +write_lua(search_dialog(zones, search)) diff --git a/addons/boxdestroyer/make_messages/settings.py b/addons/boxdestroyer/make_messages/settings.py new file mode 100644 index 0000000000..ccc6b1bb74 --- /dev/null +++ b/addons/boxdestroyer/make_messages/settings.py @@ -0,0 +1,190 @@ +search = b'You were unable to enter a combination.\x7f1\x00\x07' + +zones = { + #1: 6421, # phanauet channel + #2: 6422, # carpenters' landing + #3: 6423, # manaclipper + #4: 6424, # bibiki bay + #11: 6431, # oldton movalpolos + #15: 6435, # abyssea - konschtat + #24: 6444, # lufaise meadows + #25: 6445, # misareaux coast + #26: 6446, # tavnazian safehold + #27: 6447, # phomiuna aquaducts + #33: 6453, # al'taieu + #39: 6459, # dynamis - valkurm + #40: 6460, # dynamis - buburimu + #41: 6461, # dynamis - qufim + #42: 6462, # dynamis - tavnazia + #43: 6463, # diorama abdhaljs-ghelsba + #44: 6464, # abdhaljs isle-purgonorgo + #45: 6465, # abyssea - tahrongi + #46: 6466, # open sea route to al zahbi + #47: 6467, # open sea route to mhaura + #48: 6468, # al zahbi + #50: 6470, # aht urhgan whitegate + #51: 6471, # wajaom woodlands + #52: 6472, # bhaflau thickets + #53: 6473, # nashmau + #54: 6474, # arrapago reef + #55: 6475, # ilrusi atoll + #56: 6476, # periqia + #57: 6477, # talacca cove + #58: 6478, # silver sea route to nashmau + #59: 6479, # silver sea route to al zahbi + #60: 6480, # the ashu talif + #61: 6481, # mount zhayolm + #65: 6485, # mamook + #66: 6486, # mamool ja training grounds + #67: 6487, # jade sepulcher + #68: 6488, # aydeewa subterrane + #69: 6489, # leujaoam sanctum + #79: 6499, # caedarva mire + #81: 6501, # east ronfaure [s] + #82: 6502, # jugner forest [s] + #83: 6503, # vunkerl inlet [s] + #84: 6504, # batallia downs [s] + #85: 6505, # la vaule [s] + #86: 6506, # everbloom hollow + #87: 6507, # bastok markets [s] + #88: 6508, # north gustaberg [s] + #89: 6509, # grauberg [s] + #90: 6510, # pashhow marshlands [s] + #91: 6511, # rolanberry fields [s] + #93: 6513, # ruhotz silvermines + #94: 6514, # windurst waters [s] + #95: 6515, # west sarutabaruta [a] + #96: 6516, # fort karugo-narugo [s] + #99: 6519, # castle oztroja [s] + 100: 6520, # west ronfaure + 101: 6521, # east ronfaure + 102: 6522, # la theine plateau + 103: 6523, # valkurm dunes + 104: 6524, # jugner forest + 105: 6525, # batallia downs + 106: 6526, # north gustaberg + 107: 6527, # south gustaberg + 108: 6528, # konschtat highlands + 109: 6529, # pashhow marshlands + 110: 6530, # rolanberry fields + 111: 6531, # beaucedine glacier + 112: 6532, # xarcabard + 113: 6533, # cape teriggan + 114: 6534, # eastern altepa desert + 115: 6535, # west sarutabaruta + 116: 6536, # east sarutabaruta + 117: 6537, # tahrongi canyon + 118: 6538, # buburimu peninsula + 119: 6539, # meriphataud mountains + 120: 6540, # sauromugue champaign + 121: 6541, # the sanctuary of zi'tah + 122: 6542, # ro'maeve + 123: 6543, # yuhtunga jungle + 124: 6544, # yhoator jungle + 125: 6545, # western altepa desert + 126: 6546, # qufim island + 127: 6547, # behemoth's dominion + 128: 6548, # valley of sorrows + 130: 6550, # ru'aun gardens + #132: 6552, # abyssea - la theine + #134: 6554, # dynamis - beaucedine + #136: 6556, # beaucedine glacier [s] + #139: 6559, # horlais peak + #140: 6560, # ghelsba outpost + #141: 6561, # fort ghelsba + #142: 6562, # yughott grotto + #143: 6563, # palborough mines + #145: 6565, # giddeus + #148: 6568, # qulun dome + #149: 6569, # davoi + #151: 6571, # castle oztroja + 153: 6573, # the boyahda tree + #154: 6574, # dragon's aery + 157: 6577, # middle delkfutt's tower + 158: 6578, # upper delkfutt's tower + 159: 6579, # temple of uggalepih + 160: 6580, # den of rancor + 166: 6586, # ranguemont pass + 167: 6587, # bostaunieux oubliette + 169: 6589, # torimarai canal + 172: 6592, # zeruhn mines + 173: 6593, # korroloka tunnel + 174: 6594, # kuftal tunnel + 176: 6596, # sea serpent grotto + 177: 6597, # ve'lugannon palace + 178: 6598, # the shrine of ru'avitau + 184: 6604, # lower delkfutt's tower + #186: 6606, # dynamis - bastok + #187: 6607, # dynamis - windurst + 190: 6610, # king ranpere's tomb + 191: 6611, # dangruf wadi + 192: 6612, # inner horutoto ruins + 193: 6613, # ordelle's caves + 194: 6614, # outer horutoto ruins + 195: 6615, # eldieme necropolis + 196: 6616, # gusgan mines + 197: 6617, # crawler's nest + 198: 6618, # maze of shakrami + 200: 6620, # garlaige citadel + 204: 6624, # fei'yin + 205: 6625, # ifrit's cauldron + 208: 6628, # quicksand caves + 212: 6632, # gustav tunnel + 213: 6633, # labyrinth of onzozo + #216: 6636, # abyssea - misareaux + #217: 6637, # abyssea - vunkerl + #218: 6638, # abyssea - altepa + #220: 6640, # ship bound for selbina + #221: 6641, # ship bound for mhaura + #222: 6642, # provenance + #227: 6647, # ship bound for selbina + #228: 6648, # ship bound for mhaura + #231: 6651, # northern san d'oria + #232: 6652, # port san d'oria + #234: 6654, # bastok mines + #235: 6655, # bastok markets + #236: 6656, # port bastok + #237: 6657, # metalworks + #238: 6658, # windurst waters + #239: 6659, # windurst walls + #240: 6660, # port windurst + #241: 6661, # windurst woods + #242: 6662, # heavens tower + #245: 6665, # lower jeuno + #246: 6666, # port jeuno + #247: 6667, # rabao + #248: 6668, # selbina + #249: 6669, # mhaura + #250: 6670, # kazham + #251: 6671, # hall of the gods + #252: 6672, # norg + #253: 6473, # abyssea - uleguerand + #254: 6674, # abyssea - grauberg + #256: 85591, # western adoulin + #257: 85592, # eastern adoulin + #258: 85593, # rala waterways + #259: 85594, # rala waterways [u] + #260: 85595, # yahse hunting grounds + #261: 85596, # ceizak battlegrounds + #262: 85597, # foret de hennetiel + #263: 85598, # yorcia weald + #264: 85599, # yorcia weald [u] + #265: 85600, # morimar basalt fields + #266: 85601, # marjami ravine + #267: 85602, # kamihr drifts + #268: 85603, # sih gates + #269: 85604, # moh gates + #270: 85605, # cirdas caverns + #271: 85606, # cirdas caverns [u] + #272: 85607, # dho gates + #273: 85608, # woh gates + #274: 85609, # outer ra'kaznar + #275: 85610, # outer ra'kaznar [u] + #276: 85611, # ra'kaznar inner court + #277: 85612, # ra'kaznar turris + #280: 85615, # mog garden + #281: 85616, # leafallia + #288: 85623, # escha - zi'tah + #289: 85624, # escha - ru'aun + #291: 85626, # reisenjima +} diff --git a/addons/boxdestroyer/messages.lua b/addons/boxdestroyer/messages.lua index 15a1ebdf42..b955bc6173 100644 --- a/addons/boxdestroyer/messages.lua +++ b/addons/boxdestroyer/messages.lua @@ -1,61 +1,63 @@ -messages = { - [100] = 8055, - [101] = 7503, - [102] = 7906, - [103] = 8081, - [104] = 8646, - [105] = 7697, - [106] = 8071, - [107] = 7532, - [108] = 7601, - [109] = 8464, - [110] = 7588, - [111] = 8565, - [112] = 8167, - [113] = 7926, - [114] = 7766, - [115] = 7862, - [116] = 7558, - [117] = 7565, - [118] = 8107, - [119] = 8344, - [120] = 7504, - [121] = 8084, - [122] = 7432, - [123] = 7867, - [124] = 7818, - [125] = 7628, - [126] = 8051, - [127] = 7349, - [128] = 7504, - [130] = 7567, - [153] = 11393, - [158] = 7379, - [159] = 8442, - [160] = 7406, - [166] = 10576, - [167] = 10590, - [169] = 7536, - [172] = 7410, - [173] = 10515, - [174] = 11392, - [176] = 7601, - [177] = 11216, - [178] = 11397, - [190] = 8250, - [191] = 8370, - [192] = 7406, - [193] = 8382, - [194] = 8262, - [195] = 7593, - [196] = 8301, - [197] = 7347, - [198] = 8268, - [200] = 7524, - [204] = 7512, - [205] = 11479, - [208] = 8281, - [212] = 10636, - [213] = 10445 - } -offsets = {greater_less=0, failure=1, success=3, second_even_odd=4, first_even_odd=5, range=6, less=7, greater=8, equal=9, second_multiple=10, first_multiple=11} \ No newline at end of file +messages = { -- These dialogue IDs match "You were unable to enter a combination" for the associated zone IDs + [100] = 8066, + [101] = 7516, + [102] = 7917, + [103] = 8092, + [104] = 8657, + [105] = 7708, + [106] = 8082, + [107] = 7543, + [108] = 7612, + [109] = 8475, + [110] = 7599, + [111] = 8576, + [112] = 8178, + [113] = 7939, + [114] = 7777, + [115] = 7873, + [116] = 7569, + [117] = 7576, + [118] = 8118, + [119] = 8355, + [120] = 7515, + [121] = 8095, + [122] = 7445, + [123] = 7878, + [124] = 7829, + [125] = 7646, + [126] = 8062, + [127] = 7362, + [128] = 7517, + [130] = 7581, + [153] = 11407, + [157] = 7387, + [158] = 7393, + [159] = 8456, + [160] = 7420, + [166] = 10589, + [167] = 10603, + [169] = 7550, + [172] = 7423, + [173] = 10528, + [174] = 11406, + [176] = 7615, + [177] = 11230, + [178] = 11410, + [184] = 8640, + [190] = 8264, + [191] = 8384, + [192] = 7420, + [193] = 8396, + [194] = 8276, + [195] = 7607, + [196] = 8316, + [197] = 7361, + [198] = 8282, + [200] = 7538, + [204] = 7526, + [205] = 11493, + [208] = 8295, + [212] = 10649, + [213] = 10459, +} +offsets = {greater_less=1, failure=2, success=4, second_even_odd=5, first_even_odd=6, range=7, less=8, greater=9, equal=10, second_multiple=11, first_multiple=12, tool_failure=13} diff --git a/addons/capetrader/README.md b/addons/capetrader/README.md new file mode 100644 index 0000000000..f870836e7a --- /dev/null +++ b/addons/capetrader/README.md @@ -0,0 +1,159 @@ +# Cape Trader +Cape Trader is used to automate the process of augmenting ambuscade capes. The cape trader addon injects packets extensively so please take that into consideration and use this addon at you own risk. While there are some safeguards in this addon, there is still a risk that you can lose your abdhaljs thread,dust,sap and dye if you use this addon. Please read the usage notes and information on the prep and go commands carefully as well as the warnings section before deciding to use this addon. + +___ +### Usage notes + +Load the addon by using the following command: + + //lua load capetrader + +There are some conditions that you need to meet in order to use the important go and prep commands: + +1. You must be in Mhaura and be within a distance of 6 to the Gorpa-Masorpa npc. + +2. If you have recently zoned into Mhaura you will have to wait to use the go command until your inventory loads, or if you have only recently logged in. + +3. Make sure there is only one of the given cape you want to augment in your inventory. For example if you are intending to augment an ogma's cape, there should only be one ogma's cape in your inventory. + +4. The go command takes a number as an input that represents the number of times you wish to augment your cape. It is possible you will lose your thread,dust,sap and dye if you enter a number that would take your augment past its possible maximum. For example suppose you have an ogma's cape already augmented with Dex+5 from a thread item. After using the **//ct prep run thread dex** command you enter **//ct go 20** command. There is a safeguard that will stop the augmentation process after augmenting your cape 15 times. However it is highly recommended that you enter the exact number of times you need to max a particular augment path just in case. + +5. It is also possible to lose augment items if you try to augment a cape with a different path than is already present. Suppose again you have an ogma's cape augmented with DEX+5 via threads. If you enter the **//ct prep run thread str** and then the **//ct go 15** command intending to augment your cape with str, **you might lose these 15 threads**. There is now a safeguard to avoid this, but it is highly recommended you make sure your intended augment path already matches what is on the cape. + +6. Make sure you do not move items around your various inventory bags while the augmentation process is ongoing. You can mess around with your inventory after you get the ending message, otherwise you might interrupt the augmentation process and need to reload the addon. + +7. The augmentation process can occasionally stall. If this ever happens you can use the **//ct r** command to reload the addon and start the process over again. + + +Suppose you want to augment an ogma's cape from scratch with dex, accuracy and attack, and double attack. You can use the following steps: + +1. Enter //ct prep run thread dex + +2. Enter //ct go 20 + +3. Wait for the ending message + +4. Enter //ct prep run dust acc/atk + +5. Enter //ct go 20 + +6. Wait for the ending message. + +7. Enter //ct prep run sap doubleattack + +8. Enter //ct go 10 + +9. Upon receiving the completion message you can then consider augmenting another cape. + +___ + +### Commands + +The **help** command displays all of the possible commands of CapeTrader in your chat windower. Below are the equivalent ways of calling the command: + + //ct help + //ct h + //capetrader help + //capetrader h + +The **reload** command reloads the addon. Useful if the capetrader addon ever gets stuck during the augmentation process. The below are equivalent: + + //ct reload + //ct r + //capetrader reload + //capetrader r + +The **unload** command reloads the addon. Useful if the capetrader addon ever gets stuck during the augmentation process or you want to unload the addon quickly. The below are equivalent: + + //ct unload + //ct u + //capetrader unload + //capetrader u + +The **prep** command is one of the key components of this addon's function. This command tells the go command how to augment your cape. There are three inputs to the prep command. First is the 3 letter abbreviation of the job on the cape, for example: cor blm whm pup. The second is the type of augment item you need to use: thread, dust, sap and dye. Third is the augment path. Note that none of these inputs are case sensitive. Also in case you are not sure exactly what to input for the augment path, you can use the list command or use the following list for reference. Below are all of the possible combinations of valid augment paths: + + //ct prep war thread hp + //ct prep mnk thread mp + //ct prep whm thread str + //ct prep blm thread dex + //ct prep rdm thread vit + //ct prep thf thread agi + //ct prep pld thread int + //ct prep drk thread mnd + //ct prep bst thread chr + //ct prep brd thread petmelee + //ct prep rng thread petmagic + + //ct prep sam dust acc/atk + //ct prep nin dust racc/ratk + //ct prep drg dust macc/mdmg + //ct prep smn dust eva/meva + + //ct prep blu sap wsd + //ct prep cor sap critrate + //ct prep pup sap stp + //ct prep dnc sap doubleattack + //ct prep sch sap haste + //ct prep geo sap dw + //ct prep run sap enmity+ + //ct prep war sap enmity- + //ct prep mnk sap snapshot + //ct prep whm sap mab + //ct prep blm sap fc + //ct prep rdm sap curepotency + //ct prep thf sap waltzpotency + //ct prep pld sap petregen + //ct prep drk sap pethaste + + //ct prep bst dye hp + //ct prep brd dye mp + //ct prep rng dye str + //ct prep sam dye dex + //ct prep nin dye vit + //ct prep drg dye agi + //ct prep smn dye int + //ct prep blu dye mnd + //ct prep cor dye chr + //ct prep pup dye acc + //ct prep dnc dye atk + //ct prep sch dye racc + //ct prep geo dye ratk + //ct prep run dye macc + //ct prep war dye mdmg + //ct prep mnk dye eva + //ct prep whm dye meva + //ct prep blm dye petacc + //ct prep rdm dye petatk + //ct prep thf dye petmacc + //ct prep pld dye petmdmg + +The **go** command is the second key component of the CapeTrader addon and requires that you have used the prep command correctly beforehand. Remember again that using this command carries with it some risks as described in the usage notes section. If you do not provide an input the go command will by default only augment your cape once. Below are equivalent ways of augmenting your cape 20 times: + + //ct go 20 + //capetrader go 20 + +The **list** command is used as a reminder of what are valid inputs for the augmentpath input of the prep command. Below are the equivalent ways of calling this command: + + //ct list + //capetrader list + //ct l + //capetrader l +___ + + +### Warnings and notes on the relevant packets +There are four parts to the process of augmenting your ambuscade cape: + +1. Part 1: Targetting gorpa-masorpa plus putting together and trading the relevant items. This takes me about 10 seconds to complete manually. (Involves outgoing packet 0x036) + +2. Part 2: Waiting for the dialog menu to pop up and become usable. This takes about 1 second and can't be controlled by the player. (Involves the incoming 0x034 packet.) + +3. Part 3: Navigating the menu to confirm and augment your cape. This takes me 2-3 seconds to confirm manually. (Involves 2 outgoing 0x05B packets) + +4. Part 4: Waiting and receiving your newly augmented cape. This takes anywhere from 1 to 3 seconds and can't be controlled by the player. (Involves the incoming 0x01D packet) + +The cape trader addon uses packets in order to substantially speed up parts one and three from above at a speed that would not normally be possible. Therefore if you use this addon you could potentially look suspicious. Part 1 of the process takes only 1 second using this addon. If this makes you uncomfortable you can change the value of the dustSapThreadTradeDelay and dyeTradeDelay variables in the capeTrader.lua file to a more reasonable amount if you wish. Please note that the augmenting with dyes needs a bit longer of a delay to work. This addon does part 3 pretty much instantaneously once the incoming 0x034 packet is received from part 2. So once again you can look suspicious again during this stage. The time it takes for part 2 and 4 should not be that different from you augmenting capes manually. + +The possibility of the loss of augment items comes from part 3. When augmenting manually you will get denied by the npc if you try to trade an already maxed cape. Injecting the 0x036 packet and later the 0x05B packets bypasses this check but you lose your augment items but receive your cape back unchanged if you have already maxed an augment path. There are some safeguards to prevent this happening in this addon but it has not been tested on every single augment path. So please use the go command with caution. + +Please keep all of the above in mind before deciding to use this addon. If you do decide to use CapeTrader I hope you find it useful! diff --git a/addons/capetrader/allAugPaths.lua b/addons/capetrader/allAugPaths.lua new file mode 100644 index 0000000000..e8f337bf68 --- /dev/null +++ b/addons/capetrader/allAugPaths.lua @@ -0,0 +1,87 @@ +--[[Copyright © 2016, Burntwaffle@Odin +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 CapeTrader 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 Lygre,Burntwaffle@Odin 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.]]-- + +return T{ + ['abdhaljs thread'] = { + [0] = 'HP', + [1] = 'MP', + [2] = 'STR', + [3] = 'DEX', + [4] = 'VIT', + [5] = 'AGI', + [6] = 'INT', + [7] = 'MND', + [8] = 'CHR', + [9] = 'PetMelee', + [10] = 'PetMagic' + }, + ['abdhaljs dust'] = { + [0] = 'Acc/Atk', + [1] = 'RAcc/RAtk', + [2] = 'MAcc/MDmg', + [3] = 'Eva/MEva' + }, + ['abdhaljs sap'] = { + [0] = 'WSD', + [1] = 'CritRate', + [2] = 'STP', + [3] = 'DoubleAttack', + [4] = 'Haste', + [5] = 'DW', + [6] = 'Enmity+', + [7] = 'Enmity-', + [8] = 'Snapshot', + [9] = 'MAB', + [10] = 'FC', + [11] = 'CurePotency', + [12] = 'WaltzPotency', + [13] = 'PetRegen', + [14] = 'PetHaste', + }, + ['abdhaljs dye'] = { + [0] = 'HP', + [1] = 'MP', + [2] = 'STR', + [3] = 'DEX', + [4] = 'VIT', + [5] = 'AGI', + [6] = 'INT', + [7] = 'MND', + [8] = 'CHR', + [9] = 'Acc', + [10] = 'Atk', + [11] = 'Racc', + [12] = 'Ratk', + [13] = 'MAcc', + [14] = 'MDmg', + [15] = 'Eva', + [16] = 'MEva', + [17] = 'PetAcc', + [18] = 'PetAtk', + [19] = 'PetMAcc', + [20] = 'PetMDmg', + }, +} diff --git a/addons/capetrader/capetrader.lua b/addons/capetrader/capetrader.lua new file mode 100644 index 0000000000..40fbbf7f6e --- /dev/null +++ b/addons/capetrader/capetrader.lua @@ -0,0 +1,521 @@ +--[[Copyright © 2016, Lygre, Burntwaffle@Odin +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 CapeTrader 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 Lygre, Burntwaffle@Odin 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 = 'CapeTrader' +_addon.author = 'Lygre, Burntwaffle' +_addon.version = '1.0.2' +_addon.commands = {'capetrader', 'ct'} + +require('luau') +require('pack') +require('sets') +require('tables') +require('functions') +require('strings') +local res = require('resources') +local packets = require('packets') +local augPaths = require('allAugPaths') +local maxAugMap = require('maxAugMap') +local extData = require('extdata') +local jobToCapeMap = require('jobToCapeMap') +local validItemNames = require('validItemNames') + +function getValidItems() + local allItems = res.items + local itemTable = T{} + local counter = 0 + local numberOfValidItems = validItemNames:length() + + for key, item in pairs(allItems) do + if counter >= numberOfValidItems then + break + end + + if validItemNames:contains(item.english) then + itemTable:update(T{ [item.english:lower()] = item }) + counter = counter + 1 + end + end + + return itemTable +end +local validItemTable = getValidItems() + +--The following variables need to be carefully tracked and updated throughout all parts of this file. +--TODO: Find ways to reduce the amount of global variables in this list +local currentCape = nil +local pathItem = nil +local pathName = nil +local pathIndex +local capeHasBeenPrepared = false +local currentlyAugmenting = false +local firstTimeAug = false +local timesAugmentedCount = 0 +local numberOfTimesToAugment = 0 +local tradeReady = false +local maxAugKey = nil +local zoneHasLoaded = true +local inventory = nil + +--The following are constants. +local dustSapThreadTradeDelay = 1 +local dyeTradeDelay = 2 +local endMessageDelay = 2 +local threadIndex = 1 +local dustIndex = 2 +local dyeIndex = 3 +local sapIndex = 4 +local inventoryBagNumber = 0 +local maxAmountDustAndThread = 20 +local maxAmountSapAndDye = 10 +local blueTextColor = 466 +local redTextColor = 123 +local greenTextColor = 158 + +--NOTE: It is possible that the correct values for the following variables can change after a version update. +local gorpaID = nil +local gorpaTargetIndex = nil +local gorpaMenuID = 0x183 +local mhauraID = res.zones:with('english','Mhaura').id + +windower.register_event('addon command', function(input, ...) + local cmd = string.lower(input) + local args = {...} + + updateGorpaID() + + if cmd == 'prep' then + if args[1] and args[2] and args[3] then + prepareCapeForAugments(args[2], args[1], args[3]) + else + windower.add_to_chat(redTextColor, "You are missing at least one input to the prep command.") + end + elseif cmd == 'go' then + if zoneHasLoaded and not currentlyAugmenting then + if args[1] then + if tonumber(args[1]) then + startAugmentingCape(args[1], true) + else + windower.add_to_chat(redTextColor, 'Error: Not given a numerical argument.') + end + else + startAugmentingCape(1, true) + end + elseif not zoneHasLoaded then + windower.add_to_chat(redTextColor, 'Your inventory has not yet loaded, please try the go command again when your inventory loads.') + elseif currentlyAugmenting then + windower.add_to_chat(redTextColor, 'You are currently still augmenting a cape, please wait until the process finishes.') + end + elseif cmd == 'list' or cmd == 'l' then + printAugList() + elseif cmd == 'help' or cmd == 'h' then + printHelp() + elseif cmd == 'unload' or cmd == 'u' then + windower.send_command('lua unload ' .. _addon.name) + elseif cmd == 'reload' or cmd == 'r' then + windower.send_command('lua reload ' .. _addon.name) + else + windower.add_to_chat(redTextColor, 'You entered an unknown command, enter //ct help if you forget your commands.') + end +end) + +function getItemIndex(capeOrAugItem) + for itemIndex, item in pairs(inventory) do + if item.id == capeOrAugItem.id then + return itemIndex + end + end +end + +function getItem(itemName) + return validItemTable[itemName:lower()] +end + +function buildTrade(capeIndex,augmentItemIndex) + local packet = packets.new('outgoing', 0x036, { + ["Target"] = gorpaID, + ["Target Index"] = gorpaTargetIndex, + ["Item Count 1"] = 1, + ["Item Count 2"] = 1, + ["Item Index 1"] = capeIndex, + ["Item Index 2"] = augmentItemIndex, + ["Number of Items"] = 2 + }) + packets.inject(packet) +end + +windower.register_event('incoming chunk', function(id, data, modified, injected, blocked) + if id == 0x00B or id == 0x00A then + zoneHasLoaded = false --NOTE: This idea was taken from Zohno's findall addon. + end + + if id == 0x034 or id == 0x032 then + if currentlyAugmenting then + + injectAugmentConfirmationPackets() + + timesAugmentedCount = timesAugmentedCount + 1 + if timesAugmentedCount <= tonumber(numberOfTimesToAugment) then + windower.add_to_chat(greenTextColor, timesAugmentedCount - 1 .. '/' .. numberOfTimesToAugment .. ' augments completed.') + tradeReady = true + else + capeHasBeenPrepared = false + currentlyAugmenting = false + currentCape = nil + pathItem = nil + tradeReady = false + windower.add_to_chat:schedule(endMessageDelay,blueTextColor,'You have finished augmenting your cape.') + end + + return true + end + end + + if id == 0x01D then + if not zoneHasLoaded then + zoneHasLoaded = true + end + if tradeReady then + tradeReady = false + + if not pathItem.english:lower():endswith(' dye') then + startAugmentingCape:schedule(dustSapThreadTradeDelay, numberOfTimesToAugment - timesAugmentedCount + 1, false) + else + startAugmentingCape:schedule(dyeTradeDelay, numberOfTimesToAugment - timesAugmentedCount + 1, false) + end + end + end +end) + +function checkDistanceToGorpa() + local zoneID = tonumber(windower.ffxi.get_info().zone) + if zoneID == mhauraID then + local gorpa = windower.ffxi.get_mob_by_id(gorpaID) + + if gorpa and gorpa.distance < 36 then + return true + else + windower.add_to_chat(redTextColor, "You're not close enough to Gorpa-Masorpa, please get closer!") + return false + end + else + windower.add_to_chat(redTextColor, "You are not in Mhaura!") + currentlyAugmenting = false + return false + end +end + +function checkAugItemCount(numberOfAugmentAttempts) + if pathItem then + local pathItemCount = 0 + + for key, itemTable in pairs(inventory) do + if key ~= 'max' and key ~= 'count' and key ~= 'enabled' then + if itemTable.id == pathItem.id then + pathItemCount = pathItemCount + itemTable.count + end + end + end + + if tonumber(numberOfAugmentAttempts) < 1 then + windower.add_to_chat(redTextColor, 'Please enter a number of 1 or greater.') + return false + elseif tonumber(numberOfAugmentAttempts) > maxAmountSapAndDye and (pathItem.english:lower():endswith(' dye') or pathItem.english:lower():endswith(' sap')) then + windower.add_to_chat(redTextColor, 'For sap or dye, the max number of times you can augment a cape is ' .. maxAmountSapAndDye .. ' times. You entered: ' .. numberOfAugmentAttempts) + return false + elseif tonumber(numberOfAugmentAttempts) > maxAmountDustAndThread and (pathItem.english:lower():endswith(' dust') or pathItem.english:lower():endswith(' thread')) then + windower.add_to_chat(redTextColor, 'For dust or thread, the max number of times you can augment a cape is ' .. maxAmountDustAndThread .. ' times. You entered: ' .. numberOfAugmentAttempts) + return false + elseif tonumber(numberOfAugmentAttempts) > pathItemCount then + local temp + if tonumber(numberOfAugmentAttempts) > 1 then + temp = ' times.' + elseif tonumber(numberOfAugmentAttempts) == 1 then + temp = ' time.' + end + + if pathItemCount ~= 0 then + windower.add_to_chat(redTextColor, 'You do not have enough ' .. pathItem.name .. ' to augment that cape ' .. numberOfAugmentAttempts .. temp ..' You only have ' .. pathItemCount .. ' in your inventory.') + else + windower.add_to_chat(redTextColor, 'You do not have enough ' .. pathItem.name .. ' to augment that cape ' .. numberOfAugmentAttempts .. temp ..' You have none in your inventory.') + end + return false + else + return true + end + end +end + +function checkCapeCount() + local capeCount = 0 + + if currentCape then + for key, itemTable in pairs(inventory) do + if key ~= 'max' and key ~= 'count' and key ~= 'enabled' then + if itemTable.id == currentCape.id then + capeCount = capeCount + 1 + end + end + end + + if capeCount > 1 then + windower.add_to_chat(redTextColor, 'You have multiple ' .. currentCape.name .. 's in your inventory! Please keep only the one you intend to augment in your inventory.') + return false + elseif capeCount == 0 then + windower.add_to_chat(redTextColor, 'You have zero ' .. currentCape.name .. 's in your inventory. Please find the one you intend to augment and move it to your inventory.') + return false + elseif capeCount == 1 then + return true + end + else + return false + end +end + +function prepareCapeForAugments(augItemType, jobName, augPath) + if not currentlyAugmenting then + local validArguments = true + local augItemTypeIsValid = false + + if not S{'sap', 'dye', 'thread', 'dust'}:contains(augItemType:lower()) then + windower.add_to_chat(redTextColor, 'Error with the type of augment item you entered. The second input should be sap or dye or thread or dust. You entered: ' .. augItemType:lower()) + validArguments = false + else + pathItem = getItem('abdhaljs ' .. augItemType) + augItemTypeIsValid = true + end + + if jobToCapeMap[jobName] then + currentCape = getItem(jobToCapeMap[jobName]) + else + windower.add_to_chat(redTextColor, 'The job name you entered is not valid. You entered: ' .. jobName) + validArguments = false + end + + if augPath and augItemTypeIsValid and validArguments then + local isValidPath = false + for i, v in pairs(augPaths[pathItem.english:lower()]) do + if augPath:lower() == v:lower() then + pathIndex = i + pathName = augPath + isValidPath = true + break + end + end + + if not isValidPath then + windower.add_to_chat(redTextColor, 'The augment path you entered is not valid. Please check the possible augment list for ' .. augItemType:lower() .. ' using the //ct list command. You entered: ' .. augPath) + validArguments = false + end + end + + if validArguments then + maxAugKey = string.lower(augItemType .. augPath) + capeHasBeenPrepared = true + timesAugmentedCount = 1 + windower.add_to_chat(greenTextColor, 'You can now augment your ' .. jobToCapeMap[jobName] .. ' with ' .. augPath:lower() .. ' using abdhaljs ' .. augItemType:lower() .. '.') + else + capeHasBeenPrepared = false + currentCape = nil + pathItem = nil + end + else + windower.add_to_chat(redTextColor, 'You can\'t setup another cape while you are currently augmenting one.') + end +end + +function startAugmentingCape(numberOfRepeats, firstAttempt) + inventory = windower.ffxi.get_items(inventoryBagNumber) + currentlyAugmenting = true + local augStatus = nil + local capeIndex + local augmentItemIndex + if capeHasBeenPrepared and checkCapeCount() and checkAugItemCount(numberOfRepeats) and checkDistanceToGorpa() then + augStatus = checkAugLimits():lower() + capeIndex = getItemIndex(currentCape) + augmentItemIndex = getItemIndex(pathItem) + end + + if firstAttempt and augStatus then + if augStatus ~= 'maxed' and augStatus ~= 'notmatching' then + if augStatus:lower() ~= 'empty' then + firstTimeAug = false + else + firstTimeAug = true + end + + local temp + if tonumber(numberOfRepeats) == 1 then + temp = 'time.' + else + temp = 'times.' + end + + numberOfTimesToAugment = numberOfRepeats + windower.add_to_chat(blueTextColor, 'Starting to augment your ' .. currentCape.name .. ' ' .. numberOfRepeats .. ' ' .. temp) + + tradeReady = false + buildTrade(capeIndex,augmentItemIndex) + else + currentlyAugmenting = false + tradeReady = false + end + elseif not firstAttempt and augStatus then + if augStatus and augStatus ~= 'maxed' then + tradeReady = false + buildTrade(capeIndex,augmentItemIndex) + else + capeHasBeenPrepared = false + currentlyAugmenting = false + tradeReady = false + pathItem = nil + currentCape = nil + windower.add_to_chat(blueTextColor, 'Your cape is currently maxed in that augment path, ending the augment process now.') + end + elseif not capeHasBeenPrepared then + currentlyAugmenting = false + windower.add_to_chat(redTextColor, 'You have not yet setup your cape and augment information with the //ct prep command!') + else + currentlyAugmenting = false + end +end + +function checkAugLimits() + local capeItem + for index, item in pairs(inventory) do + if index ~= 'max' and index ~= 'count' and index ~= 'enabled' then + if item.id == currentCape.id then + capeItem = item + break + end + end + end + + local augmentTable + if extData.decode(capeItem).augments then + augmentTable = extData.decode(capeItem).augments + end + + local augValue + if augmentTable then + if pathItem.english:lower():endswith(' thread') then + augValue = augmentTable[threadIndex] + elseif pathItem.english:lower():endswith(' dust') then + augValue = augmentTable[dustIndex] + elseif pathItem.english:lower():endswith(' dye') then + augValue = augmentTable[dyeIndex] + elseif pathItem.english:lower():endswith(' sap') then + augValue = augmentTable[sapIndex] + end + else + augValue = 'none' + end + + if augValue:lower() == 'none' or not augmentTable then + return 'empty' + end + + local max = maxAugMap[maxAugKey].max + if augValue:contains(max) then + windower.add_to_chat(redTextColor, 'You have augmented your ' .. currentCape.name .. ' to the max already with ' .. pathItem.name .. '.') + return 'maxed' + end + + local mustContainTable = maxAugMap[maxAugKey].mustcontain + for k, augmentString in pairs(mustContainTable) do + if not augValue:lower():contains(augmentString:lower()) then + windower.add_to_chat(redTextColor,'You can\'t augment your ' .. currentCape.name .. ' with ' .. pathName .. ' because it has already been augmented with: ' .. augValue .. ' using ' .. pathItem.name .. '.') + return 'notmatching' + end + end + + local cantContainTable = maxAugMap[maxAugKey].cantcontain + if table.length(cantContainTable) > 0 then + for k, augmentString in pairs(cantContainTable) do + if augValue:lower():contains(augmentString:lower()) then + windower.add_to_chat(redTextColor,'You can\'t augment your ' .. currentCape.name .. 'with ' .. pathName .. ' because it has already been augmented with: ' .. augValue .. ' using ' .. pathItem.name .. '.') + return 'notmatching' + end + end + end + + return 'allclear' +end + +function injectAugmentConfirmationPackets() + local optionIndex + if firstTimeAug then + firstTimeAug = false + optionIndex = 512 + else + optionIndex = 256 + end + + local augmentChoicePacket = packets.new('outgoing', 0x05B) + augmentChoicePacket["Target"] = gorpaID + augmentChoicePacket["Option Index"] = optionIndex + augmentChoicePacket["_unknown1"] = pathIndex + augmentChoicePacket["Target Index"] = gorpaTargetIndex + augmentChoicePacket["Automated Message"] = true + augmentChoicePacket["Zone"] = mhauraID + augmentChoicePacket["Menu ID"] = gorpaMenuID + packets.inject(augmentChoicePacket) + + augmentChoicePacket["Automated Message"] = false + packets.inject(augmentChoicePacket) + + local playerUpdatePacket = packets.new('outgoing', 0x016, { + ["Target Index"] = windower.ffxi.get_mob_by_target('me').index, + }) + packets.inject(playerUpdatePacket) +end + +function updateGorpaID() + if not gorpaID then + local zoneID = tonumber(windower.ffxi.get_info().zone) + if zoneID == mhauraID then + local gorpa = windower.ffxi.get_mob_by_name('Gorpa-Masorpa') + gorpaID = gorpa.id + gorpaTargetIndex = gorpa.index + end + end +end + +function printAugList() + windower.add_to_chat(blueTextColor, 'Thread: hp mp str dex vit agi int mnd chr petmelee petmagic') + windower.add_to_chat(blueTextColor, 'Dust: acc/atk racc/ratk macc/mdmg eva/meva') + windower.add_to_chat(blueTextColor, 'Sap: wsd critrate stp doubleattack haste dw enmity+ enmity- snapshot mab fc curepotency waltzpotency petregen pethaste') + windower.add_to_chat(blueTextColor, 'Dye: hp mp str dex vit agi int mnd chr acc atk racc ratk macc mdmg eva meva petacc petatk petmacc petmdmg') +end + +function printHelp() + windower.add_to_chat(blueTextColor, string.format('%s Version: %s Command Listing:', _addon.name, _addon.version)) + windower.add_to_chat(blueTextColor, ' reload|r Reload CapeTrader.') + windower.add_to_chat(blueTextColor, ' unload|u Unload CapeTrader.') + windower.add_to_chat(blueTextColor, ' prep Prepares a given job\'s cape with augItem on augPath. Need to use this before using //ct go.') + windower.add_to_chat(blueTextColor, ' go <#repeats> Starts augmenting cape with the info gathered from the prep command. The repeats input defaults to one if not provided.') + windower.add_to_chat(blueTextColor, ' list|l Lists all possible augitems and their valid paths. Use to know what the valid inputs for //ct prep are.') +end diff --git a/addons/capetrader/jobToCapeMap.lua b/addons/capetrader/jobToCapeMap.lua new file mode 100644 index 0000000000..552923ce2c --- /dev/null +++ b/addons/capetrader/jobToCapeMap.lua @@ -0,0 +1,50 @@ +--[[Copyright © 2016, Lygre, Burntwaffle@Odin +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 CapeTrader 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 Lygre, Burntwaffle@Odin 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.]]-- + +return T{ + ['war'] = "Cichol's Mantle", + ['mnk'] = "Segomo's Mantle", + ['whm'] = "Alaunus's Cape", + ['blm'] = "Taranus's Cape", + ['rdm'] = "Sucellos's Cape", + ['thf'] = "Toutatis's Cape", + ['pld'] = "Rudianos's Mantle", + ['drk'] = "Ankou's Mantle", + ['bst'] = "Artio's Mantle", + ['brd'] = "Intarabus's Cape", + ['rng'] = "Belenus's Cape", + ['sam'] = "Smertrios's Mantle", + ['nin'] = "Andartia's Mantle", + ['drg'] = "Brigantia's Mantle", + ['smn'] = "Campestres's Cape", + ['blu'] = "Rosmerta's Cape", + ['cor'] = "Camulus's Mantle", + ['pup'] = "Visucius's Mantle", + ['dnc'] = "Senuna's Mantle", + ['sch'] = "Lugh's Cape", + ['geo'] = "Nantosuelta's Cape", + ['run'] = "Ogma's cape", +} diff --git a/addons/capetrader/maxAugMap.lua b/addons/capetrader/maxAugMap.lua new file mode 100644 index 0000000000..c4d173762e --- /dev/null +++ b/addons/capetrader/maxAugMap.lua @@ -0,0 +1,81 @@ +--[[Copyright © 2016, Lygre, Burntwaffle@Odin +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 CapeTrader 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 Lygre, Burntwaffle@Odin 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.]]-- + +return T{ + ['threadhp'] = {['max'] = '60', ['mustcontain'] = T{'hp'},['cantcontain'] = T{}}, + ['threadmp'] = {['max'] = '60', ['mustcontain'] = T{'mp'},['cantcontain'] = T{}}, + ['threadstr'] = {['max'] = '20', ['mustcontain'] = T{'str'},['cantcontain'] = T{}}, + ['threaddex'] = {['max'] = '20', ['mustcontain'] = T{'dex'},['cantcontain'] = T{}}, + ['threadvit'] = {['max'] = '20', ['mustcontain'] = T{'vit'},['cantcontain'] = T{}}, + ['threadagi'] = {['max'] = '20', ['mustcontain'] = T{'agi'},['cantcontain'] = T{}}, + ['threadint'] = {['max'] = '20', ['mustcontain'] = T{'int'},['cantcontain'] = T{}}, + ['threadmnd'] = {['max'] = '20', ['mustcontain'] = T{'mnd'},['cantcontain'] = T{}}, + ['threadchr'] = {['max'] = '20', ['mustcontain'] = T{'chr'},['cantcontain'] = T{}}, + ['threadpetmelee'] = {['max'] = '20', ['mustcontain'] = T{'acc','r.acc','atk.','r.atk'},['cantcontain'] = T{}}, + ['threadpetmagic'] = {['max'] = '20', ['mustcontain'] = T{'pet','m.acc.','m.dmg.'},['cantcontain'] = T{}}, + + ['dustacc/atk'] = {['max'] = '20', ['mustcontain'] = T{'accuracy','attack'},['cantcontain'] = T{}}, + ['dustracc/ratk'] = {['max'] = '20', ['mustcontain'] = T{'rng.acc','rng.atk'},['cantcontain'] = T{}}, + ['dustmacc/mdmg'] = {['max'] = '20', ['mustcontain'] = T{'mag. acc','mag. dmg.'},['cantcontain'] = T{}}, + ['dusteva/meva'] = {['max'] = '20', ['mustcontain'] = T{'eva.','mag. eva.'},['cantcontain'] = T{}}, + + ['sapwsd'] = {['max'] = '10', ['mustcontain'] = T{'weapon skill damage'},['cantcontain'] = T{}}, + ['sapcritrate'] = {['max'] = '10', ['mustcontain'] = T{'crit'},['cantcontain'] = T{}}, + ['sapstp'] = {['max'] = '10', ['mustcontain'] = T{'store tp'},['cantcontain'] = T{}}, + ['sapdoubleattack'] = {['max'] = '10', ['mustcontain'] = T{'dbl.atk.'},['cantcontain'] = T{}}, + ['saphaste'] = {['max'] = '10', ['mustcontain'] = T{'haste'},['cantcontain'] = T{'pet'}}, + ['sapdw'] = {['max'] = '10', ['mustcontain'] = T{'dual'},['cantcontain'] = T{}}, + ['sapenmity+'] = {['max'] = '10', ['mustcontain'] = T{'enmity','+'},['cantcontain'] = T{}}, + ['sapenmity-'] = {['max'] = '10', ['mustcontain'] = T{'enmity','-'},['cantcontain'] = T{}}, + ['sapsnapshot'] = {['max'] = '10', ['mustcontain'] = T{'snapshot'},['cantcontain'] = T{}}, + ['sapmab'] = {['max'] = '10', ['mustcontain'] = T{'mag.atk.bns.'},['cantcontain'] = T{}}, + ['sapfc'] = {['max'] = '10', ['mustcontain'] = T{'fast cast'},['cantcontain'] = T{}}, + ['sapcurepotency'] = {['max'] = '10', ['mustcontain'] = T{'cure'},['cantcontain'] = T{}}, + ['sapwaltzpotency'] = {['max'] = '10', ['mustcontain'] = T{'waltz'},['cantcontain'] = T{}}, + ['sappetregen'] = {['max'] = '10', ['mustcontain'] = T{'pet','regen'},['cantcontain'] = T{}}, + ['sappethaste'] = {['max'] = '10', ['mustcontain'] = T{'pet','haste'},['cantcontain'] = T{}}, + + ['dyehp'] = {['max'] = '20', ['mustcontain'] = T{'hp'},['cantcontain'] = T{}}, + ['dyemp'] = {['max'] = '20', ['mustcontain'] = T{'mp'},['cantcontain'] = T{}}, + ['dyestr'] = {['max'] = '10', ['mustcontain'] = T{'str'},['cantcontain'] = T{}}, + ['dyedex'] = {['max'] = '10', ['mustcontain'] = T{'dex'},['cantcontain'] = T{}}, + ['dyevit'] = {['max'] = '10', ['mustcontain'] = T{'vit'},['cantcontain'] = T{}}, + ['dyeagi'] = {['max'] = '10', ['mustcontain'] = T{'agi'},['cantcontain'] = T{}}, + ['dyeint'] = {['max'] = '10', ['mustcontain'] = T{'int'},['cantcontain'] = T{}}, + ['dyemnd'] = {['max'] = '10', ['mustcontain'] = T{'mnd'},['cantcontain'] = T{}}, + ['dyechr'] = {['max'] = '10', ['mustcontain'] = T{'chr'},['cantcontain'] = T{}}, + ['dyeacc'] = {['max'] = '10', ['mustcontain'] = T{'accuracy'},['cantcontain'] = T{'pet'}}, + ['dyeatk'] = {['max'] = '10', ['mustcontain'] = T{'attack'},['cantcontain'] = T{'pet'}}, + ['dyeracc'] = {['max'] = '10', ['mustcontain'] = T{'rng', 'acc'},['cantcontain'] = T{'pet'}}, + ['dyeratk'] = {['max'] = '10', ['mustcontain'] = T{'rng', 'atk'},['cantcontain'] = T{'pet'}}, + ['dyemacc'] = {['max'] = '10', ['mustcontain'] = T{'mag', 'acc'},['cantcontain'] = T{'pet'}}, + ['dyemdmg'] = {['max'] = '10', ['mustcontain'] = T{'magic', 'damage'},['cantcontain'] = T{'pet'}}, + ['dyeeva'] = {['max'] = '10', ['mustcontain'] = T{'evasion'}, ['cantcontain'] = T{'mag'}}, + ['dyemeva'] = {['max'] = '10', ['mustcontain'] = T{'mag', 'evasion'},['cantcontain'] = T{}}, + ['dyepetacc'] = {['max'] = '10', ['mustcontain'] = T{'pet','accuracy','rng', 'acc'},['cantcontain'] = T{}}, + ['dyepetatk'] = {['max'] = '10', ['mustcontain'] = T{'pet','attack','rng', 'atk'},['cantcontain'] = T{}}, + ['dyepetmacc'] = {['max'] = '10', ['mustcontain'] = T{'pet','mag' , 'acc'},['cantcontain'] = T{}}, + ['dyepetmdmg'] = {['max'] = '10', ['mustcontain'] = T{'pet','magic', 'damage'},['cantcontain'] = T{}}, +} diff --git a/addons/capetrader/validItemNames.lua b/addons/capetrader/validItemNames.lua new file mode 100644 index 0000000000..9e4fa5f36d --- /dev/null +++ b/addons/capetrader/validItemNames.lua @@ -0,0 +1,54 @@ +--[[Copyright © 2016, Lygre, Burntwaffle@Odin +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 CapeTrader 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 Lygre, Burntwaffle@Odin 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.]]-- + +return T{ + "Cichol's Mantle", + "Segomo's Mantle", + "Alaunus's Cape", + "Taranus's Cape", + "Sucellos's Cape", + "Toutatis's Cape", + "Rudianos's Mantle", + "Ankou's Mantle", + "Artio's Mantle", + "Intarabus's Cape", + "Belenus's Cape", + "Smertrios's Mantle", + "Andartia's Mantle", + "Brigantia's Mantle", + "Campestres's Cape", + "Rosmerta's Cape", + "Camulus's Mantle", + "Visucius's Mantle", + "Senuna's Mantle", + "Lugh's Cape", + "Nantosuelta's Cape", + "Ogma's cape", + "Abdhaljs Thread", + "Abdhaljs Dust", + "Abdhaljs Dye", + "Abdhaljs Sap", +} diff --git a/addons/checkparam/README.md b/addons/checkparam/README.md new file mode 100644 index 0000000000..7b0a6bcaeb --- /dev/null +++ b/addons/checkparam/README.md @@ -0,0 +1,30 @@ +# checkparam +![40696007-caf91c3c-63fe-11e8-9837-516f9e1f2b0e](https://user-images.githubusercontent.com/26649687/40877257-96ccef12-66b8-11e8-97a4-797789375a00.jpg) +## English +- `/check` OR `/c` (in-game command) + - Whenever you `/check` any player, displays the total of property of that players current equipments.(defined in `settings.xml`) +- `//checkparam` OR `//cp` (addon command) + - same as /check . you can use this command in equipment menu. + +### data/settings.xml (auto-generated) +- Define the properties you want to be displayed for each job. + - `|` divide each property + - `pet: ` define properties for all pets, which means avatar: wyvern: automaton: luopan: +- `` ignore players with below the level `` when `/check`. default value is 99. + - **Tips:** if set `100`, ignore all players. you can still use `//cp` for yourself. +- If there’s something wrong,or something strange, +please tell me on Twitter [@from20020516](https://twitter.com/from20020516) **with simple English**. Thank you! + +## 日本語 +- `/check` または `/c`(ゲーム内コマンド) + - プレイヤーを「調べる」したとき、そのプレイヤーが装備しているアイテムの任意のプロパティを合計して表示します。(`settings.xml`で定義) +- `//checkparam` または `//cp`(アドオンコマンド) + - /check と同様ですが、装備変更画面でも使用できます。 + +### data/settings.xml (自動生成) +- 表示させたいプロパティをジョブごとに定義します。 + - `|` 区切り記号 + - `pet: ` 召喚獣: 飛竜: オートマトン: 羅盤: は代わりに`pet:`で指定します。 +- `` + -「調べる」時に対象のレベルが設定値未満なら結果を表示しません。(初期値99) + - **Tips:** `100`を設定すると「調べる」時の結果を表示しません。 diff --git a/addons/checkparam/checkparam.lua b/addons/checkparam/checkparam.lua new file mode 100644 index 0000000000..b3b6bc9821 --- /dev/null +++ b/addons/checkparam/checkparam.lua @@ -0,0 +1,373 @@ +--[[ +Copyright © 2018, from20020516 +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 checkparam 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 from20020516 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 = 'Checkparam' +_addon.author = 'from20020516 & Kigen' +_addon.version = '1.3' +_addon.commands = {'cp','checkparam'} + +require('logger') +res = require('resources') +extdata = require('extdata') +config = require('config') +packets = require('packets') +require('math') + +defaults = { + WAR = 'store tp|double attack|triple attack|quadruple attack|weapon skill damage', + MNK = 'store tp|double attack|triple attack|quadruple attack|martial arts|subtle blow', + WHM = 'cure potency|cure potency ii|fast cast|quick cast|cure spellcasting time|enmity|healing magic casting time|divine benison|damage taken|physical damage taken|magic damage taken', + BLM = 'magic attack bonus|magic burst damage|magic burst damage ii|int|magic accuracy|magic damage|fast cast|elemental magic casting time', + RDM = 'magic attack bonus|magic burst damage|magic burst damage ii|magic accuracy|fast cast|quick cast|enfeebling magic skill|enhancing magic skill|store tp|dual wield', + THF = 'store tp|double attack|triple attack|quadruple attack|dual wield|critical hit rate|critical hit damage|haste|weapon skill damage|steal|sneak attack|trick attack', + PLD = 'enmity|damage taken|physical damage taken|magic damage taken|spell interruption rate|phalanx|cure potency|fastcast', + DRK = 'store tp|double attack|triple attack|quadruple attack|weapon skill damage', + BST = 'pet: double attack|pet: magic attack bonus|pet: damage taken', + BRD = 'all songs|song effect duration|fast cast|song spellcasting time|singing skill|wind skill|string skill', + RNG = 'store tp|snapshot|rapid shot|weapon skill damage', + SAM = 'store tp|double attack|triple attack|quadruple attack|weapon skill damage', + NIN = 'store tp|double attack|triple attack|quadruple attack|subtle blow', + DRG = 'store tp|double attack|triple attack|quadruple attack|weapon skill damage', + SMN = 'physical damage taken|magic damage taken|pet: physical damage taken|pet: magic damage taken|blood pact delay|blood pact delay ii|blood pact damage|avatar perpetuation cost|pet: magic attack bonus|pet: attack|pet: double attack|pet: accuracy|pet: magic accuracy|summoning magic skill|pet: blood pact damage|pet: magic damage', + BLU = 'physical damage taken|magic damage taken|haste|dual wield|store tp|double attack|triple attack|quadruple attack|critical hit rate|critical hit damage|weapon skill damage|fast cast|magic attack bonus|magic accuracy|cure potency', + COR = 'physical damage taken|magic damage taken|haste|dual wield|store tp|snapshot|rapid shot|fast cast|cure potency|magic accuracy|magic attack bonus|magic damage|weapon skill damage', + PUP = 'pet: hp|pet: damage taken|pet: regen|martial arts|store tp|double attack|triple attack|quadruple attack', + DNC = 'store tp|double attack|triple attack|quadruple attack', + SCH = 'magic attack bonus|magic burst damage|magic burst damage ii|magic accuracy|magic damage|fast cast|elemental magic casting time|cure potency|enh mag eff dur|enhancing magic effect duration', + GEO = 'pet: regen|pet: damage taken|indicolure effect duration|fast cast|magic evasion|handbell skill|geomancy skill|geomancy', + RUN = 'enmity|damage taken|physical damage taken|magic damage taken|spell interruption rate|phalanx|inquartata|fastcast', + levelfilter = 99, +} +settings = config.load(defaults) + +tbl = {} + +windower.register_event('addon command',function(arg) + local items = windower.ffxi.get_items + for i=0,#res.slots do + local slot = windower.regex.replace(string.lower(res.slots[i].english),' ','_') + local gear_set = items().equipment + local gear = items(gear_set[slot..'_bag'],gear_set[slot]) + if gear_set[slot] > 0 then + get_text(gear.id,gear.extdata) + end + end + local my = windower.ffxi.get_player() + show_results(my.name,my.main_job,my.sub_job) +end) + +windower.register_event('incoming chunk',function(id,data) + if id == 0x0C9 then + local p = packets.parse('incoming',data) + if p['Type'] == 3 then + local count = p['Count'] + if count == 1 then + get_text(p['Item'],p['ExtData']) + else + for i=1,count do + get_text(p['Item '..i],p['ExtData '..i]) + end + end + elseif p['Type'] == 1 then + local t = windower.ffxi.get_mob_by_index(p['Target Index']) + local mjob = res.jobs[p['Main Job']].english_short + local sjob = res.jobs[p['Sub Job']].english_short + if p['Main Job Level'] >= settings.levelfilter then + show_results(t.name,mjob,sjob) + else + tbl = {} + if mjob == 'NON' then + error('The target is in /anon state.') + end + end + end + end +end) + +function get_text(id,data) + config.reload(settings) + local descriptions = res.item_descriptions[id] + local helptext = descriptions and descriptions.english or '' --for 'vanilla' items. e.g. Moonshade Earring + local stats = windower.regex.split(helptext,'(Pet|Avatar|Automaton|Wyvern|Luopan): ') + for i,v in ipairs(windower.regex.split(stats[1],'\n')) do + split_text(id,v) + end + if stats[2] then + stats[2] = stats[2]:trim() + split_text(id,stats[2],'pet: ') + end + local ext = extdata.decode({id=id,extdata=data}) + if ext.augments then + for i,v in ipairs(ext.augments) do + local stats = windower.regex.split(v,'(Pet|Avatar|Automaton|Wyvern|Luopan): ') + if stats[2] then + stats[2] = stats[2]:trim() + split_text(id,stats[2],'pet: ') + else + split_text(id,v) + end + end + end + if enhanced[id] then + local stats = enhanced[id]:gsub('([+-:][0-9]+)',',%1'):split(',') + tbl[stats[1]] = tonumber(stats[2]) + (tbl[stats[1]] or 0) + if settings.debugmode then + log(id,res.items[id].english,stats[1],stats[2],tbl[stats[1]]) + end + end + tbl.sets = tbl.sets or {} + table.insert(tbl.sets,id) +end + +function split_text(id,text,arg) + for key,value in string.gmatch(text,'/?([%D]-):?([%+%-]?[0-9]+)%%?%s?') do + local key = windower.regex.replace(string.lower(key),'(\\"|\\.|\\s$)','') + local key = integrate[key] or key + local key = arg and arg..key or key + if key == "blood pact damage" then + key = "pet: blood pact damage" + elseif key == "pet: damage taken" then + tbl['pet: physical damage taken'] = tonumber(value)+(tbl['pet: physical damage taken'] or 0) + tbl['pet: magic damage taken'] = tonumber(value)+(tbl['pet: magic damage taken'] or 0) + elseif key == "damage taken" then + tbl['physical damage taken'] = tonumber(value)+(tbl['physical damage taken'] or 0) + tbl['magic damage taken'] = tonumber(value)+(tbl['magic damage taken'] or 0) + tbl['breath damage taken'] = tonumber(value)+(tbl['breath damage taken'] or 0) + else + tbl[key] = tonumber(value)+(tbl[key] or 0) + end + if settings.debugmode then + log(id,res.items[id].english,key,value,tbl[key]) + end + end +end + +function show_results(name,mjob,sjob) + local count = {} + for key,value in pairs(combination) do + for _,id in pairs(tbl.sets) do + if value.item[id] then + count[key] = (count[key] or 0)+1 + end + end + if count[key] and count[key] > 1 then + for stat,multi in pairs(value.stats) do + tbl[stat] = (tbl[stat] or 0)+multi*math.min((count[key]+value.type),5) + end + end + end + local stats = settings[mjob] + local head = '<'..mjob..'/'..(sjob or '')..'>' + windower.add_to_chat(160,string.color(name,1,160)..': '..string.color(head,160,160)) + for index,key in ipairs(windower.regex.split(stats,'[|]')) do + -- WA for blood pact damage showing when it is converted to pet: blood pact damage + -- WA for damage taken showing when it is converted to physical/magic damage taken + key = string.lower(key) + if key ~= 'blood pact damage' and key ~= 'damage taken' then + local value = tbl[key] + local color = {value and 1 or 160,value and 166 or 160, 106, 205, 61} + local stat_cap = caps[key] + local output_string = ' ['..string.color(key,color[1],160)..']' + if stat_cap == nil or value == nil then + output_string = output_string..' '..string.color(tostring(value),color[2],160) + elseif value == stat_cap then + output_string = output_string..' '..string.color(tostring(value),color[3],160)..'/'..string.color(tostring(stat_cap),155,160) + elseif math.abs(value) > math.abs(stat_cap) then + output_string = output_string..' '..string.color(tostring(value),color[4],160)..'/'..string.color(tostring(stat_cap),155,160) + else + output_string = output_string..' '..string.color(tostring(value),color[5],160)..'/'..string.color(tostring(stat_cap),155,160) + end + windower.add_to_chat(160,output_string) + end + end + tbl = {} +end + +integrate = { + --[[integrate same property.information needed for development. @from20020516]] + ['quad atk'] = 'quadruple attack', + ['quad attack'] = 'quadruple attack', + ['triple atk'] = 'triple attack', + ['double atk'] = 'double attack', + ['dblatk'] = 'double attack', + ['blood pact ability delay'] = 'blood pact delay', + ['blood pact ability delay ii'] = 'blood pact delay ii', + ['blood pact ab del ii'] = 'blood pact delay ii', + ['blood pact recast time ii'] = 'blood pact delay ii', + ['blood pact dmg'] = 'blood pact damage', + ['enhancing magic duration'] = 'enhancing magic effect duration', + ['eva'] = 'evasion', + ['indicolure spell duration'] = 'indicolure effect duration', + ['indi eff dur'] = 'indicolure effect duration', + ['mag eva'] = 'magic evasion', + ['magic eva'] = 'magic evasion', + ['magic atk bonus'] = 'magic attack bonus', + ['magatkbns'] = 'magic attack bonus', + ['mag atk bonus'] = 'magic attack bonus', + ['mag acc'] = 'magic accuracy', + ['m acc'] = 'magic accuracy', + ['r acc'] = 'ranged accuracy', + ['magic burst dmg'] = 'magic burst damage', + ['mag dmg'] = 'magic damage', + ['crithit rate'] = 'critical hit rate', + ['phys dmg taken'] = 'physical damage taken', + ['occ. quickens spellcasting']="quick cast", + ['occassionally quickens spellcasting']="quick cast", + ['song duration']="song effect duration", +} +enhanced = { + [10392] = 'cursna+10', --Malison Medallion + [10393] = 'cursna+15', --Debilis Medallion + [10394] = 'fast cast+5', --Orunmila's Torque + [10469] = 'fast cast+10', --Eirene's Manteel + [10752] = 'fast cast+2', --Prolix Ring + [10790] = 'cursna+10', --Ephedra Ring + [10791] = 'cursna+15', --Haoma's Ring + [10802] = 'fast cast+5', --Majorelle Shield + [10806] = 'potency of cure effects received+15', --Adamas + [10826] = 'fast cast+3', --Witful Belt + [10838] = 'dual wield+5', --Patentia Sash + [11000] = 'fast cast+3', --Swith Cape + [11001] = 'fast cast+4', --Swith Cape +1 + [11037] = 'stoneskin+10', --Earthcry Earring + [11051] = 'increases resistance to all status ailments+5', --Hearty Earring + [11544] = 'fast cast+1', --Veela Cape + [11602] = 'martial arts+10', --Cirque Necklace + [11603] = 'dual wield+3', --Charis Necklace + [11615] = 'fast cast+5', --Orison Locket + [11707] = 'fast cast+2', --Estq. Earring + [11711] = 'rewards+2', --Ferine Earring + [11715] = 'dual wield+1', --Iga Mimikazari + [11722] = 'sublimation+1', --Savant's Earring + [11732] = 'dual wield+5', --Nusku's Sash + [11734] = 'martial arts+10', --Shaolin Belt + [11735] = 'snapshot+3', --Impulse Belt + [11753] = 'aquaveil+1', --Emphatikos Rope + [11775] = 'occult acumen+20', --Oneiros Rope + [11856] = 'fast cast+10', --Anhur Robe + [13177] = 'stoneskin+30', --Stone Gorget + [14739] = 'dual wield+5', --Suppanomimi + [14812] = 'fast cast+2', --Loquac. Earring + [14813] = 'double attack+5', --Brutal Earring + [15857] = 'drain and aspir potency+5', --Excelsis Ring + [15960] = 'stoneskin+20', --Siegel Sash + [15962] = 'magic burst damage+5', --Static Earring + [16209] = 'snapshot+5', --Navarch's Mantle + [19062] = 'divine benison+1', --Yagrush80 + [19082] = 'divine benison+2', --Yagrush85 + [19260] = 'dual wield+3', --Raider's Bmrng. + [19614] = 'divine benison+3', --Yagrush90 + [19712] = 'divine benison+3', --Yagrush95 + [19821] = 'divine benison+3', --Yagrush99 + [19950] = 'divine benison+3', --Yagrush99+ + [20509] = 'counter+14', --Spharai119AG + [20511] = 'martial arts+55', --Kenkonken119AG + [21062] = 'divine benison+3', --Yagrush119 + [21063] = 'divine benison+3', --Yagrush119+ + [21078] = 'divine benison+3', --Yagrush119AG + [21201] = 'fast cast+2', --Atinian Staff +1 + [27279] = 'physical damage taken-6', --Eri. Leg Guards + [27280] = 'physical damage taken-7', --Eri. Leg Guards +1 + [21699] = 'potency of cure effects received+10', --Nibiru Faussar + [27768] = 'fast cast+5', --Cizin Helm + [27775] = 'fast cast+10', --Nahtirah Hat + [28054] = 'fast cast+7', --Gendewitha Gages + [28058] = 'snapshot+4', --Manibozho Gloves + [28184] = 'fast cast+5', --Orvail Pants +1 + [28197] = 'snapshot+9', --Nahtirah Trousers + [28206] = 'fast cast+10', --Geomancy Pants + [28335] = 'cursna+10', --Gende. Galoshes + [28459] = 'potency of cure effects received+5', --Chuq'aba Belt + [28484] = 'cure potency+3', --Nourish Earring + [28485] = 'cure potency+5', --Nourish Earring +1 + [28577] = 'potency of cure effects received+5', --Kunaji Ring + [28582] = 'magic burst damage+5', --Locus Ring + [28619] = 'cursna+15', --Mending Cape + [28631] = 'elemental siphon+30', --Conveyance Cape + [28637] = 'fast cast+7', --Lifestream Cape + [11618] = 'song effect duration+10', -- Aoidos' Matinee + [20629] = 'song effect duration+5', -- Legato Dagger +} +combination={ + ['af']={item=S{ + 23040,23041,23042,23043,23044,23045,23046,23047,23048,23049,23050,23051,23052,23053,23055,23056,23057,23058,23059,23060,23061,23062, + 23107,23108,23109,23110,23111,23112,23113,23114,23115,23116,23117,23118,23119,23120,23122,23123,23124,23125,23126,23127,23128,23129, + 23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,23186,23187,23189,23190,23191,23192,23193,23194,23195,23196, + 23241,23242,23243,23244,23245,23246,23247,23248,23249,23250,23251,23252,23253,23254,23256,23257,23258,23259,23260,23261,23262,23263, + 23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,23318,23319,23320,23321,23323,23324,23325,23326,23327,23328,23329,23330, + 23375,23376,23377,23378,23379,23380,23381,23382,23383,23384,23385,23386,23387,23388,23390,23391,23392,23393,23394,23395,23396,23397, + 23442,23443,23444,23445,23446,23447,23448,23449,23450,23451,23452,23453,23454,23455,23457,23458,23459,23460,23461,23462,23463,23464, + 23509,23510,23511,23512,23513,23514,23515,23516,23517,23518,23519,23520,23521,23522,23524,23525,23526,23527,23528,23529,23530,23531, + 23576,23577,23578,23579,23580,23581,23582,23583,23584,23585,23586,23587,23588,23589,23591,23592,23593,23594,23595,23596,23597,23598, + 23643,23644,23645,23646,23647,23648,23649,23650,23651,23652,23653,23654,23655,23656,23658,23659,23660,23661,23662,23663,23664,23665, + 26085,26191},stats={['accuracy']=15,['magic accuracy']=15,['ranged accuracy']=15},type=-1}, + ['af_smn']={item=S{23054,23121,23188,23255,23322,23389,23456,23523,23590,23657,26342}, + stats={['pet: accuracy']=15,['pet: magic accuracy']=15,['pet: ranged accuracy']=15},type=-1}, + ['adhemar']={item=S{25614,25687,27118,27303,27474},stats={['critical hit rate']=2},type=0}, + ['amalric']={item=S{25616,25689,27120,27305,27476},stats={['magic attack bonus']=10},type=0}, + ['apogee']={item=S{26677,26853,27029,27205,27381},stats={['pet: blood pact damage']=2},type=0}, + ['argosy']={item=S{26673,26849,27025,27201,27377},stats={['double attack']=2},type=0}, + ['emicho']={item=S{25610,25683,27114,27299,27470},stats={['double attack']=2},type=0}, + ['carmine']={item=S{26679,26855,27031,27207,27383},stats={['accuracy']=10},type=0}, + ['kaykaus']={item=S{25618,25691,27122,27307,27478},stats={['cure potency ii']=2},type=0}, + ['lustratio']={item=S{26669,26845,27021,27197,27373},stats={['weapon skill damage']=2},type=0}, + ['rao']={item=S{26675,26851,27027,27203,27379},stats={['matial arts']=2},type=0}, + ['ryuo']={item=S{25612,25685,27116,27301,27472},stats={['attack']=10},type=0}, + ['souveran']={item=S{26671,26847,27023,27199,27375},stats={['damage taken']=2},type=0}, + ['ayanmo']={item=S{25572,25795,25833,25884,25951},stats={['str']=8,['vit']=8,['mnd']=8},type=-1}, + ['flamma']={item=S{25569,25797,25835,25886,25953},stats={['str']=8,['dex']=8,['vit']=8},type=-1}, + ['mallquis']={item=S{25571,25799,25837,25888,25955},stats={['vit']=8,['int']=8,['mnd']=8},type=-1}, + ['Mummu']={item=S{25570,25798,25836,25887,25954},stats={['dex']=8,['agi']=8,['chr']=8},type=-1}, + ['tali\'ah']={item=S{25573,25796,25834,25885,25952},stats={['vit']=8,['dex']=8,['chr']=8},type=-1}, + ['Hizamaru']={item=S{25576,25792,25830,25881,25948},stats={['counter']=2},type=-1}, + ['Inyanga']={item=S{25577,25793,25831,25882,25949},stats={['refresh']=1},type=-1}, + ['jhakri']={item=S{25578,25794,25832,25883,25950},stats={['fast cast']=3},type=-1}, + ['meghanada']={item=S{25575,25791,25829,25880,25947},stats={['regen']=3},type=-1}, + ['Sulevia\'s']={item=S{25574,25790,25828,25879,25946},stats={['subtle blow']=5},type=-1}, + ['BladeFlashEarrings']={item=S{28520,28521},stats={['double attack']=7},type=-1}, + ['HeartDudgeonEarrings']={item=S{28522,28523},stats={['dual wield']=7},type=-1} +} + +caps={ + ['haste']=25, + ['subtle blow']=50, + ['cure potency']=50, + ['potency of cure effects received']=30, + ['quick cast']=10, + ['physical damage taken']=-50, + ['magic damage taken']=-50, + ['breath damage taken']=-50, + ['pet: physical damage taken']=-87.5, + ['pet: magic damage taken']=-87.5, + ['pet: haste']=25, + ['magic burst damage']=40, + ['blood pact delay']=-15, + ['blood pact delay ii']=-15, + ['save tp']=500, + ['fast cast']=80, + ['reward']=50 +} diff --git a/addons/craft/README.md b/addons/craft/README.md new file mode 100644 index 0000000000..64f29a739b --- /dev/null +++ b/addons/craft/README.md @@ -0,0 +1,38 @@ +**Author:** Snaps
+**Version:** 1.1.3
+**Date:** June 13th, 2017
+ +# craft # + +* A Final Fantasy XI Crafting Addon + +#### Commands: #### +1. help - Shows a menu of commands in game. +2. repeat [count] - Repeats synthesis (default 1) using the lastsynth command. +- repeat - Repeats 1 synthesis. +- r 13 - Repeats 13 synthesis. +3. make [recipe] [count] - Issue a synthesis command using a recipe name. +- make "Sheep Leather" - Makes 1 Sheep Leather. +- m "Sheep Leather" 5 - Makes 5 Sheep Leather. +4. put [bag] - 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 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 24s) +- delay 30 - Sets the delay between crafting to 30 seconds. +6. food [item] - Sets a food item that will be consumed automatically while crafting (default None.) +- 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 pending items in the queue. +10. jiggle [key] - 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. +12. find [details] - 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". The recipe ingredients and crystal are also displayed. +13. status - Display some information about the addon's current state. +14. display - Toggles whether outgoing crafting packets are displayed in the chat log. diff --git a/addons/craft/craft.lua b/addons/craft/craft.lua new file mode 100644 index 0000000000..020893d35e --- /dev/null +++ b/addons/craft/craft.lua @@ -0,0 +1,820 @@ +--[[ +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\" ':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\" ':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\" ':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() + coroutine.sleep(2) + 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 + local count = p['Count'] + if count > 1 then + windower.add_to_chat(121, 'You synthesized: \30\02%s\30\01 x%d.':format(item, count)) + else + windower.add_to_chat(121, 'You synthesized: \30\02%s\30\01.':format(item)) + end + 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) diff --git a/addons/craft/create_recipes.py b/addons/craft/create_recipes.py new file mode 100644 index 0000000000..cc02c28158 --- /dev/null +++ b/addons/craft/create_recipes.py @@ -0,0 +1,250 @@ +import urllib.request +from bs4 import BeautifulSoup +from slpp import slpp as lua +import os +import platform + + +hdr = { + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', + 'Accept-Encoding': 'none', + 'Accept-Language': 'en-US,en;q=0.8', + 'Connection': 'keep-alive', +} + +sphere = None + +def get_recipe(row): + crystals = [ + 'Dark Crystal', + 'Light Crystal', + 'Earth Crystal', + 'Water Crystal', + 'Fire Crystal', + 'Wind Crystal', + 'Lightning Crystal', + 'Ice Crystal', + 'Pyre Crystal', + 'Frost Crystal', + 'Vortex Crystal', + 'Geo Crystal', + 'Terra II Crystal', + 'Bolt Crystal', + 'Fluid Crystal', + 'Glimmer Crystal', + 'Shadow Crystal', + ] + result, _, recipe = [ + td for td in row.findAll('td') + ] + name = str(result.findAll('a')[0]['title']) + crystal = None + ingredients = [] + for li in recipe.findAll('li'): + english = str(li.findAll('a')[0]['title']) + if english in crystals: + crystal = english + continue + try: + if li.text is None: + ingredients.append("unknown") # ingredient is "Question Mark", e.g. for Pagodite + elif li.text[-1].isdigit() and not "Kit" in english: + for n in range(int(li.text[-1])): + ingredients.append(english) + else: + ingredients.append(english) + except IndexError: + return None + return [(name, crystal, ingredients)] + +def get_sphere_recipe(row): + spheres = [ + 'Liquefaction Sphere', + 'Transfixion Sphere', + 'Detonation Sphere', + 'Impaction Sphere', + 'Induration Sphere', + 'Reverberation Sphere', + 'Scission Sphere', + 'Compression Sphere', + ] + global sphere + cells = [td for td in row.findAll('td')] + if len(cells) > 4: + rare_ex, rare, ex, c, s = cells[:5] + if str(s.findAll('a')[0]['title']) in spheres: + sphere = str(s.findAll('a')[0]['title']) + else: + rare_ex, rare, ex, c = cells[:4] + recipes = [] + crystal = str(c.findAll('img')[0]['alt']).rstrip(' icon.png') + ingredients = [] + for cell in cells[:3]: + for a in cell.findAll('a'): + recipes.append((sphere, crystal, [str(a['title'])])) + return recipes + +def get_recipes_from_rows(rows, spheres=False): + recipes = {} + for row in rows: + if spheres: + subrecipes = get_sphere_recipe(row) + else: + subrecipes = get_recipe(row) + for (name, crystal, ingredients) in subrecipes: + while name in recipes.keys(): + if name[-1].isdigit(): + name = name[:-2] + (" %d" % (int(name[-1]) + 1)) + else: + name = name + " 2" + recipes[name] = [crystal, ingredients] + return recipes + +def get_recipes_from_soup(soup, spheres=False): + string = "Sphere Obtained" if spheres else "Synthesis Information" + lengths = [4, 5, 6, 7] if spheres else [3] + subtables = [ + descendant.parent.parent.parent + for descendant in soup.descendants + if string in descendant + ] + rows = [] + for subtable in subtables: + children = [ + row + for row in subtable.children + if (hasattr(row, 'findAll') and + len(row.findAll('td')) in lengths) + ] + rows.extend(children) + return get_recipes_from_rows(rows, spheres) + +def get_items_dictionary(): + if platform.system() == 'Windows': + path = 'C:\\Program Files (x86)\\Windower4\\res\\items.lua' + else: + path = os.path.join(os.path.expanduser("~"), 'Resources/lua/items.lua') + with open(path) as fd: + data = fd.read().replace('return', '', 1) + return lua.decode(data) + +def get_items(): + exceptions = { + 'geo crystal' : 6509, + 'terra ii crystal' : 6509, + 'broken single-hook fishing rod' : 472, + 'broken hume rod' : 1832, + 'broken bamboo rod' : 487, + 'dark adaman sheet' : 2001, + 'black chocobo fletchings' : 1254, + 'broken willow rod' : 485, + 'four-leaf korringan bud' : 1265, + 'broken fastwater rod' : 488, + 'h. q. coeurl hide' : 1591, + 'broken yew rod' : 486, + 'broken mithran rod' : 483, + 'broken tarutaru rod' : 484, + "broken lu shang's rod" : 489, + 'fire emblem card' : 9764, + 'ice emblem card' : 9765, + 'wind emblem card' : 9766, + 'earth emblem card' : 9767, + 'lightning emblem card': 9768, + 'water emblem card' : 9769, + 'light emblem card': 9770, + 'dark emblem card': 9771, + } + items = get_items_dictionary() + inverted = {} + for k, v in items.items(): + if not v['en'].lower() in inverted: + inverted[v['en'].lower()] = k + if not v['enl'].lower() in inverted: + inverted[v['enl'].lower()] = k + inverted.update(exceptions) + return items, inverted + +def get_item(ingredient, inverted): + results = [] + exceptions = { + 'behemoth leather' : 'square of behemoth leather', + 'puk fletchings' : 'bag of puk fletchings', + 'phrygian gold' : 'phrygian gold ingot', + 'smilodon leather' : 'square of smilodon leather', + 'chocobo fletchings' : 'bag of chocobo fletchings', + 'vermilion lacquer' : 'pot of vermilion lacquer', + } + if ingredient in exceptions: + return inverted[exceptions[ingredient]] + for name, iid in inverted.items(): + if ingredient in name: + return iid + +def fix_recipes(recipes): + items, inverted = get_items() + for name, (crystal, ingredients) in recipes.items(): + crystal = items[inverted[crystal.lower()]]['en'] + sorted = [] + for ingredient in ingredients: + ingredient = ingredient.lower() + if ingredient in inverted: + sorted.append(inverted[ingredient]) + else: + sorted.append(get_item(ingredient, inverted)) + sorted = list(filter(lambda item: item is not None, sorted)) + sorted.sort() + ingredients = [ + items[ingredient]['en'] + for ingredient in sorted + ] + recipes[name] = [crystal, ingredients] + +def build_recipe_string(name, crystal, ingredients): + recipe = " [\"%s\"] = {\n [\"crystal\"] = \"%s\",\n [\"ingredients\"] = {\n" % (name, crystal) + for ingredient in ingredients: + recipe += " \"%s\",\n" % ingredient + recipe += " },\n },\n" + return recipe + +def save_recipes(recipes): + with open('recipes.lua', 'w') as fd: + fd.write("return {\n") + for key in sorted(recipes.keys()): + fd.write(build_recipe_string(key, *recipes[key])) + fd.write("}\n") + +def get_recipes(craft, spheres=False): + base = "https://www.bg-wiki.com/bg/" + name = "%s.html" % craft + if not os.path.exists(name): + req = urllib.request.Request(base + craft, headers=hdr) + try: + page = urllib.request.urlopen(req).read() + except urllib.request.HTTPError: + return + with open(name, 'wb') as fd: + fd.write(page) + with open(name, 'r') as fd: + page = fd.read() + soup = BeautifulSoup(page, 'lxml') + return get_recipes_from_soup(soup, spheres) + +if __name__ == "__main__": + crafts = [ + 'Alchemy', + 'Bonecraft', + 'Clothcraft', + 'Cooking', + 'Goldsmithing', + 'Leathercraft', + 'Smithing', + 'Woodworking', + ] + recipes = {} + for craft in crafts: + recipes.update(get_recipes(craft)) + recipes.update(get_recipes('Category:Escutcheons', True)) + fix_recipes(recipes) + save_recipes(recipes) diff --git a/addons/craft/recipes.lua b/addons/craft/recipes.lua new file mode 100644 index 0000000000..10ee9fb487 --- /dev/null +++ b/addons/craft/recipes.lua @@ -0,0 +1,37591 @@ +return { + ["3-Drawer Almirah"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Ebony Lumber", + "Ancient Lumber", + "Gold Thread", + "Silk Cloth", + }, + }, + ["6-Drawer Almirah"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Ebony Lumber", + "Ancient Lumber", + "Gold Thread", + "Silk Cloth", + }, + }, + ["9-Drawer Almirah"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Ebony Lumber", + "Ancient Lumber", + "Gold Thread", + "Silk Cloth", + }, + }, + ["Aak'ab Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Mohbwa Cloth", + "Rhodium Ingot", + "Rhodium Ingot", + "Urunday Lumber", + "Umbril Ooze", + }, + }, + ["Aalak' Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Midrium Ingot", + "Urunday Lumber", + }, + }, + ["Abrasion Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mercury", + "Animal Glue", + "Belladonna Sap", + "Acuex Poison", + "Ra'Kaznar Ingot", + }, + }, + ["Abyss Scythe"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Dark Matter", + "Tartarian Chain", + "Cypress Log", + "Moldy Scythe", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Obsidian Crystal", + }, + }, + ["Abyssal Beads"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Waktza Crest", + "Dark Matter", + "Khoma Thread", + "Obsidian Crystal", + "Moldy Necklace", + }, + }, + ["Accelerator"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Coeurl Whisker", + "Goblin Grease", + "Imperial Cermet", + "Myth.Gear Mach.", + "Wind Fan", + }, + }, + ["Accelerator II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Coeurl Whisker", + "Goblin Grease", + "Imperial Cermet", + "Golden Gear", + "Kilo Fan", + }, + }, + ["Accelerator III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Coeurl Whisker", + "Goblin Grease", + "Imperial Cermet", + "Platinum Gear", + "Mega Fan", + }, + }, + ["Accelerator IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Coeurl Whisker", + "Goblin Grease", + "Imperial Cermet", + "Ocl. Gearbox", + "Kilo Fan", + "Mega Fan", + }, + }, + ["Accura Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Velvet Cloth", + "Dahu Hair", + }, + }, + ["Acheron Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Adamantoise Shell", + "Adamantoise Shell", + }, + }, + ["Acid Baselard"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Vitriol", + "Mythril Baselard", + }, + }, + ["Acid Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Acid Bolt Heads", + }, + }, + ["Acid Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Ash Lumber", + "Acid Bolt Heads", + "Acid Bolt Heads", + "Acid Bolt Heads", + "Bundling Twine", + }, + }, + ["Acid Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Animal Glue", + "Vitriol", + }, + }, + ["Acid Claws"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Vitriol", + "Mythril Claws", + }, + }, + ["Acid Dagger"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Vitriol", + "Mythril Dagger", + }, + }, + ["Acid Knife"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Vitriol", + "Mythril Knife", + }, + }, + ["Acid Kukri"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Vitriol", + "Mythril Kukri", + }, + }, + ["Acorn Cookie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Crawler Egg", + "Honey", + "Acorn", + "Acorn", + "Acorn", + "Acorn", + }, + }, + ["Acrobat's Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "G. Bgd. Leather", + "Barbarian's Belt", + }, + }, + ["Adaman Barbuta"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Sheet", + "Adaman Sheet", + "Gold Ingot", + "Sheep Leather", + "Mercury", + }, + }, + ["Adaman Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Adaman Ingot", + }, + }, + ["Adaman Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + }, + }, + ["Adaman Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Mandrel", + }, + }, + ["Adaman Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Adaman Sheet", + "Adaman Sheet", + "Gold Ingot", + "Tiger Leather", + "Tiger Leather", + "Mercury", + }, + }, + ["Adaman Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Adaman Sheet", + "Gold Ingot", + "Tiger Leather", + "Mercury", + }, + }, + ["Adaman Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Adaman Sheet", + "Gold Ingot", + "Mercury", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Adaman Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Adaman Ore", + "Adaman Ore", + "Adaman Ore", + }, + }, + ["Adaman Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ore", + "Adaman Nugget", + "Adaman Nugget", + "Adaman Nugget", + "Adaman Nugget", + "Adaman Nugget", + "Adaman Nugget", + }, + }, + ["Adaman Kilij"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Ebony Lumber", + "Aquamarine", + "Deathstone", + "Marid Leather", + "Scintillant Ingot", + "Scintillant Ingot", + }, + }, + ["Adaman Kris"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Gold Ingot", + "Deathstone", + }, + }, + ["Adaman Sabatons"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Adaman Sheet", + "Gold Ingot", + "Tiger Leather", + "Tiger Leather", + "Mercury", + }, + }, + ["Adaman Sainti"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Adaman Ingot", + "Ebony Lumber", + "Gold Ingot", + "Gold Ingot", + "Mercury", + }, + }, + ["Adaman Scales"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Adaman Sheet", + }, + }, + ["Adaman Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + }, + }, + ["Adaman Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Workshop Anvil", + }, + }, + ["Adamantoise Soup"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Chicken Bone", + "Fiend Blood", + "Rock Salt", + "Wild Onion", + "Distilled Water", + "Tav. Ram Meat", + "Diatryma Meat", + }, + }, + ["Adargas"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Oak Lumber", + "Gold Ingot", + "Rheiyoh Leather", + }, + }, + ["Adder Jambiya"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Viper Potion", + "Khimaira Jambiya", + }, + }, + ["Adoulin Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Adoulinian Kelp", + "Adoulinian Kelp", + "Wild Onion", + "Distilled Water", + "Black Prawn", + }, + }, + ["Aero Mufflers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mtl. Mesh Sheet", + "Mufflers", + }, + }, + ["Aetosaur Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Squamous Hide", + "Raaz Leather", + "Leather Gloves", + }, + }, + ["Aetosaur Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Squamous Hide", + "Squamous Hide", + "Raaz Leather", + }, + }, + ["Aetosaur Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Squamous Hide", + "Squamous Hide", + "Raaz Leather", + "Raaz Leather", + }, + }, + ["Aetosaur Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Squamous Hide", + "Rhodium Sheet", + "Raaz Leather", + "Leather Highboots", + }, + }, + ["Aetosaur Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Squamous Hide", + "Squamous Hide", + "Raaz Leather", + "Leather Trousers", + }, + }, + ["Agility Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Phalaenopsis", + "Dried Mugwort", + "Honey", + "Distilled Water", + }, + }, + ["Ahkormaar Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Grass Cloth", + "Coeurl Whisker", + "Urunday Lumber", + "Urunday Lumber", + "Chapuli Horn", + }, + }, + ["Aht Urhgan Brass Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Aht Urhgan Brass", + "Aht Urhgan Brass", + "Aht Urhgan Brass", + "Aht Urhgan Brass", + }, + }, + ["Aht Urhgan Brass Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "A.U. Brass Ingot", + }, + }, + ["Aht Urhgan Brass Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Workshop Anvil", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + }, + }, + ["Aht Urhgan Dart"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Animal Glue", + "Colibri Feather", + "Colibri Feather", + "Colibri Beak", + }, + }, + ["Aiming Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Water Cell", + "Lam. Wind Cell", + "Studded Gloves", + }, + }, + ["Air Rider"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Firesand", + "Firesand", + "Bast Parchment", + "Goblin Doll", + "Twinkle Powder", + }, + }, + ["Air Solea"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lizard Molt", + "Light Soleas", + }, + }, + ["Airborne"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Cloth", + "Bomb Ash", + "Firesand", + "Firesand", + "Bast Parchment", + "Goblin Doll", + }, + }, + ["Airmid's Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Chain", + "Silver Chain", + "Vivified Coral", + "Vivified Mythril", + }, + }, + ["Aisa"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Tama-Hagane", + "Elm Lumber", + "Thokcha Ingot", + "Behem. Leather", + "Khimaira Mane", + }, + }, + ["Akamochi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Sticky Rice", + "Cornstarch", + "Distilled Water", + "Azuki Bean", + }, + }, + ["Akaso Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Akaso Thread", + "Akaso Thread", + "Akaso Thread", + }, + }, + ["Akaso Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Akaso", + "Akaso", + }, + }, + ["Akaso Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Spindle", + "Akaso", + "Akaso", + "Akaso", + "Akaso", + "Akaso", + "Akaso", + }, + }, + ["Aketon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Silk Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Beetle Blood", + }, + }, + ["Akua Sainti"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Mercury", + "Rhodium Ingot", + "Rhodium Ingot", + "Urunday Lumber", + }, + }, + ["Al Zahbi Sash"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Gold Thread", + "Marid Hair", + "Marid Hair", + "Karakul Thread", + "Wamoura Silk", + }, + }, + ["Alacer Aketon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Gold Thread", + "Gold Thread", + "Silk Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Beetle Blood", + "Radiant Velvet", + }, + }, + ["Alchemist's Tools"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Parchment", + "Glass Sheet", + "Triturator", + "Colibri Feather", + "A.U. Brass Ingot", + "A.U Brass Sheet", + "F. Glass Sheet", + }, + }, + ["Alchemist's Water"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Mercury", + "Dryad Root", + "Beastman Blood", + "Phil. Stone", + }, + }, + ["Alchemy Set 25"] = { + ["crystal"] = "Fluid Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Baselard", + }, + }, + ["Alchemy Set 45"] = { + ["crystal"] = "Bolt Crystal", + ["ingredients"] = { + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + }, + }, + ["Alchemy Set 65"] = { + ["crystal"] = "Fluid Crystal", + ["ingredients"] = { + "Invitriol", + "Acid Baselard", + }, + }, + ["Alchemy Set 70"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Tiger Leather", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Alchemy Set 75"] = { + ["crystal"] = "Fluid Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Darksteel Kukri", + }, + }, + ["Alchemy Set 80"] = { + ["crystal"] = "Fluid Crystal", + ["ingredients"] = { + "Animal Glue", + "Paralyze Potion", + "Cermet Knife", + }, + }, + ["Alchemy Set 85"] = { + ["crystal"] = "Shadow Crystal", + ["ingredients"] = { + "Beastman Blood", + "Revival Root", + "Schlaeger", + }, + }, + ["Alchemy Set 90"] = { + ["crystal"] = "Shadow Crystal", + ["ingredients"] = { + "Beastman Blood", + "Beastman Blood", + "Revival Root", + "Darksteel Lance", + }, + }, + ["Alchemy Set 95"] = { + ["crystal"] = "Fluid Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Sage", + "Sage", + "Dragon Blood", + "Reishi Mushroom", + "Distilled Water", + }, + }, + ["Alluring Cotton Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Thread", + "Cotton Thread", + "Earth Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Altana's Repast"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Holy Water", + "Cursed Beverage", + "Cursed Soup", + "Orc Offering", + "Quadav Offering", + "Yagudo Offering", + "Goblin Offering", + }, + }, + ["Alumine Brayettes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Chain", + "Aluminum Chain", + "Linen Cloth", + "Ram Leather", + "Ram Leather", + }, + }, + ["Alumine Haubert"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Aluminum Sheet", + "Aluminum Ingot", + "Darksteel Chain", + "Darksteel Chain", + "Darksteel Chain", + "Velvet Cloth", + "Silk Cloth", + }, + }, + ["Alumine Moufles"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Aluminum Sheet", + "Chain Mittens", + }, + }, + ["Alumine Salade"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Sheet", + "Aluminum Sheet", + "Darksteel Chain", + "Sheep Leather", + }, + }, + ["Alumine Solerets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Aluminum Sheet", + "Greaves", + }, + }, + ["Aluminum Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Aluminum Ingot", + "Aluminum Ingot", + }, + }, + ["Aluminum Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Mandrel", + }, + }, + ["Aluminum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Aluminum Ore", + "Aluminum Ore", + "Aluminum Ore", + "Aluminum Ore", + }, + }, + ["Aluminum Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Aluminum Ingot", + }, + }, + ["Aluminum Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Workshop Anvil", + }, + }, + ["Aluminum Sheet 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 50", + }, + }, + ["Amaltheia Lth."] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Amaltheia Hide", + "Distilled Water", + }, + }, + ["Amaltheia Lth. 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Amaltheia Hide", + "Distilled Water", + }, + }, + ["Amaltheia Lth. 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Amaltheia Hide", + "Amaltheia Hide", + "Amaltheia Hide", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Amber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yellow Rock", + }, + }, + ["Amber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Soil Geode", + }, + }, + ["Amber Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amber", + "Silver Earring", + }, + }, + ["Amber Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amber", + "Silver Earring +1", + }, + }, + ["Amber Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amber", + "Silver Ring", + }, + }, + ["Amber Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amber", + "Silver Ring +1", + }, + }, + ["Amemet Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Lizard Molt", + "Amemet Skin", + }, + }, + ["Ames"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonbow Urushi", + "Moonbow Stone", + "Ruthenium Ingot", + "Mistilteinn", + }, + }, + ["Amethyst"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Purple Rock", + }, + }, + ["Amethyst 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Thunder Geode", + }, + }, + ["Amethyst Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amethyst", + "Silver Earring", + }, + }, + ["Amethyst Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amethyst", + "Silver Earring +1", + }, + }, + ["Amethyst Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amethyst", + "Silver Ring", + }, + }, + ["Amethyst Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amethyst", + "Silver Ring +1", + }, + }, + ["Ametrine Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ametrine", + "Mythril Earring", + }, + }, + ["Ametrine Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ametrine", + "Mythril Earring +1", + }, + }, + ["Ametrine Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ametrine", + "Mythril Ring", + }, + }, + ["Ametrine Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ametrine", + "Mythril Ring +1", + }, + }, + ["Amiga Cactus"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Red Rock", + "Red Gravel", + "Cactus Arm", + "Karugo Clay", + "Humus", + }, + }, + ["Amigo Cactus"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Yellow Rock", + "Red Gravel", + "Cactus Arm", + "Karugo Clay", + "Humus", + }, + }, + ["Amir Bed"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bldwd. Lumber", + "Gold Thread", + "Gold Brocade", + "Karakul Cloth", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + "A.U. Brass Ingot", + }, + }, + ["Amood"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Gold Ingot", + "Turquoise", + "Scintillant Ingot", + "Scintillant Ingot", + }, + }, + ["Amphiptere Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Amphiptere Hide", + "Distilled Water", + }, + }, + ["Amphiptere Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Amphiptere Hide", + "Distilled Water", + }, + }, + ["Amphiptere Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tanning Vat", + "Amphiptere Hide", + "Amphiptere Hide", + "Amphiptere Hide", + "Distilled Water", + }, + }, + ["Amplifier"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Ice Anima", + "Glass Sheet", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Amplifier II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Ice Anima", + "Plasma Oil", + "F. Glass Sheet", + "F. Glass Sheet", + }, + }, + ["Analyzer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Earth Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Anchovy"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Bay Leaves", + "Olive Oil", + "Rock Salt", + "Icefish", + "Icefish", + "Icefish", + "Icefish", + }, + }, + ["Anchovy 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Bay Leaves", + "Olive Oil", + "Rock Salt", + "Sandfish", + "Sandfish", + "Sandfish", + "Sandfish", + }, + }, + ["Anchovy Pizza"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Holy Basil", + "Pizza Dough", + "Pomodoro Sauce", + "Anchovy", + "Chalaimbille", + }, + }, + ["Anchovy Slice"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Holy Basil", + "Pizza Dough", + "Pomodoro Sauce", + "Anchovy", + "Chalaimbille", + "Pizza Cutter", + }, + }, + ["Ancient Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Petrified Log", + }, + }, + ["Ancient Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Petrified Log", + "Petrified Log", + "Petrified Log", + "Bundling Twine", + }, + }, + ["Anelace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Gold Ingot", + "Cockatrice Skin", + "Mercury", + }, + }, + ["Anelace 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 94", + }, + }, + ["Angel Skin Orb"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Angel Skin", + }, + }, + ["Angel's Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Angelstone", + "Platinum Earring", + }, + }, + ["Angel's Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Angelstone", + "Ptm. Earring +1", + }, + }, + ["Angel's Flute"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Parchment", + }, + }, + ["Angel's Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Angelstone", + "Platinum Ring", + }, + }, + ["Angel's Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Angelstone", + "Platinum Ring +1", + }, + }, + ["Angler Stewpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fish Stock", + "Danceshroom", + "Distilled Water", + "Cotton Tofu", + "Cibol", + "Shungiku", + "Shirataki", + "Orobon Meat", + }, + }, + ["Angon"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Yew Lumber", + "Yew Lumber", + "Yew Lumber", + "Wool Thread", + }, + }, + ["Animal Glue"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rabbit Hide", + "Bone Chip", + "Bone Chip", + "Distilled Water", + }, + }, + ["Animal Glue 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rabbit Hide", + "Rabbit Hide", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Triturator", + "Distilled Water", + }, + }, + ["Animator P"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Divine Lumber", + "Exalted Lumber", + "Exalted Lumber", + "Vulcanite Ore", + "Animator Z", + }, + }, + ["Animator P II"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Divine Lumber", + "Glass Fiber", + "Exalted Lumber", + "Exalted Lumber", + "Vulcanite Ore", + "Animator Z", + }, + }, + ["Antacid"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Maple Sugar", + "Chamomile", + "Dried Mugwort", + "Distilled Water", + }, + }, + ["Antica Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Antican Pauldron", + "Antican Robe", + "Antican Acid", + }, + }, + ["Antica Broth 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Antican Robe", + "Antican Robe", + "Antican Acid", + "Antican Acid", + }, + }, + ["Antidote"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Wijnruit", + "San d'Or. Grape", + "Distilled Water", + }, + }, + ["Antidote 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Wijnruit", + "Wijnruit", + "Wijnruit", + "Triturator", + "San d'Or. Grape", + "San d'Or. Grape", + "San d'Or. Grape", + "Distilled Water", + }, + }, + ["Antlion Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Antlion Jaw", + }, + }, + ["Antlion Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Antlion Jaw", + "Antlion Jaw", + "Antlion Jaw", + "Shagreen File", + }, + }, + ["Antlion Trap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Whisker", + "Animal Glue", + "Antican Pauldron", + "Antican Robe", + "H.Q. Antlion Jaw", + "H.Q. Antlion Jaw", + }, + }, + ["Apaisante"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Thokcha Ingot", + "Thokcha Ingot", + "Buffalo Horn", + }, + }, + ["Apkallu Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Apkallu Feather", + "Apkallu Feather", + }, + }, + ["Apkallu Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Apkallu Feather", + "Apkallu Feather", + "Apkallu Feather", + "Apkallu Feather", + "Apkallu Feather", + "Apkallu Feather", + }, + }, + ["Apple Juice"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Faerie Apple", + "Faerie Apple", + "Faerie Apple", + "Faerie Apple", + }, + }, + ["Apple Juice 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cook. Kit 20", + }, + }, + ["Apple Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Maple Sugar", + "Cinnamon", + "Lizard Egg", + "Faerie Apple", + }, + }, + ["Apple Pie 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Maple Sugar", + "Cinnamon", + "Faerie Apple", + "Bird Egg", + }, + }, + ["Apple Pie 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 50", + }, + }, + ["Apple Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Brass Tank", + "Apple au Lait", + "Apple au Lait", + "Apple au Lait", + "Apple au Lait", + }, + }, + ["Apple Vinegar"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Faerie Apple", + "Faerie Apple", + "Faerie Apple", + "Honey", + }, + }, + ["Apple au Lait"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Faerie Apple", + "Faerie Apple", + "Honey", + "Selbina Milk", + }, + }, + ["Aptitude Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Lizard Molt", + "Raaz Hide", + "Belinda's Hide", + }, + }, + ["Aput Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Akaso Thread", + "Cehuetzi Pelt", + }, + }, + ["Aqua Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Water Bead", + "Orichalcum Ring", + }, + }, + ["Aquamarine"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Scholar Stone", + }, + }, + ["Aquamarine 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Leviatite", + }, + }, + ["Aquamarine Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Aquamarine", + "Gold Ring", + }, + }, + ["Aquamarine Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Aquamarine", + "Gold Ring +1", + }, + }, + ["Aquamrne. Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Aquamarine", + "Gold Earring", + }, + }, + ["Aquamrne. Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Aquamarine", + "Gold Earring +1", + }, + }, + ["Aquan Slayer"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Bird Blood", + "Ameretat Vine", + "Darksteel Kilij", + }, + }, + ["Aqueous Orichalcum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + "Lightning Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Arachne Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Rainbow Thread", + "Silver Thread", + "Gold Thread", + "Arachne Thread", + }, + }, + ["Arachne Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Arachne Web", + "Arachne Web", + }, + }, + ["Arasy Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Ebony Lumber", + "Deathstone", + "Electrum Ingot", + "Bismuth Ingot", + }, + }, + ["Arasy Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Carbon Fiber", + "Glass Fiber", + "Gua. Lumber", + "Akaso Cloth", + }, + }, + ["Arasy Claymore"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Ebony Lumber", + "Wyvern Skin", + "Bismuth Ingot", + }, + }, + ["Arasy Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Adaman Ingot", + "Ebony Lumber", + "Bismuth Ingot", + }, + }, + ["Arasy Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bldwd. Lumber", + "Bismuth Ingot", + }, + }, + ["Arasy Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ruby", + "Rhodium Ingot", + "Gua. Lumber", + }, + }, + ["Arasy Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Electrum Ingot", + "Bismuth Ingot", + }, + }, + ["Arasy Sainti"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Ebony Lumber", + "Bismuth Ingot", + }, + }, + ["Arasy Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Ruby", + "Rhodium Ingot", + "Akaso Cloth", + }, + }, + ["Arasy Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gua. Lumber", + "Raaz Tusk", + }, + }, + ["Arasy Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Wyvern Skin", + "Electrum Ingot", + "Bismuth Ingot", + }, + }, + ["Arasy Tabar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Ebony Lumber", + "Electrum Ingot", + "Bismuth Ingot", + }, + }, + ["Arbalest"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mahogany Lbr.", + "Carbon Fiber", + }, + }, + ["Arcanic Cell"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Carbon Fiber", + "Light Anima", + "Glass Sheet", + "Plasma Oil", + }, + }, + ["Arcanic Cell II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Carbon Fiber", + "Light Anima", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Arcanoclutch"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Ice Bead", + "Homncl. Nerves", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Arcanoclutch II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Ice Bead", + "Homncl. Nerves", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Ardent Jadeite"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Jadeite", + "Fire Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Areion Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Serica Cloth", + "Strider Boots", + }, + }, + ["Argent Coat"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Thread", + "Silk Cloth", + "Eltoro Leather", + "Galateia", + "Baking Soda", + "Platinum Silk", + }, + }, + ["Argent Hose"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Silver Chain", + "Velvet Cloth", + "Velvet Cloth", + "Sheep Leather", + "Sheep Leather", + "Eltoro Leather", + "Baking Soda", + "Platinum Silk", + }, + }, + ["Argute Staff"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Plovid Effluvium", + "Dark Matter", + "Khoma Thread", + "Moldy Staff", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Moonstone Crystal", + }, + }, + ["Argute Stole"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Yggdreant Bole", + "Dark Matter", + "Cypress Log", + "Moonstone Crystal", + "Moldy Stole", + }, + }, + ["Arhat's Gi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Steel Sheet", + "Rainbow Thread", + "Velvet Cloth", + "Silk Cloth", + "Rainbow Cloth", + }, + }, + ["Arhat's Hakama"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Arhat's Jinpachi"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Arhat's Sune-Ate"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Silk Thread", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Arhat's Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Iron Chain", + "Linen Thread", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Arke Corazza"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Gabbrath Horn", + "Tartarian Chain", + "Tartarian Chain", + "Faulpie Leather", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Arke Cosciales"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Gabbrath Horn", + "Tartarian Chain", + "Faulpie Leather", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Arke Gambieras"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Gabbrath Horn", + "Tartarian Chain", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Arke Manopolas"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Gabbrath Horn", + "Tartarian Chain", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Arke Zuchetto"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Gabbrath Horn", + "Tartarian Chain", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Armoire"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Gold Ingot", + }, + }, + ["Armor Plate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Darksteel Sheet", + "Steel Sheet", + "Carbon Fiber", + "Imperial Cermet", + }, + }, + ["Armor Plate II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Steel Sheet", + "Carbon Fiber", + "Imperial Cermet", + }, + }, + ["Armor Plate III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Adaman Sheet", + "Carbon Fiber", + "Drk. Adm. Sheet", + "Imperial Cermet", + }, + }, + ["Armor Plate IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Carbon Fiber", + "Drk. Adm. Sheet", + "Imperial Cermet", + "Titanium Sheet", + }, + }, + ["Armored Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Taurus Horn", + }, + }, + ["Armored Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Taurus Horn", + "Taurus Horn", + "Taurus Horn", + "Shagreen File", + }, + }, + ["Armored Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tgh. Dhal. Lth.", + "Leather Ring", + }, + }, + ["Army Biscuit"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Rye Flour", + "Selbina Butter", + "Rock Salt", + "Simsim", + "Honey", + "Yogurt", + }, + }, + ["Arquebus"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Steel Ingot", + "Mahogany Lbr.", + }, + }, + ["Arrabbiata"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Olive Oil", + "Rock Salt", + "Holy Basil", + "Spaghetti", + "Dragon Meat", + "Pomodoro Sauce", + }, + }, + ["Arrowwood Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Arrowwood Log", + }, + }, + ["Arrowwood Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Arrowwood Log", + "Arrowwood Log", + "Arrowwood Log", + "Bundling Twine", + }, + }, + ["Artificial Lens"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Glass Fiber", + "Glass Fiber", + }, + }, + ["Ash Clogs"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Sheep Leather", + }, + }, + ["Ash Club"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + }, + }, + ["Ash Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Log", + }, + }, + ["Ash Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Log", + "Ash Log", + "Ash Log", + "Bundling Twine", + }, + }, + ["Ash Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + }, + }, + ["Ash Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Bat Fang", + }, + }, + ["Ash Staff 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 10", + }, + }, + ["Ashijiro No Tachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Tama-Hagane", + "Ebony Lumber", + "Rainbow Thread", + "Wyvern Skin", + "Bismuth Ingot", + }, + }, + ["Ashura"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Thread", + "Uchigatana", + }, + }, + ["Ashura 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 75", + }, + }, + ["Aspis"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Bronze Sheet", + "Ash Lumber", + }, + }, + ["Assailant's Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Water Cell", + "Lam. Wind Cell", + "Butterfly Axe", + }, + }, + ["Assassin's Gorget"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Pelt", + "Dark Matter", + "S. Faulpie Leather", + "Peridot Crystal", + "Moldy Gorget", + }, + }, + ["Assassin's Knife"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Horn", + "Dark Matter", + "Ruthenium Ore", + "Moldy Dagger", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Peridot Crystal", + }, + }, + ["Astragalos"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Giant Femur", + "Black Ink", + "Beastman Blood", + }, + }, + ["Athenienne"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Sheet", + "Maple Lumber", + "A.U. Brass Ingot", + }, + }, + ["Atinian Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Belladonna Sap", + "Urunday Lumber", + "Gabbrath Horn", + }, + }, + ["Attacker's Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Molt", + "Wamoura Silk", + "Hahava's Mail", + "Squamous Hide", + }, + }, + ["Augmenting Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Earth Cell", + "Leather Belt", + }, + }, + ["Aumoniere"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Amaryllis", + "Ensang. Cloth", + "Scarlet Ribbon", + }, + }, + ["Aureous Chest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Mahogany Lbr.", + "Gold Ingot", + }, + }, + ["Aurgelmir Orb"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Black Ink", + "Beastman Blood", + "Cyan Coral", + "Cyan Coral", + "Cyan Coral", + "Wyrm Ash", + }, + }, + ["Aurora Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Tiger Hide", + "Tundra Mantle", + }, + }, + ["Auroral Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Distilled Water", + "Aurora Bass", + }, + }, + ["Austere Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Tarasque Skin", + "Yowie Skin", + "Velvet Cuffs", + }, + }, + ["Austere Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Sheep Leather", + "Ram Leather", + "Yowie Skin", + "Velvet Hat", + }, + }, + ["Austere Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Wool Cloth", + "Rainbow Cloth", + "Undead Skin", + "Ram Leather", + "Tarasque Skin", + "Yowie Skin", + "Velvet Robe", + }, + }, + ["Austere Sabots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Sheep Leather", + "Ram Leather", + "Lindwurm Skin", + "Ebony Sabots", + }, + }, + ["Austere Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Undead Skin", + "Wolf Hide", + "Lindwurm Skin", + "Velvet Slops", + }, + }, + ["Auto-Repair Kit"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Glass Fiber", + "Glass Sheet", + "Hi-Potion Tank", + "Kilo Pump", + }, + }, + ["Auto-Repair Kit II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Glass Fiber", + "Glass Sheet", + "Hi-Potion Tank", + "Kilo Pump", + }, + }, + ["Auto-Repair Kit III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Glass Fiber", + "Glass Sheet", + "Hi-Potion Tank", + "Mega Pump", + }, + }, + ["Auto-Repair Kit IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Glass Fiber", + "Glass Sheet", + "Hi-Potion Tank", + "Kilo Pump", + "Mega Pump", + }, + }, + ["Automaton Oil"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Olive Oil", + "Plasma Oil", + "Polyflan Paper", + }, + }, + ["Automaton Oil +1"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Olive Oil", + "Olive Oil", + "Plasma Oil", + "Polyflan Paper", + }, + }, + ["Automaton Oil +2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Olive Oil", + "Olive Oil", + "Olive Oil", + "Plasma Oil", + "Polyflan Paper", + }, + }, + ["Automaton Oil +3"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Olive Oil", + "Olive Oil", + "Olive Oil", + "Olive Oil", + "Plasma Oil", + "Polyflan Paper", + }, + }, + ["Awning"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Elm Lumber", + "Sieglinde Putty", + "Glass Sheet", + }, + }, + ["Ayran"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Rock Salt", + "Distilled Water", + "Yogurt", + }, + }, + ["Azure Cermet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Panacea", + "Azure Leaf", + }, + }, + ["Azure Chest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ore", + "Blue Text. Dye", + "Light Chest", + }, + }, + ["B.E.W. Pitaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Rock Salt", + "Imperial Flour", + "Hard-boiled Egg", + "Distilled Water", + "Buffalo Jerky", + "Chalaimbille", + "Winterflower", + }, + }, + ["Baayami Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Waktza Rostrum", + "Plovid Flesh", + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + }, + }, + ["Baayami Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Waktza Rostrum", + "Plovid Flesh", + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + }, + }, + ["Baayami Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Waktza Rostrum", + "Plovid Flesh", + "Plovid Flesh", + "Khoma Thread", + "Khoma Cloth", + }, + }, + ["Baayami Sabots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Waktza Rostrum", + "Plovid Flesh", + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + }, + }, + ["Baayami Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Waktza Rostrum", + "Plovid Flesh", + "Khoma Thread", + "Khoma Cloth", + }, + }, + ["Baghnakhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Sheet", + }, + }, + ["Bagua Charm"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Claw", + "Dark Matter", + "Cyan Coral", + "Emerald Crystal", + "Moldy Charm", + }, + }, + ["Bagua Wand"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Dark Matter", + "Tartarian Chain", + "Cypress Log", + "Moldy Club", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Emerald Crystal", + }, + }, + ["Bahadur"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Jacaranda Lbr.", + }, + }, + ["Bahut"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + }, + }, + ["Bahut 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 40", + }, + }, + ["Baked Apple"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Maple Sugar", + "Cinnamon", + "Faerie Apple", + }, + }, + ["Baked Popoto"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Popoto", + }, + }, + ["Baking Soda"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Rock Salt", + "Moval. Water", + }, + }, + ["Balder Earring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ruthenium Ingot", + "Ruthenium Ingot", + "Wyrm Ash", + }, + }, + ["Balik Sandvici"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Rock Salt", + "Kitron", + "White Bread", + "Wild Onion", + "Mithran Tomato", + "Uskumru", + }, + }, + ["Balik Sis"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Black Pepper", + "Rock Salt", + "Mithran Tomato", + "Kilicbaligi", + }, + }, + ["Balsam Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tanzanite Jewel", + "Urunday Lumber", + "Rockfin Tooth", + }, + }, + ["Bamboo Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Bamboo Rod", + }, + }, + ["Bamboo Fishing Rod 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Grass Thread", + }, + }, + ["Bamboo Fishing Rod 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 15", + }, + }, + ["Banded Helm"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Sheet", + "Mythril Sheet", + "Mythril Chain", + "Sheep Leather", + }, + }, + ["Banded Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Mythril Chain", + "Mythril Chain", + "Mythril Chain", + "Mythril Chain", + "Linen Cloth", + }, + }, + ["Bandeiras Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Walnut Lumber", + "Midrium Ingot", + "Rhodium Ingot", + }, + }, + ["Bandit's Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Giant Femur", + }, + }, + ["Bannaret Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Chainmail", + }, + }, + ["Banquet Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "B. Table Blueprint", + "B. Table Fabric", + "B. Table Wood", + }, + }, + ["Barbarian's Belt"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Fiend Blood", + "Beastman Blood", + "Leather Belt", + }, + }, + ["Barbarity"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Moonbow Steel", + "Moonbow Leather", + "Faulpie Leather", + "Juggernaut", + }, + }, + ["Barchha"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Ash Lumber", + "Ash Lumber", + "Gold Ingot", + }, + }, + ["Bard's Charm"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Claw", + "Dark Matter", + "Cyan Coral", + "Alexandrite Crystal", + "Moldy Charm", + }, + }, + ["Bard's Knife"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Horn", + "Dark Matter", + "Ruthenium Ore", + "Moldy Dagger", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Alexandrite Crystal", + }, + }, + ["Barnacle"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Carrier Crab Crpc.", + }, + }, + ["Barnacle Paella"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Tarutaru Rice", + "Saffron", + "Wild Onion", + "Distilled Water", + "Mussel", + "Barnacle", + "Barnacle", + }, + }, + ["Barone Corazza"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Mlbd. Sheet", + "Gold Ingot", + "Ocl. Chain", + "Mercury", + "Water Bead", + "Buffalo Leather", + "Scarlet Linen", + }, + }, + ["Barone Cosciales"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Cloth", + "Sarcenet Cloth", + "Buffalo Leather", + "Buffalo Leather", + "H.Q. Bugard Skin", + }, + }, + ["Barone Gambieras"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Ocl. Sheet", + "Gold Ingot", + "Platinum Sheet", + "Mercury", + "Buffalo Leather", + "Buffalo Leather", + }, + }, + ["Barone Manopolas"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Adaman Sheet", + "Gold Ingot", + "Mercury", + "Buffalo Leather", + "Scarlet Linen", + "Scarlet Linen", + }, + }, + ["Barone Zucchetto"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Sheet", + "Ocl. Sheet", + "Gold Ingot", + "Sapphire", + "Sheep Leather", + "Mercury", + }, + }, + ["Barrier Module"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Slime Oil", + "Glass Fiber", + "Mythril Coil", + "Myth.Gear Mach.", + }, + }, + ["Bascinet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Sheet", + "Darksteel Sheet", + "Darksteel Chain", + "Sheep Leather", + }, + }, + ["Baselard"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Steel Ingot", + }, + }, + ["Bass Meuniere"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Saruta Orange", + "Dark Bass", + }, + }, + ["Bast Parchment"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Elm Log", + "Moko Grass", + "Distilled Water", + }, + }, + ["Bastard Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Ram Leather", + }, + }, + ["Bastokan Cap"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Legionnaire's Cap", + }, + }, + ["Bastokan Circlet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Lgn. Circlet", + }, + }, + ["Bastokan Crossbow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Lgn. Crossbow", + }, + }, + ["Bastokan Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Ctr. Cuisses", + }, + }, + ["Bastokan Dagger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Decurion's Dagger", + }, + }, + ["Bastokan Finger Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Ctr. F. Gauntlets", + }, + }, + ["Bastokan Greataxe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Centurion's Axe", + }, + }, + ["Bastokan Greaves"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Ctr. Greaves", + }, + }, + ["Bastokan Hammer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Decurion's Hammer", + }, + }, + ["Bastokan Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Lgn. Harness", + }, + }, + ["Bastokan Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Lgn. Knuckles", + }, + }, + ["Bastokan Leggings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Lgn. Leggings", + }, + }, + ["Bastokan Leggings 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Lgn. Leggings", + }, + }, + ["Bastokan Mittens"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Lgn. Mittens", + }, + }, + ["Bastokan Scale Mail"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Ctr. Scale Mail", + }, + }, + ["Bastokan Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Lgn. Scythe", + }, + }, + ["Bastokan Sill"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Sieglinde Putty", + "Glass Sheet", + }, + }, + ["Bastokan Staff"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Lgn. Staff", + }, + }, + ["Bastokan Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Lgn. Subligar", + }, + }, + ["Bastokan Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Centurion's Sword", + }, + }, + ["Bastokan Targe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Decurion's Shield", + }, + }, + ["Bastokan Tea Set"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Adaman Ingot", + "Silver Ingot", + }, + }, + ["Bastokan Visor"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Centurion's Visor", + }, + }, + ["Batagreen Saute"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Batagreens", + }, + }, + ["Bataquiche"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Black Pepper", + "Rock Salt", + "Danceshroom", + "Selbina Milk", + "Stone Cheese", + "Batagreen Saute", + "Bird Egg", + }, + }, + ["Bathtub"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Angelstone", + "Marble", + "Sieglinde Putty", + "Kaolin", + "Kaolin", + "White Text. Dye", + }, + }, + ["Battery"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Tin Ingot", + "Cermet Chunk", + "Rock Salt", + "Lightning Cluster", + "Distilled Water", + }, + }, + ["Battle Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Scales", + "Ram Leather", + "Ram Leather", + "Tiger Leather", + }, + }, + ["Battle Boots 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 66", + }, + }, + ["Battle Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Chestnut Lumber", + "Silk Cloth", + "Scorpion Claw", + "Coeurl Whisker", + }, + }, + ["Battle Bracers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Velvet Cloth", + "Velvet Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Battle Fork"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Trident", + }, + }, + ["Battle Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Battle Jupon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Battle Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Walnut Lumber", + "Walnut Lumber", + }, + }, + ["Battleaxe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Holly Lumber", + }, + }, + ["Bavarois (Item)"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Maple Sugar", + "Gelatin", + "Apple Mint", + "Vanilla", + "Bird Egg", + "Uleguerand Milk", + }, + }, + ["Bay Aquarium"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Oak Lumber", + "Coral Fragment", + "Sieglinde Putty", + "Glass Sheet", + "Saltwater Set", + "Bibikibo", + "Bibikibo", + "Bibikibo", + }, + }, + ["Beak Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cockatrice Skin", + "Cuir Gloves", + }, + }, + ["Beak Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Sheep Leather", + "Cockatrice Skin", + "Cockatrice Skin", + }, + }, + ["Beak Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Cockatrice Skin", + "Cockatrice Skin", + }, + }, + ["Beak Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Cockatrice Skin", + "Cuir Highboots", + }, + }, + ["Beak Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cockatrice Skin", + "Cockatrice Skin", + }, + }, + ["Beak Necklace"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "H.Q. Crab Shell", + "Oxblood", + "Colibri Beak", + "Colibri Beak", + "Colibri Beak", + "Colibri Beak", + "Mohbwa Thread", + "Wivre Maul", + }, + }, + ["Beak Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cockatrice Skin", + "Cockatrice Skin", + "Cuir Trousers", + }, + }, + ["Bean Daifuku"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blue Peas", + "Maple Sugar", + "Sticky Rice", + "Cornstarch", + "Distilled Water", + "Azuki Bean", + }, + }, + ["Beast Horn"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ram Horn", + "Ram Horn", + }, + }, + ["Beastmaster Collar"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Claw", + "Dark Matter", + "Cyan Coral", + "Topaz Crystal", + "Moldy Collar", + }, + }, + ["Beaugreen Saute"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Beaugreens", + }, + }, + ["Beaugreen Saute 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 55", + }, + }, + ["Bee Spatha"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Beeswax", + "Beeswax", + "Spatha", + }, + }, + ["Beech Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beech Log", + }, + }, + ["Beech Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beech Log", + "Beech Log", + "Beech Log", + "Bundling Twine", + }, + }, + ["Beef Paella"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Tarutaru Rice", + "Saffron", + "Wild Onion", + "Gigant Squid", + "Distilled Water", + "Buffalo Meat", + "Mussel", + }, + }, + ["Beef Stewpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Soy Stock", + "Distilled Water", + "Bird Egg", + "Buffalo Meat", + "Cotton Tofu", + "Cibol", + "Shungiku", + "Shirataki", + }, + }, + ["Beeswax"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beehive Chip", + "Beehive Chip", + "Beehive Chip", + "Distilled Water", + }, + }, + ["Beeswax 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beehive Chip", + "Beehive Chip", + "Beehive Chip", + "Beehive Chip", + "Beehive Chip", + "Beehive Chip", + "Triturator", + "Distilled Water", + }, + }, + ["Beeswax 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Peph. Hive Chip", + "Peph. Hive Chip", + "Distilled Water", + }, + }, + ["Beeswax 4"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Triturator", + "Peph. Hive Chip", + "Peph. Hive Chip", + "Peph. Hive Chip", + "Peph. Hive Chip", + "Distilled Water", + }, + }, + ["Beetle Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Chocobo Fltchg.", + "Beetle Arrowhd.", + }, + }, + ["Beetle Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Beetle Jaw", + }, + }, + ["Beetle Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Beetle Jaw", + "Beetle Jaw", + "Beetle Jaw", + "Shagreen File", + }, + }, + ["Beetle Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Beetle Jaw", + "Silver Earring", + }, + }, + ["Beetle Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Beetle Shell", + "Beetle Jaw", + "Beetle Jaw", + }, + }, + ["Beetle Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Lizard Skin", + "Lizard Skin", + "Beetle Shell", + "Beetle Shell", + }, + }, + ["Beetle Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Beetle Jaw", + }, + }, + ["Beetle Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Lizard Skin", + "Beetle Shell", + "Beetle Jaw", + }, + }, + ["Beetle Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Beetle Jaw", + }, + }, + ["Beetle Mask 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone. Kit 30", + }, + }, + ["Beetle Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Lizard Skin", + "Beetle Shell", + }, + }, + ["Beetle Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beetle Jaw", + }, + }, + ["Beetle Ring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 25", + }, + }, + ["Beetle Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Lizard Skin", + "Beetle Jaw", + }, + }, + ["Behemoth Cesti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Cesti", + }, + }, + ["Behemoth Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Behemoth Horn", + }, + }, + ["Behemoth Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Behemoth Hide", + "Distilled Water", + }, + }, + ["Behemoth Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Behemoth Hide", + "Distilled Water", + }, + }, + ["Behemoth Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Behemoth Hide", + }, + }, + ["Behemoth Mantle 2"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Leath. Kit 70", + }, + }, + ["Behemoth Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Behemoth Horn", + "Behemoth Horn", + }, + }, + ["Behemoth Steak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Popoto", + "Kitron", + "San d'Or. Carrot", + "Behemoth Meat", + }, + }, + ["Beryllium Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Beryllium Ingot", + }, + }, + ["Beryllium Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beryllium Ingot", + }, + }, + ["Beryllium Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Beryllium Ore", + }, + }, + ["Beryllium Kris"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pearl", + "Beryllium Ingot", + "Ra'Kaznar Ingot", + }, + }, + ["Beryllium Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beryllium Ingot", + "Beryllium Ingot", + "Beryllium Ingot", + }, + }, + ["Beryllium Pick"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Urunday Lumber", + "Beryllium Ingot", + }, + }, + ["Beryllium Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Urunday Lumber", + "Raaz Leather", + "Beryllium Ingot", + "Beryllium Ingot", + "Beryllium Ingot", + }, + }, + ["Beryllium Tachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Urunday Lumber", + "Akaso Thread", + "Raaz Leather", + "Beryllium Ingot", + "Beryllium Ingot", + "Ra'Kaznar Ingot", + }, + }, + ["Beverage Barrel"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Water Barrel", + "Oak Lumber", + "Oak Lumber", + "Grape Juice", + "Grape Juice", + "Grape Juice", + }, + }, + ["Bewitched Ash Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Log", + "Fire Anima", + "Ice Anima", + "Light Anima", + }, + }, + ["Bewitched Breeches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "C. Breeches -1", + "Eschite Ore", + }, + }, + ["Bewitched Breeches 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Breeches", + "Warblade's Hide", + "Tartarian Chain", + "Eschite Ore", + }, + }, + ["Bewitched Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Cap -1", + "Eschite Ore", + }, + }, + ["Bewitched Cap 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Cap", + "Maliya. Coral", + "Largantua's Shard", + "Eschite Ore", + }, + }, + ["Bewitched Celata"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Celata -1", + "Eschite Ore", + }, + }, + ["Bewitched Celata 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Celata", + "Warblade's Hide", + "Tartarian Chain", + "Eschite Ore", + }, + }, + ["Bewitched Crown"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Crown -1", + "Eschite Ore", + }, + }, + ["Bewitched Crown 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Crown", + "Hepatizon Ingot", + "Sif's Macrame", + "Eschite Ore", + }, + }, + ["Bewitched Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Cuirass -1", + "Eschite Ore", + }, + }, + ["Bewitched Cuirass 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Cuirass", + "Macuil Plating", + "Douma's Shard", + "Eschite Ore", + }, + }, + ["Bewitched Cuisses"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Cuisses -1", + "Eschite Ore", + }, + }, + ["Bewitched Cuisses 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Cuisses", + "Arthro's Shell", + "Plovid Effluvium", + "Eschite Ore", + }, + }, + ["Bewitched Dalmatica"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "C. Dalmatica -1", + "Eschite Ore", + }, + }, + ["Bewitched Dalmatica 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Dalmatica", + "Hepatizon Ingot", + "Sif's Macrame", + "Eschite Ore", + }, + }, + ["Bewitched Diechlings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "C. Diechlings -1", + "Eschite Ore", + }, + }, + ["Bewitched Diechlings 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Diechlings", + "Macuil Plating", + "Douma's Shard", + "Eschite Ore", + }, + }, + ["Bewitched Finger Gauntlets"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed F. Gnt. -1", + "Eschite Ore", + }, + }, + ["Bewitched Finger Gauntlets 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Fng. Gnt.", + "Arthro's Shell", + "Plovid Effluvium", + "Eschite Ore", + }, + }, + ["Bewitched Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Gloves -1", + "Eschite Ore", + }, + }, + ["Bewitched Gloves 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Gloves", + "Maliya. Coral", + "Immani. Hide", + "Eschite Ore", + }, + }, + ["Bewitched Gold Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ore", + "Gold Ore", + "Gold Ore", + "Gold Ore", + "Fire Anima", + "Ice Anima", + "Light Anima", + }, + }, + ["Bewitched Greaves"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Greaves -1", + "Eschite Ore", + }, + }, + ["Bewitched Greaves 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Greaves", + "Arthro's Shell", + "Plovid Effluvium", + "Eschite Ore", + }, + }, + ["Bewitched Haidate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Haidate -1", + "Eschite Ore", + }, + }, + ["Bewitched Haidate 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Haidate", + "Yggdreant Bole", + "Specter's Ore", + "Eschite Ore", + }, + }, + ["Bewitched Handschuhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "C. Handschuhs -1", + "Eschite Ore", + }, + }, + ["Bewitched Handschuhs 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "C. Handschuhs", + "Macuil Plating", + "Douma's Shard", + "Eschite Ore", + }, + }, + ["Bewitched Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Harness -1", + "Eschite Ore", + }, + }, + ["Bewitched Harness 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Harness", + "Maliya. Coral", + "Immani. Hide", + "Eschite Ore", + }, + }, + ["Bewitched Hauberk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Hauberk -1", + "Eschite Ore", + }, + }, + ["Bewitched Hauberk 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Hauberk", + "Sif's Macrame", + "Tartarian Chain", + "Eschite Ore", + }, + }, + ["Bewitched Kabuto"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Kabuto -1", + "Eschite Ore", + }, + }, + ["Bewitched Kabuto 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Kabuto", + "Yggdreant Bole", + "Specter's Ore", + "Eschite Ore", + }, + }, + ["Bewitched Kote"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cursed Kote -1", + "Eschite Ore", + }, + }, + ["Bewitched Kote 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cursed Kote", + "Yggdreant Bole", + "Specter's Ore", + "Eschite Ore", + }, + }, + ["Bewitched Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "C. Leggings -1", + "Eschite Ore", + }, + }, + ["Bewitched Leggings 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Leggings", + "Maliya. Coral", + "Immani. Hide", + "Eschite Ore", + }, + }, + ["Bewitched Mail"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Mail -1", + "Eschite Ore", + }, + }, + ["Bewitched Mail 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Mail", + "Arthro's Shell", + "Plovid Effluvium", + "Eschite Ore", + }, + }, + ["Bewitched Mask"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Mask -1", + "Eschite Ore", + }, + }, + ["Bewitched Mask 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Cursed Mask", + "Arthro's Shell", + "Plovid Effluvium", + "Eschite Ore", + }, + }, + ["Bewitched Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Mitts -1", + "Eschite Ore", + }, + }, + ["Bewitched Mitts 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Mitts", + "Hepatizon Ingot", + "Sif's Macrame", + "Eschite Ore", + }, + }, + ["Bewitched Mufflers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "C. Mufflers -1", + "Eschite Ore", + }, + }, + ["Bewitched Mufflers 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Mufflers", + "Malatrix's Shard", + "Tartarian Chain", + "Eschite Ore", + }, + }, + ["Bewitched Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Pumps -1", + "Eschite Ore", + }, + }, + ["Bewitched Pumps 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Pumps", + "Sif's Macrame", + "Cehuetzi Pelt", + "Eschite Ore", + }, + }, + ["Bewitched Schaller"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Schaller -1", + "Eschite Ore", + }, + }, + ["Bewitched Schaller 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Schaller", + "Macuil Plating", + "Douma's Shard", + "Eschite Ore", + }, + }, + ["Bewitched Schuhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Schuhs -1", + "Eschite Ore", + }, + }, + ["Bewitched Schuhs 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cursed Schuhs", + "Macuil Plating", + "Douma's Shard", + "Eschite Ore", + }, + }, + ["Bewitched Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Slacks -1", + "Eschite Ore", + }, + }, + ["Bewitched Slacks 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Slacks", + "Hepatizon Ingot", + "Sif's Macrame", + "Eschite Ore", + }, + }, + ["Bewitched Sollerets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "C. Sollerets -1", + "Eschite Ore", + }, + }, + ["Bewitched Sollerets 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Sollerets", + "Malatrix's Shard", + "Tartarian Chain", + "Eschite Ore", + }, + }, + ["Bewitched Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Subligar -1", + "Eschite Ore", + }, + }, + ["Bewitched Subligar 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cursed Subligar", + "Maliya. Coral", + "Immani. Hide", + "Eschite Ore", + }, + }, + ["Bewitched Sune-Ate"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "C. Sune-Ate -1", + "Eschite Ore", + }, + }, + ["Bewitched Sune-Ate 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cursed Sune-Ate", + "Yggdreant Bole", + "Specter's Ore", + "Eschite Ore", + }, + }, + ["Bewitched Togi"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cursed Togi -1", + "Eschite Ore", + }, + }, + ["Bewitched Togi 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cursed Togi", + "Yggdreant Bole", + "Specter's Ore", + "Eschite Ore", + }, + }, + ["Bhakazi Sainti"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gua. Lumber", + "Titanium Ingot", + "Bismuth Ingot", + "Cehuetzi Claw", + "Cehuetzi Claw", + }, + }, + ["Bhuj"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Gold Ingot", + "Mercury", + }, + }, + ["Bihkah Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Peiste Leather", + "Midrium Ingot", + "Midrium Ingot", + }, + }, + ["Bilbo"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Silver Ingot", + }, + }, + ["Bird Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bird Feather", + "Bird Feather", + }, + }, + ["Bird Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Zephyr Thread", + }, + }, + ["Bishop's Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Linen Cloth", + "Priest's Robe", + }, + }, + ["Bismuth Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bismuth Ingot", + }, + }, + ["Bismuth Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tin Ore", + "Zinc Ore", + "Bismuth Ore", + "Bismuth Ore", + }, + }, + ["Bismuth Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bismuth Ingot", + }, + }, + ["Bismuth Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Workshop Anvil", + "Bismuth Ingot", + "Bismuth Ingot", + "Bismuth Ingot", + "Bismuth Ingot", + "Bismuth Ingot", + "Bismuth Ingot", + }, + }, + ["Bison Gamashes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Manticore Hair", + "Manticore Hair", + "Hippogryph Fthr.", + "Buffalo Leather", + "Buffalo Leather", + }, + }, + ["Bison Jacket"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Manticore Lth.", + "Manticore Hair", + "Manticore Hair", + "Buffalo Horn", + "Eft Skin", + "Buffalo Leather", + "Buffalo Leather", + }, + }, + ["Bison Kecks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Manticore Lth.", + "Manticore Hair", + "Manticore Hair", + "Manticore Hair", + "Manticore Hair", + "Buffalo Leather", + "Buffalo Leather", + }, + }, + ["Bison Steak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bay Leaves", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Rarab Tail", + "Buffalo Meat", + }, + }, + ["Bison Warbonnet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Manticore Hair", + "Manticore Hair", + "Hippogryph Fthr.", + "Hippogryph Fthr.", + "Eft Skin", + "Buffalo Leather", + }, + }, + ["Bison Wristbands"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Manticore Lth.", + "Manticore Hair", + "Manticore Hair", + "Buffalo Leather", + }, + }, + ["Bittern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Salinator", + "Distilled Water", + }, + }, + ["Black Adargas"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Oak Lumber", + "Gold Ingot", + "Ovinnik Leather", + }, + }, + ["Black Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Teak Lumber", + "Blk. Bolt Heads", + }, + }, + ["Black Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bundling Twine", + "Teak Lumber", + "Teak Lumber", + "Teak Lumber", + "Blk. Bolt Heads", + "Blk. Bolt Heads", + "Blk. Bolt Heads", + }, + }, + ["Black Bolt 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 35", + }, + }, + ["Black Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Obsidian", + }, + }, + ["Black Bread"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rye Flour", + "Rock Salt", + "Distilled Water", + }, + }, + ["Black Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Velvet Cloth", + }, + }, + ["Black Chocobo Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Black C. Feather", + "Black C. Feather", + }, + }, + ["Black Chocobo Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Black C. Feather", + "Black C. Feather", + "Black C. Feather", + "Black C. Feather", + "Black C. Feather", + "Black C. Feather", + "Zephyr Thread", + }, + }, + ["Black Cloak"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Gold Thread", + "Silk Cloth", + "Silk Cloth", + "Rainbow Cloth", + "Raxa", + "Raxa", + "Raxa", + }, + }, + ["Black Cotehardie"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Malboro Fiber", + "Ram Leather", + "Tiger Leather", + "Mistletoe", + "Fiend Blood", + "Black Ink", + "Velvet Robe", + "Beak Jerkin", + }, + }, + ["Black Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Tiger Leather", + "Tiger Leather", + "Kunwu Sheet", + }, + }, + ["Black Curry"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Curry Powder", + "Woozyshroom", + "Eggplant", + "Distilled Water", + "Lakerda", + "Ahtapot", + }, + }, + ["Black Curry 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Curry Powder", + "Nebimonite", + "Woozyshroom", + "Eggplant", + "Gugru Tuna", + "Distilled Water", + }, + }, + ["Black Curry Bun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Olive Oil", + "Black Curry", + "Bird Egg", + }, + }, + ["Black Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Black Pearl", + "Mythril Earring", + }, + }, + ["Black Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Black Pearl", + "Mythril Earring +1", + }, + }, + ["Black Gadlings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Kunwu Sheet", + "Tiger Gloves", + }, + }, + ["Black Hobby Bo"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Hickory Lumber", + "Dogwd. Lumber", + "Onyx", + "Onyx", + "Blk. Chocobo Dye", + }, + }, + ["Black Ink"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Nebimonite", + "Distilled Water", + }, + }, + ["Black Ink 10"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Gigant Squid", + "Distilled Water", + }, + }, + ["Black Ink 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Nebimonite", + "Distilled Water", + }, + }, + ["Black Ink 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Distilled Water", + "Cone Calamary", + "Cone Calamary", + }, + }, + ["Black Ink 4"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Distilled Water", + "Cone Calamary", + "Cone Calamary", + }, + }, + ["Black Ink 5"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Im. Tea Leaves", + "Distilled Water", + "Kalamar", + "Kalamar", + }, + }, + ["Black Ink 6"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Distilled Water", + "Kalamar", + "Kalamar", + }, + }, + ["Black Ink 7"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Grimmonite", + "Distilled Water", + }, + }, + ["Black Ink 8"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Im. Tea Leaves", + "Im. Tea Leaves", + "Distilled Water", + "Ahtapot", + }, + }, + ["Black Ink 9"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Alch. Kit 5", + }, + }, + ["Black Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Tiger Leather", + "Tiger Mantle", + }, + }, + ["Black Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Linen Cloth", + "Velvet Cloth", + "Saruta Cotton", + }, + }, + ["Black Mitts 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 60", + }, + }, + ["Black Pudding"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Cinnamon", + "Kitron", + "Saruta Orange", + "Buburimu Grape", + "Bird Egg", + "Royal Grape", + }, + }, + ["Black Puppet Turban"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Cotton Cloth", + "Velvet Cloth", + }, + }, + ["Black Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Black Pearl", + "Mythril Ring", + }, + }, + ["Black Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Black Pearl", + "Mythril Ring +1", + }, + }, + ["Black Sallet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Sheet", + "Ocl. Ingot", + "Sheep Leather", + "Kunwu Sheet", + }, + }, + ["Black Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Linen Cloth", + "Linen Cloth", + "Velvet Cloth", + }, + }, + ["Black Sollerets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Kunwu Sheet", + "Tiger Ledelsens", + }, + }, + ["Black Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + }, + }, + ["Blackened Frog"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Rock Salt", + "Copper Frog", + }, + }, + ["Blackened Frog 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Rock Salt", + "Senroh Frog", + }, + }, + ["Blackened Newt"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Bay Leaves", + "Rock Salt", + "Elshimo Newt", + }, + }, + ["Blackened Newt 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Bay Leaves", + "Rock Salt", + "Phanauet Newt", + }, + }, + ["Blaze Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Incomb. Wool", + "Wool Hose", + }, + }, + ["Blenmot's Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oxblood", + "Vivified Coral", + "Holy Water", + "Holy Water", + "Hallowed Water", + }, + }, + ["Blessed Bliaut"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Rainbow Cloth", + "Galateia", + "Galateia", + }, + }, + ["Blessed Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Saruta Cotton", + "Galateia", + }, + }, + ["Blessed Mythril Sheet"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Holy Water", + }, + }, + ["Blessed Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Tiger Leather", + "Manticore Hair", + "Eltoro Leather", + }, + }, + ["Blessed Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Rainbow Cloth", + "Galateia", + }, + }, + ["Blind Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Bln. Bolt Heads", + }, + }, + ["Blind Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Ash Lumber", + "Bln. Bolt Heads", + "Bln. Bolt Heads", + "Bln. Bolt Heads", + "Bundling Twine", + }, + }, + ["Blind Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Animal Glue", + "Blinding Potion", + }, + }, + ["Blind Dagger"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Blinding Potion", + "Bronze Dagger", + }, + }, + ["Blind Knife"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Blinding Potion", + "Bronze Knife", + }, + }, + ["Blinding Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Crying Mustard", + "Poison Flour", + "Sleepshroom", + }, + }, + ["Blinding Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Crying Mustard", + "Crying Mustard", + "Poison Flour", + "Poison Flour", + "Triturator", + "Sleepshroom", + "Sleepshroom", + }, + }, + ["Blinding Potion 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Mercury", + "Nebimonite", + }, + }, + ["Blink Band"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fine Linen Cloth", + "Flax Headband", + }, + }, + ["Blissful Chapeau"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Water Cell", + "Lam. Earth Cell", + "Trader's Chapeau", + }, + }, + ["Blizzard Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Frigid Skin", + "Raptor Gloves", + }, + }, + ["Blizzard Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Frgd. Orichalcum", + "Orichalcum Scythe", + }, + }, + ["Blood Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Fiend Blood", + "Leech Saliva", + "Lizard Blood", + "Bird Blood", + "Beast Blood", + }, + }, + ["Blood Broth 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Beastman Blood", + "Leech Saliva", + "Lizard Blood", + "Bird Blood", + "Beast Blood", + }, + }, + ["Blood Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Garnet", + "Mythril Earring", + }, + }, + ["Blood Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Garnet", + "Mythril Earring +1", + }, + }, + ["Blood Stone"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Grass Thread", + "Giant Femur", + "Fiend Blood", + }, + }, + ["Bloodwood Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bloodwood Log", + }, + }, + ["Bloodwood Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bloodwood Log", + "Bloodwood Log", + "Bloodwood Log", + "Bundling Twine", + }, + }, + ["Bloody Aketon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Gold Thread", + "Gold Thread", + "Silk Cloth", + "Rainbow Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Dragon Blood", + }, + }, + ["Bloody Blade"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Beastman Blood", + "Revival Root", + "Darksteel Falchion", + }, + }, + ["Bloody Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Bld. Bolt Heads", + }, + }, + ["Bloody Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Ash Lumber", + "Bld. Bolt Heads", + "Bld. Bolt Heads", + "Bld. Bolt Heads", + "Bundling Twine", + }, + }, + ["Bloody Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Beastman Blood", + "Revival Root", + }, + }, + ["Bloody Chocolate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Kukuru Bean", + "Kukuru Bean", + "Kukuru Bean", + "Kukuru Bean", + "Flytrap Leaf", + "Selbina Milk", + }, + }, + ["Bloody Lance"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Beastman Blood", + "Beastman Blood", + "Revival Root", + "Darksteel Lance", + }, + }, + ["Bloody Lance 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Alch. Kit 90", + }, + }, + ["Bloody Ram Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Ram Skin", + "Earth Anima", + "Lightning Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Bloody Ram Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Ram Skin", + "Earth Anima", + "Lightning Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Bloody Rapier"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Beastman Blood", + "Revival Root", + "Schlaeger", + }, + }, + ["Bloody Rapier 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Alch. Kit 85", + }, + }, + ["Bloody Sword"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Beastman Blood", + "Revival Root", + "Bastard Sword", + }, + }, + ["Blue 3-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "3-Drawer Almirah", + "Gold Thread", + "Blue Text. Dye", + }, + }, + ["Blue 6-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "6-Drawer Almirah", + "Gold Thread", + "Blue Text. Dye", + }, + }, + ["Blue 9-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "9-Drawer Almirah", + "Gold Thread", + "Blue Text. Dye", + }, + }, + ["Blue Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Cloth", + "Silk Cloth", + "Beetle Blood", + }, + }, + ["Blue Cotehardie"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Malboro Fiber", + "Ram Leather", + "Tiger Leather", + "Mistletoe", + "Fiend Blood", + "Beetle Blood", + "Velvet Robe", + "Beak Jerkin", + }, + }, + ["Blue Hobby Bo"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Hickory Lumber", + "Dogwd. Lumber", + "Onyx", + "Onyx", + "Blue Chocobo Dye", + }, + }, + ["Blue Mahogany Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mahogany Bed", + "Wool Thread", + "Blue Text. Dye", + }, + }, + ["Blue Noble's Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Noble's Bed", + "Gold Thread", + "Blue Text. Dye", + }, + }, + ["Blue Round Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Linen Cloth", + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Platinum Silk", + "Teak Lumber", + "Blue Text. Dye", + }, + }, + ["Blue Storm Lantern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Brass Ingot", + "Silver Ingot", + "Silk Cloth", + "Glass Sheet", + "Sailcloth", + "Blue Text. Dye", + }, + }, + ["Blue Tarutaru Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Tarutaru Desk", + "Blue Text. Dye", + }, + }, + ["Blue Tarutaru Standing Screen"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Taru F. Screen", + "Blue Text. Dye", + }, + }, + ["Blue Textile Dye"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dyer's Woad", + }, + }, + ["Blue Viola"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Blue Rock", + "Granite", + "Red Gravel", + "Wildgrass Seeds", + "Humus", + }, + }, + ["Blunderbuss"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Steel Ingot", + "Elm Lumber", + "Silver Ingot", + }, + }, + ["Blurred Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Tabarzin", + }, + }, + ["Blurred Bow"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Amazon Bow", + }, + }, + ["Blurred Claws"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Dragon Claws", + }, + }, + ["Blurred Claymore"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Nagan", + }, + }, + ["Blurred Cleaver"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Toporok", + }, + }, + ["Blurred Crossbow"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Rpt. Crossbow", + }, + }, + ["Blurred Harp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Cythara Anglica", + }, + }, + ["Blurred Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Misericorde", + }, + }, + ["Blurred Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Dabo", + }, + }, + ["Blurred Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Scepter", + }, + }, + ["Blurred Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Death Scythe", + }, + }, + ["Blurred Shield"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Koenig Shield", + }, + }, + ["Blurred Staff"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Mythic Pole", + }, + }, + ["Blurred Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Adaman Kilij", + }, + }, + ["Blutkrallen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Bldwd. Lumber", + "Linen Thread", + "Scintillant Ingot", + "Meeble Claw", + "Meeble Claw", + "Meeble Claw", + }, + }, + ["Bodkin Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Blk. Chc. Fltchg.", + "Arm. Arrowhd.", + }, + }, + ["Boiled Barnacles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Distilled Water", + "Barnacle", + }, + }, + ["Boiled Cockatrice"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Ginger", + "Rock Salt", + "San d'Or. Carrot", + "Mithran Tomato", + "Cockatrice Meat", + "Coral Fungus", + "Distilled Water", + }, + }, + ["Boiled Crab"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bay Leaves", + "Rock Salt", + "Land Crab Meat", + "Distilled Water", + }, + }, + ["Boiled Crayfish"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Crayfish", + "Distilled Water", + }, + }, + ["Boiled Tuna Head"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ginger", + "Maple Sugar", + "Rock Salt", + "Treant Bulb", + "Grape Juice", + "Gugru Tuna", + "Distilled Water", + "Beaugreens", + }, + }, + ["Bokuto"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Blinding Potion", + "Shinobi-Gatana", + }, + }, + ["Bolt Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Sheep Leather", + "Brz. Bolt Heads", + "Brz. Bolt Heads", + "Leather Pouch", + }, + }, + ["Bone Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Bone Arrowhd.", + "Yagudo Fltchg.", + }, + }, + ["Bone Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + }, + }, + ["Bone Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Shagreen File", + }, + }, + ["Bone Arrowheads 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 10", + }, + }, + ["Bone Axe"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Giant Femur", + "Ram Horn", + "Ram Horn", + }, + }, + ["Bone Axe 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 20", + }, + }, + ["Bone Cudgel"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Grass Cloth", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Giant Femur", + }, + }, + ["Bone Cudgel 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 40", + }, + }, + ["Bone Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bone Chip", + "Bone Chip", + }, + }, + ["Bone Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + }, + }, + ["Bone Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Sheep Leather", + "Pugil Scales", + "Bone Chip", + "Giant Femur", + }, + }, + ["Bone Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Giant Femur", + }, + }, + ["Bone Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Sheep Leather", + "Bone Chip", + "Giant Femur", + }, + }, + ["Bone Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Bone Chip", + "Giant Femur", + }, + }, + ["Bone Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Sheep Leather", + "Bone Chip", + "Bone Chip", + }, + }, + ["Bone Patas"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Crab Shell", + "Giant Femur", + "Giant Femur", + "Carbon Fiber", + }, + }, + ["Bone Pick"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Giant Femur", + }, + }, + ["Bone Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Sheep Tooth", + }, + }, + ["Bone Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Giant Femur", + "Ram Horn", + "Ram Horn", + }, + }, + ["Bone Rod 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bone. Kit 50", + }, + }, + ["Bone Scythe"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Lumber", + "Grass Cloth", + "Sheep Tooth", + "Giant Femur", + "Giant Femur", + }, + }, + ["Bone Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Cloth", + "Sheep Leather", + "Sheep Leather", + "Bone Chip", + }, + }, + ["Bonecraft Set 25"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Beetle Jaw", + }, + }, + ["Bonecraft Set 45"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Crab Shell", + }, + }, + ["Bonecraft Set 65"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Ladybug Wing", + "Ladybug Wing", + }, + }, + ["Bonecraft Set 70"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Fish Scales", + "Demon Horn", + }, + }, + ["Bonecraft Set 75"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Ladybug Wing", + "Electrum Chain", + }, + }, + ["Bonecraft Set 80"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Coral Fragment", + "Coral Fragment", + }, + }, + ["Bonecraft Set 85"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Imp Horn", + "Colibri Beak", + }, + }, + ["Bonecraft Set 90"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Beetle Jaw", + "Dragon Talon", + "Dragon Talon", + }, + }, + ["Bonecraft Set 95"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ram Leather", + "Ram Leather", + "H.Q. Crab Shell", + "H.Q. Crab Shell", + "H.Q. Crab Shell", + "H.Q. Crab Shell", + }, + }, + ["Bonfire"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beech Lumber", + "Beech Lumber", + "Firesand", + "Teak Lumber", + }, + }, + ["Bongo Drum"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Dhalmel Hide", + "Buffalo Leather", + }, + }, + ["Book Holder"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Holly Lumber", + }, + }, + ["Bookshelf"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Tufa", + "Tufa", + "Tufa", + }, + }, + ["Bookstack"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Marble", + "Marble", + "Marble", + }, + }, + ["Boomerang"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Lumber", + "Cotton Thread", + }, + }, + ["Boscaiola"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Olive Oil", + "Spaghetti", + "Danceshroom", + "King Truffle", + "Wild Onion", + "Scream Fungus", + "Pomodoro Sauce", + }, + }, + ["Bracers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Bracers 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 25", + }, + }, + ["Brain Stew"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Crying Mustard", + "Apple Vinegar", + "Gelatin", + "Honey", + "King Truffle", + "Yellow Globe", + "Distilled Water", + }, + }, + ["Brais"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + "Sheep Leather", + }, + }, + ["Brass Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Axe", + }, + }, + ["Brass Baghnakhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Cat Baghnakhs", + }, + }, + ["Brass Cap"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Cap", + }, + }, + ["Brass Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Ingot", + }, + }, + ["Brass Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Workshop Anvil", + }, + }, + ["Brass Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Brass Scales", + "Cotton Thread", + "Dhalmel Leather", + "Leather Trousers", + }, + }, + ["Brass Dagger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Dagger", + }, + }, + ["Brass Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Brass Scales", + "Cotton Thread", + "Dhalmel Leather", + "Leather Gloves", + }, + }, + ["Brass Finger Gauntlets 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold. Kit 30", + }, + }, + ["Brass Flowerpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Sheet", + "Brass Sheet", + "Brass Sheet", + }, + }, + ["Brass Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Brass Scales", + "Cotton Thread", + "Dhalmel Leather", + "Leather Highboots", + }, + }, + ["Brass Grip"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Ingot", + "Mandrel", + }, + }, + ["Brass Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Brass Ingot", + }, + }, + ["Brass Hammer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Hammer", + }, + }, + ["Brass Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Sheet", + "Bronze Harness", + }, + }, + ["Brass Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ore", + "Copper Ore", + "Copper Ore", + "Zinc Ore", + }, + }, + ["Brass Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Zinc Ore", + "Brass Nugget", + "Brass Nugget", + "Brass Nugget", + "Brass Nugget", + "Brass Nugget", + "Brass Nugget", + }, + }, + ["Brass Ingot 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 10", + }, + }, + ["Brass Jadagna"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Karakul Leather", + "A.U. Brass Ingot", + "Jadagna", + }, + }, + ["Brass Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Knuckles", + }, + }, + ["Brass Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Leggings", + }, + }, + ["Brass Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Dhalmel Leather", + "Faceguard", + }, + }, + ["Brass Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Mittens", + }, + }, + ["Brass Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Ingot", + }, + }, + ["Brass Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Rod", + }, + }, + ["Brass Scale Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Brass Scales", + "Brass Scales", + "Brass Scales", + "Cotton Thread", + "Dhalmel Leather", + "Leather Vest", + }, + }, + ["Brass Scales"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Brass Sheet", + }, + }, + ["Brass Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + }, + }, + ["Brass Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Workshop Anvil", + }, + }, + ["Brass Spear"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Brass Ingot", + "Ash Lumber", + "Linen Thread", + }, + }, + ["Brass Subligar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Subligar", + }, + }, + ["Brass Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Brass Sheet", + "Brass Sheet", + "Animal Glue", + }, + }, + ["Brass Xiphos"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Xiphos", + }, + }, + ["Brass Zaghnal"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bronze Zaghnal", + }, + }, + ["Brass Zaghnal 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 15", + }, + }, + ["Bread Crock"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Jadeite", + "Grass Thread", + "Grass Thread", + "Kaolin", + "Kaolin", + }, + }, + ["Bream Risotto"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Selbina Butter", + "Tarutaru Rice", + "Black Pepper", + "Olive Oil", + "Sage", + "Bastore Bream", + "Distilled Water", + }, + }, + ["Bream Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Ground Wasabi", + "Mercanbaligi", + }, + }, + ["Bream Sushi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Bastore Bream", + "Distilled Water", + "Ground Wasabi", + }, + }, + ["Breastplate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Iron Sheet", + "Iron Sheet", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Breath Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Fr. Dhalmel Hide", + "Dhalmel Mantle", + }, + }, + ["Breeches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Chain", + "Mythril Chain", + "Linen Cloth", + "Ram Leather", + "Ram Leather", + }, + }, + ["Breeze Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wind Bead", + "Orichalcum Ring", + }, + }, + ["Breidox"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Thokcha Ingot", + "Thokcha Ingot", + "Dark Adaman", + }, + }, + ["Bretzel"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Rock Salt", + "Lizard Egg", + "Distilled Water", + }, + }, + ["Bretzel 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Rock Salt", + "Distilled Water", + "Bird Egg", + }, + }, + ["Brigandine"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Brass Scales", + "Gold Sheet", + "Velvet Cloth", + "Velvet Cloth", + "Ram Leather", + "Lizard Jerkin", + }, + }, + ["Brigandine 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Iron Chain", + "Wool Thread", + "Linen Cloth", + "Velvet Cloth", + "Sheep Leather", + "Tiger Leather", + }, + }, + ["Brilliant Gold Thread"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Silk Thread", + "Water Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Brilliant Snow"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Sheep Leather", + "Glass Fiber", + "Rock Salt", + "Holy Water", + "Distilled Water", + }, + }, + ["Brimsand"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bomb Ash", + "Bomb Ash", + "Sulfur", + "Fire Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Brimsand 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sulfur", + "Cluster Ash", + "Fire Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Briny Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Rhinochimera", + "Hamsi", + "Mercanbaligi", + }, + }, + ["Brioso Whistle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Thought Crystal", + "Cyan Coral", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Brioso Whistle 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Hope Crystal", + "Cyan Coral", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Brioso Whistle 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fulfillment Crystal", + "Cyan Coral", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Brise-os"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Karakul Leather", + "Sahagin Gold", + "Jadagna", + }, + }, + ["Brisingamen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Chain", + "Platinum Chain", + "Platinum Chain", + "Freya's Tear", + "Jeweled Collar", + }, + }, + ["Broach Lance"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Obelisk Lance", + }, + }, + ["Broadsword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Lizard Skin", + }, + }, + ["Brocade Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Silver Thread", + "Silver Thread", + "Gold Thread", + "Gold Thread", + }, + }, + ["Brocade Obi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 80", + }, + }, + ["Bronze Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Ash Lumber", + }, + }, + ["Bronze Bed"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Grass Thread", + "Cotton Cloth", + "Cotton Cloth", + "Saruta Cotton", + }, + }, + ["Bronze Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Brz. Bolt Heads", + }, + }, + ["Bronze Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Ash Lumber", + "Brz. Bolt Heads", + "Brz. Bolt Heads", + "Brz. Bolt Heads", + "Bundling Twine", + }, + }, + ["Bronze Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + }, + }, + ["Bronze Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Firesand", + }, + }, + ["Bronze Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Bronze Dagger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Bronze Ingot", + }, + }, + ["Bronze Hammer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Chestnut Lumber", + }, + }, + ["Bronze Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Bronze Sheet", + "Bronze Sheet", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Bronze Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beastcoin", + "Beastcoin", + "Beastcoin", + "Beastcoin", + }, + }, + ["Bronze Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ore", + "Copper Ore", + "Copper Ore", + "Tin Ore", + }, + }, + ["Bronze Ingot 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tin Ore", + "Bronze Nugget", + "Bronze Nugget", + "Bronze Nugget", + "Bronze Nugget", + "Bronze Nugget", + "Bronze Nugget", + }, + }, + ["Bronze Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Ash Lumber", + }, + }, + ["Bronze Knife 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 5", + }, + }, + ["Bronze Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Sheet", + "Bronze Sheet", + "Ash Lumber", + }, + }, + ["Bronze Leggings"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rusty Leggings", + }, + }, + ["Bronze Leggings 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Bronze Sheet", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Bronze Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + }, + }, + ["Bronze Mace 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 10", + }, + }, + ["Bronze Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Sheep Leather", + }, + }, + ["Bronze Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Bronze Ingot", + "Bronze Ingot", + }, + }, + ["Bronze Rose"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Im. Wootz Ingot", + "Drk. Adm. Sheet", + "Tr. Brz. Sheet", + "A.U. Brass Ingot", + }, + }, + ["Bronze Scales"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Sheet", + }, + }, + ["Bronze Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + }, + }, + ["Bronze Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Workshop Anvil", + }, + }, + ["Bronze Spear"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Ash Lumber", + "Grass Thread", + }, + }, + ["Bronze Subligar"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rusty Subligar", + }, + }, + ["Bronze Subligar 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Grass Cloth", + "Sheep Leather", + }, + }, + ["Bronze Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Sheep Leather", + }, + }, + ["Bronze Zaghnal"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Ash Lumber", + "Grass Cloth", + }, + }, + ["Bubble Chocolate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Kukuru Bean", + "Kukuru Bean", + "Kukuru Bean", + "Kukuru Bean", + "Selbina Milk", + }, + }, + ["Bubbling Carrion Broth"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Gelatin", + "Hare Meat", + "Distilled Water", + "Rotten Meat", + }, + }, + ["Buche au Chocolat"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Bay Leaves", + "Maple Sugar", + "Kukuru Bean", + "Selbina Milk", + "Bbl. Chocolate", + "Bird Egg", + }, + }, + ["Buckler"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Targe", + }, + }, + ["Buckler Plaque"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Silver Sheet", + "Mahogany Lbr.", + "Platinum Ingot", + "Platinum Sheet", + "Fluorite", + "Fluorite", + "Rainbow Velvet", + }, + }, + ["Budliqa"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Waktza Rostrum", + "Gua. Lumber", + "Bismuth Ingot", + }, + }, + ["Buffalo Jerky"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Rock Salt", + "Buffalo Meat", + }, + }, + ["Buffalo Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Buffalo Hide", + "Distilled Water", + }, + }, + ["Buffalo Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Buffalo Hide", + "Distilled Water", + }, + }, + ["Buffalo Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Buffalo Hide", + "Buffalo Hide", + "Buffalo Hide", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Buffoon's Collar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Karakul Cloth", + }, + }, + ["Bug Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Lugworm", + "Lugworm", + "Shell Bug", + "Shell Bug", + }, + }, + ["Bugard Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Bugard Skin", + "Distilled Water", + }, + }, + ["Bugard Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Bugard Skin", + "Bugard Skin", + "Bugard Skin", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Bugard Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Bugard Skin", + "Distilled Water", + }, + }, + ["Bugard Strap"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bugard Leather", + "Bugard Leather", + }, + }, + ["Bulky Coffer"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ore", + "Light Chest", + }, + }, + ["Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Firesand", + }, + }, + ["Bureau"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + }, + }, + ["Burning Carrion Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Hare Meat", + "G. Sheep Meat", + "Ruszor Meat", + }, + }, + ["Busuto"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Shinobi-Gatana", + }, + }, + ["Butachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Darksteel Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Tama-Hagane", + "Ancient Lumber", + "Cotton Thread", + "Manta Leather", + }, + }, + ["Butter Crepe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Bird Egg", + "Uleguerand Milk", + }, + }, + ["Butterfly Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Iron Ingot", + "Maple Lumber", + }, + }, + ["Butterfly Cage"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Rattan Lumber", + "Rattan Lumber", + "Dogwd. Lumber", + "White Butterfly", + }, + }, + ["Butznar Shield"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Urunday Lumber", + "Midrium Sheet", + "Midrium Sheet", + }, + }, + ["Buzbaz Sainti"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Light Steel", + "Light Steel", + "Ruszor Fang", + "Ruszor Fang", + }, + }, + ["Buzdygan"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Gold Ingot", + "Mercury", + }, + }, + ["Byrnie"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Dhalmel Leather", + "Ram Leather", + "Tiger Leather", + "Behem. Leather", + "Silver Mail", + }, + }, + ["Cabinet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Holly Lumber", + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + }, + }, + ["Cabinet 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 81", + }, + }, + ["Caisson"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Bronze Sheet", + "Chestnut Lumber", + "Chestnut Lumber", + }, + }, + ["Caliginous Wolf Hide"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wolf Hide", + "Earth Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Candelabrum"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Beeswax", + "Beeswax", + "Beeswax", + }, + }, + ["Candle Holder"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Ingot", + "Brass Ingot", + "Gold Ingot", + "Beeswax", + }, + }, + ["Cannon Shell"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Iron Ingot", + "Firesand", + "Firesand", + "Bomb Arm", + }, + }, + ["Cantarella"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Mercury", + "Venom Dust", + "Paralysis Dust", + "Fresh Orc Liver", + "Distilled Water", + }, + }, + ["Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + }, + }, + ["Carapace Breastplate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ram Leather", + "Ram Leather", + "H.Q. Crab Shell", + "H.Q. Crab Shell", + "H.Q. Crab Shell", + "H.Q. Crab Shell", + }, + }, + ["Carapace Breastplate 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone. Kit 95", + }, + }, + ["Carapace Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "H.Q. Crab Shell", + "H.Q. Crab Shell", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Carapace Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Crab Shell", + "Crab Shell", + }, + }, + ["Carapace Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Dhalmel Leather", + "Crab Shell", + "Crab Shell", + }, + }, + ["Carapace Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Sheep Leather", + "Ram Leather", + "H.Q. Crab Shell", + "H.Q. Crab Shell", + }, + }, + ["Carapace Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Dhalmel Leather", + "Fish Scales", + "Crab Shell", + }, + }, + ["Carapace Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Crab Shell", + }, + }, + ["Carapace Mask 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone. Kit 45", + }, + }, + ["Carapace Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Fish Scales", + "Crab Shell", + }, + }, + ["Carapace Powder"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beetle Shell", + "Beetle Shell", + }, + }, + ["Carapace Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Crab Shell", + }, + }, + ["Carapace Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Dhalmel Leather", + "Crab Shell", + }, + }, + ["Carbon Dioxide"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Trumpet Shell", + }, + }, + ["Carbon Fiber"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + }, + }, + ["Carbon Fiber 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Alch. Kit 45", + }, + }, + ["Carbon Fiber 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Bomb Ash", + "Cluster Ash", + }, + }, + ["Carbon Fiber 4"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Djinn Ash", + }, + }, + ["Carbon Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Carbon Rod", + }, + }, + ["Carbon Fishing Rod 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Glass Fiber", + }, + }, + ["Carbonara"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Black Pepper", + "Holy Basil", + "Spaghetti", + "Selbina Milk", + "Stone Cheese", + "Bird Egg", + "Buffalo Jerky", + }, + }, + ["Cardinal Vest"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Steel Sheet", + "Gold Thread", + "Ram Leather", + "Tiger Leather", + "Tiger Leather", + "Beeswax", + "Manticore Lth.", + "Manticore Lth.", + }, + }, + ["Carmine Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Desk", + "Red Textile Dye", + }, + }, + ["Carp Sushi"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rock Salt", + "Forest Carp", + }, + }, + ["Carp Sushi 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rock Salt", + "Moat Carp", + }, + }, + ["Carrion Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Hare Meat", + "Hare Meat", + "Rotten Meat", + }, + }, + ["Carrot Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "San d'Or. Carrot", + "San d'Or. Carrot", + "San d'Or. Carrot", + "San d'Or. Carrot", + }, + }, + ["Carrot Paste"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "La Theine Millet", + "Lizard Egg", + "Distilled Water", + "Vomp Carrot", + "Vomp Carrot", + }, + }, + ["Cartonnier"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Bldwd. Lumber", + "Cassia Lumber", + "Cassia Lumber", + }, + }, + ["Cashmere Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cashmere Thrd.", + "Cashmere Thrd.", + "Cashmere Thrd.", + }, + }, + ["Cashmere Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Cashmere Wool", + "Cashmere Wool", + }, + }, + ["Cat Baghnakhs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Rabbit Hide", + "Bone Chip", + "Bone Chip", + "Bone Chip", + }, + }, + ["Catobl. Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Catoblepas Hide", + "Distilled Water", + }, + }, + ["Catobl. Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Catoblepas Hide", + "Distilled Water", + }, + }, + ["Catobl. Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Catoblepas Hide", + "Catoblepas Hide", + "Catoblepas Hide", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Cehuetzi Snow Cone"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Sugar", + "Rolanberry", + "Thundermelon", + "Thundermelon", + "C. Ice Shard", + }, + }, + ["Cehuetzi Snow Cone 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Sugar", + "Rolanberry", + "Honey", + "Thundermelon", + "Thundermelon", + "C. Ice Shard", + }, + }, + ["Celata"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Sheet", + "Steel Sheet", + "Darksteel Chain", + "Sheep Leather", + }, + }, + ["Celerity Salad"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gausebit Grass", + "Blue Peas", + "Cupid Worm", + "La Theine Millet", + "La Theine Cbg.", + "King Truffle", + "Shall Shell", + "Vomp Carrot", + }, + }, + ["Celerity Salad 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gausebit Grass", + "Blue Peas", + "Cupid Worm", + "La Theine Millet", + "La Theine Cbg.", + "King Truffle", + "Istiridye", + "Vomp Carrot", + }, + }, + ["Celerity Salad 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cook. Kit 75", + }, + }, + ["Celestial Globe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Comet Fragment", + "Puny Planet Kit", + "Cosmic Designs", + }, + }, + ["Cerberus Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bldwd. Lumber", + "Bldwd. Lumber", + "Coeurl Whisker", + "Cerberus Claw", + "Karakul Cloth", + }, + }, + ["Cerberus Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Cerberus Hide", + "Karakul Thread", + }, + }, + ["Cerberus Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cerberus Claw", + "Cerberus Claw", + }, + }, + ["Cermet Chunk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Magic Pot Shard", + "Magic Pot Shard", + "Magic Pot Shard", + "Magic Pot Shard", + }, + }, + ["Cermet Chunk 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Golem Shard", + "Golem Shard", + }, + }, + ["Cermet Chunk 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Doll Shard", + "Doll Shard", + }, + }, + ["Cermet Claws"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beetle Jaw", + "Cermet Chunk", + }, + }, + ["Cermet Kilij"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Garnet", + "Sunstone", + "Marid Leather", + "Teak Lumber", + }, + }, + ["Cermet Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Oak Lumber", + "Cermet Chunk", + }, + }, + ["Cermet Kukri"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Cermet Chunk", + "Wyvern Skin", + }, + }, + ["Cermet Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Cermet Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tiger Leather", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Cerulean Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Desk", + "Blue Text. Dye", + }, + }, + ["Cesti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Chai"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Im. Tea Leaves", + "Distilled Water", + }, + }, + ["Chain Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Chain", + "Silver Chain", + "Silver Chain", + }, + }, + ["Chain Choker"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Chain", + "Garnet", + }, + }, + ["Chain Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Chain", + "Silver Chain", + }, + }, + ["Chain Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Iron Chain", + "Linen Cloth", + "Ram Leather", + "Ram Leather", + }, + }, + ["Chain Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Iron Chain", + "Ram Leather", + }, + }, + ["Chainmail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Chain", + "Iron Chain", + "Iron Chain", + "Iron Chain", + "Ram Leather", + }, + }, + ["Chakram"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Ingot", + "Gold Ingot", + "Mercury", + }, + }, + ["Chalaimbille"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Rock Salt", + "Carbon Dioxide", + "Uleguerand Milk", + "Uleguerand Milk", + }, + }, + ["Chamomile Tea"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Chamomile", + "Chamomile", + "Honey", + "Distilled Water", + }, + }, + ["Chanar Xyston"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Midrium Ingot", + "Midrium Ingot", + "Urunday Lumber", + "Urunday Lumber", + }, + }, + ["Chapuli Arrowhd."] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Chapuli Horn", + }, + }, + ["Chapuli Arrowhd. 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Shagreen File", + "Chapuli Horn", + "Chapuli Horn", + "Chapuli Horn", + }, + }, + ["Chapuli Fltchg."] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chapuli Wing", + "Chapuli Wing", + }, + }, + ["Chapuli Fltchg. 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Chapuli Wing", + "Chapuli Wing", + "Chapuli Wing", + "Chapuli Wing", + "Chapuli Wing", + "Chapuli Wing", + }, + }, + ["Charisma Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cattleya", + "Dried Mugwort", + "2Leaf Mandra Bud", + "Honey", + "Distilled Water", + }, + }, + ["Chasuble"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Silver Thread", + "Velvet Cloth", + "Velvet Cloth", + "Manticore Lth.", + "Eft Skin", + "Eltoro Leather", + "Eltoro Leather", + }, + }, + ["Cheese Sandwich"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Crying Mustard", + "Black Pepper", + "White Bread", + "Mithran Tomato", + "Chalaimbille", + "Graubg. Lettuce", + }, + }, + ["Chelona Blazer"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Carnelian", + "Karakul Skin", + "Beetle Blood", + "Silver Brocade", + "Karakul Cloth", + "Wamoura Silk", + "Amph. Leather", + "Wyrdstrand", + }, + }, + ["Chelona Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Thread", + "Karakul Cloth", + "Karakul Cloth", + "Karakul Cloth", + "Platinum Silk", + "Amph. Leather", + }, + }, + ["Chelona Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Karakul Cloth", + "Karakul Cloth", + "Wamoura Silk", + "Platinum Silk", + "Amph. Leather", + }, + }, + ["Chelona Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Carnelian", + "Beetle Blood", + "Silver Brocade", + "Wolf Felt", + "Wamoura Silk", + "Platinum Silk", + "Amph. Leather", + "Wyrdstrand", + }, + }, + ["Chelona Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wolf Felt", + "Wolf Felt", + "Imp. Silk Cloth", + "Platinum Silk", + "Amph. Leather", + }, + }, + ["Cherry Bavarois"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Maple Sugar", + "Gelatin", + "Vanilla", + "Yagudo Cherry", + "Bird Egg", + "Uleguerand Milk", + }, + }, + ["Cherry Macaron"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Almond", + "Lizard Egg", + "Yagudo Cherry", + }, + }, + ["Cherry Muffin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Selbina Milk", + "Yagudo Cherry", + "Bird Egg", + }, + }, + ["Chest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Lauan Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + }, + }, + ["Chestnut Club"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Lumber", + }, + }, + ["Chestnut Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Log", + }, + }, + ["Chestnut Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Log", + "Chestnut Log", + "Chestnut Log", + "Bundling Twine", + }, + }, + ["Chestnut Sabots"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Sheep Leather", + }, + }, + ["Chestnut Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Bird Feather", + }, + }, + ["Cheviot Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Cheviot Cloth", + "Cheviot Cloth", + }, + }, + ["Chiffonier"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + }, + }, + ["Chikuwa"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rock Salt", + "Bastore Bream", + "Tiger Cod", + }, + }, + ["Chimera Blood"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Lesser Chigoe", + }, + }, + ["Chimera Blood 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Triturator", + "Lesser Chigoe", + "Lesser Chigoe", + "Lesser Chigoe", + }, + }, + ["Chirich Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Plovid Effluvium", + "Macuil Plating", + "Defiant Sweat", + "Dark Matter", + }, + }, + ["Chirping Grasshopper Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Skull Locust", + "Skull Locust", + "La Theine Cbg.", + "Gysahl Greens", + "Little Worm", + "Shell Bug", + }, + }, + ["Chocobo Blinkers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Silk Cloth", + "Karakul Leather", + }, + }, + ["Chocobo Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Grass Cloth", + "Dhalmel Leather", + "Dhalmel Leather", + }, + }, + ["Chocobo Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chocobo Fthr.", + "Chocobo Fthr.", + }, + }, + ["Chocobo Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chocobo Fthr.", + "Chocobo Fthr.", + "Chocobo Fthr.", + "Chocobo Fthr.", + "Chocobo Fthr.", + "Chocobo Fthr.", + "Zephyr Thread", + }, + }, + ["Chocobo Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Dhalmel Leather", + "Lizard Skin", + }, + }, + ["Chocobo Hood"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + }, + }, + ["Chocobo Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Wool Cloth", + "Sheep Leather", + }, + }, + ["Chocobo Jack Coat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Linen Cloth", + "Wool Cloth", + "Sheep Leather", + "Ram Leather", + "Ram Leather", + }, + }, + ["Chocobo Taping"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Chocolate Cake"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Maple Sugar", + "Olive Oil", + "Selbina Milk", + "Heart Chocolate", + "Bird Egg", + "Apkallu Egg", + }, + }, + ["Chocolate Crepe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Almond", + "Honey", + "Pamamas", + "Bbl. Chocolate", + "Bird Egg", + "Uleguerand Milk", + }, + }, + ["Chocolate Rusk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Bbl. Chocolate", + "Bbl. Chocolate", + "Iron Bread", + "Bird Egg", + }, + }, + ["Chocolixir"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mistletoe", + "Revival Root", + "Gold Leaf", + "Royal Jelly", + "Distilled Water", + }, + }, + ["Chocomilk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Kukuru Bean", + "Kukuru Bean", + "Kukuru Bean", + "Kukuru Bean", + "Honey", + "Selbina Milk", + "Distilled Water", + }, + }, + ["Chocotonic"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Attohwa Ginseng", + "Distilled Water", + "Gysahl Greens", + }, + }, + ["Chocotonic 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Yellow Ginseng", + "Distilled Water", + "Gysahl Greens", + }, + }, + ["Chronos Tooth"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Colossal Skull", + }, + }, + ["Chrysoberyl"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Titanite", + }, + }, + ["Chrysoberyl Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chrysoberyl", + "Gold Ring", + }, + }, + ["Chrysoberyl Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chrysoberyl", + "Gold Ring +1", + }, + }, + ["Cilbir"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Selbina Butter", + "Rock Salt", + "Apkallu Egg", + "Apkallu Egg", + "Yogurt", + }, + }, + ["Cilice"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Dhalmel Hair", + "Dhalmel Hair", + }, + }, + ["Cinna-cookie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Cinnamon", + "Lizard Egg", + "Distilled Water", + }, + }, + ["Cinna-cookie 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Cinnamon", + "Distilled Water", + "Bird Egg", + }, + }, + ["Circlet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Brass Ingot", + }, + }, + ["Cl. Wheat Broth"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Coriander", + "Imperial Flour", + "Distilled Water", + }, + }, + ["Claws"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Beetle Jaw", + }, + }, + ["Claymore"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Ash Lumber", + "Lizard Skin", + }, + }, + ["Clear Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Clear Topaz", + "Silver Earring", + }, + }, + ["Clear Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Clear Topaz", + "Silver Earring +1", + }, + }, + ["Clear Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Clear Topaz", + "Silver Ring", + }, + }, + ["Clear Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Clear Topaz", + "Silver Ring +1", + }, + }, + ["Clear Topaz"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Translucent Rock", + }, + }, + ["Clear Topaz 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sparkling Stone", + }, + }, + ["Clear Topaz 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Snow Geode", + }, + }, + ["Clear Topaz 4"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gelid Aggregate", + }, + }, + ["Cleric's Torque"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Waktza Crest", + "Dark Matter", + "Khoma Thread", + "Seedstone Crystal", + "Moldy Torque", + }, + }, + ["Cleric's Wand"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Dark Matter", + "Tartarian Chain", + "Cypress Log", + "Moldy Club", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Seedstone Crystal", + }, + }, + ["Clerisy Strap"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Behemoth Hide", + "Bztavian Wing", + }, + }, + ["Cloak"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Clothcraft Set 25"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Clothcraft Set 45"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Chocobo Fthr.", + }, + }, + ["Clothcraft Set 64"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Wool Thread", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Clothcraft Set 70"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Gold Thread", + }, + }, + ["Clothcraft Set 75"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Imp. Silk Cloth", + "Battle Bracers", + }, + }, + ["Clothcraft Set 80"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Silver Thread", + "Silver Thread", + "Gold Thread", + "Gold Thread", + }, + }, + ["Clothcraft Set 85"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Rainbow Cloth", + "Carbon Fiber", + }, + }, + ["Clothcraft Set 90"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Rainbow Thread", + "Rainbow Thread", + "Silver Thread", + "Gold Thread", + }, + }, + ["Clothcraft Set 95"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Wool Thread", + "Rainbow Thread", + "Silver Thread", + "Gold Thread", + "Manticore Hair", + "Manticore Hair", + }, + }, + ["Clothespole"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Clothespole", + }, + }, + ["Clothespole 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Silk Thread", + }, + }, + ["Clown's Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Coral Fragment", + "Lindwurm Skin", + }, + }, + ["Coated Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Exor. Oak Lbr.", + "Oak Shield", + }, + }, + ["Coconut Rusk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Iron Bread", + "Bird Egg", + "Elshimo Coconut", + }, + }, + ["Coeurl Cesti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Cesti", + }, + }, + ["Coeurl Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Cuir Gloves", + }, + }, + ["Coeurl Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Coeurl Hide", + }, + }, + ["Coeurl Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Coeurl Leather", + "Sheep Leather", + }, + }, + ["Coeurl Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Coeurl Hide", + "Distilled Water", + }, + }, + ["Coeurl Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Coeurl Hide", + "Distilled Water", + }, + }, + ["Coeurl Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Coeurl Hide", + "Coeurl Hide", + "Coeurl Hide", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Coeurl Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Mythril Sheet", + "Cuir Highboots", + }, + }, + ["Coeurl Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Coeurl Hide", + }, + }, + ["Coeurl Mantle 2"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Leath. Kit 85", + }, + }, + ["Coeurl Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Coeurl Leather", + "Faceguard", + }, + }, + ["Coeurl Saute"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Honey", + "Coeurl Meat", + "Wild Onion", + "Grape Juice", + }, + }, + ["Coeurl Saute 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Honey", + "Wild Onion", + "Grape Juice", + "Lynx Meat", + }, + }, + ["Coeurl Sub"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Selbina Butter", + "Crying Mustard", + "White Bread", + "La Theine Cbg.", + "Mithran Tomato", + "Coeurl Saute", + }, + }, + ["Coeurl Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Coeurl Leather", + "Cuir Trousers", + }, + }, + ["Coffee Beans"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Coffee Cherries", + }, + }, + ["Coffee Macaron"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Coffee Beans", + "Almond", + "Lizard Egg", + }, + }, + ["Coffee Muffin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Coffee Powder", + "Selbina Milk", + "Bird Egg", + }, + }, + ["Coffee Powder"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rst. Coff. Beans", + }, + }, + ["Coffee Table"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Thread", + "Lancewood Lbr.", + "Lancewood Lbr.", + "Lancewood Lbr.", + "Silver Brocade", + }, + }, + ["Coffer"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Yew Lumber", + "Yew Lumber", + "Yew Lumber", + "Yew Lumber", + "Yew Lumber", + "Rosewood Lbr.", + }, + }, + ["Coiler II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Carbon Fiber", + "Super Cermet", + "Imperial Cermet", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Colibri Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Colibri Feather", + "Colibri Feather", + }, + }, + ["Colibri Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + "Colibri Feather", + }, + }, + ["Colichemarde"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Deathstone", + "Mailbreaker", + }, + }, + ["Colored Egg"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lizard Egg", + "La Theine Cbg.", + "San d'Or. Carrot", + "Distilled Water", + }, + }, + ["Colored Egg 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "La Theine Cbg.", + "San d'Or. Carrot", + "Distilled Water", + "Bird Egg", + }, + }, + ["Colossal Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Gigant Axe", + }, + }, + ["Combat Caster's Axe +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Cmb.Cst. Axe", + }, + }, + ["Combat Caster's Boomerang +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Cmb.Cst. B'merang", + }, + }, + ["Combat Caster's Cloak +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Cmb.Cst. Cloak", + }, + }, + ["Combat Caster's Dagger +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Cmb.Cst. Dagger", + }, + }, + ["Combat Caster's Mitts +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Cmb.Cst. Mitts", + }, + }, + ["Combat Caster's Scimitar +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Cmb.Cst. Scimitar", + }, + }, + ["Combat Caster's Shoes +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Cmb.Cst. Shoes", + }, + }, + ["Combat Caster's Slacks +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Cmb.Cst. Slacks", + }, + }, + ["Combat Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Saruta Cotton", + "Ephemeral Cloth", + }, + }, + ["Commode"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + }, + }, + ["Commodore Charm"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Claw", + "Dark Matter", + "Cyan Coral", + "Jadeite Crystal", + "Moldy Charm", + }, + }, + ["Commodore's Knife"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Horn", + "Dark Matter", + "Ruthenium Ore", + "Moldy Dagger", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Jadeite Crystal", + }, + }, + ["Composite Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Lumber", + "Ash Lumber", + "Wool Thread", + "Linen Cloth", + }, + }, + ["Composite Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Broken Comp. Rod", + }, + }, + ["Composite Fishing Rod 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Cermet Chunk", + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Glass Fiber", + "Glass Fiber", + }, + }, + ["Compression Sphere"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Demon Pen", + }, + }, + ["Compression Sphere 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tonberry Board", + }, + }, + ["Compression Sphere 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Orcish Mail Scales", + }, + }, + ["Compression Sphere 4"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Colorful Hair", + }, + }, + ["Compression Sphere 5"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dark Crest Card", + }, + }, + ["Console"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Dogwd. Lumber", + "Dogwd. Lumber", + "Dogwd. Lumber", + }, + }, + ["Cooking Set 25"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Bay Leaves", + "Rock Salt", + "La Theine Cbg.", + "Frost Turnip", + "Wild Onion", + "Eggplant", + "San d'Or. Carrot", + "Distilled Water", + }, + }, + ["Cooking Set 45"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Selbina Butter", + "Black Pepper", + "Rock Salt", + "Wild Onion", + "Mithran Tomato", + "Puk Egg", + "Puk Egg", + }, + }, + ["Cooking Set 65"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Bay Leaves", + "Olive Oil", + "Wild Onion", + "Eggplant", + "Mithran Tomato", + "Zucchini", + "Paprika", + }, + }, + ["Cooking Set 70"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Maple Sugar", + "Win. Tea Leaves", + "Sage", + "Selbina Milk", + "Distilled Water", + }, + }, + ["Cooking Set 75"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Gausebit Grass", + "Blue Peas", + "Cupid Worm", + "La Theine Millet", + "La Theine Cbg.", + "King Truffle", + "Shall Shell", + "Vomp Carrot", + }, + }, + ["Cooking Set 80"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Selbina Butter", + "Bay Leaves", + "Rock Salt", + "Kazham Pineapl.", + "Shall Shell", + "Shall Shell", + "Distilled Water", + }, + }, + ["Cooking Set 85"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Popoto", + "Curry Powder", + "Turmeric", + "Coeurl Meat", + "Selbina Milk", + "Wild Onion", + "Distilled Water", + }, + }, + ["Cooking Set 90"] = { + ["crystal"] = "Fluid Crystal", + ["ingredients"] = { + "Faerie Apple", + "Rolanberry", + "Mithran Tomato", + "Red Terrapin", + }, + }, + ["Cooking Set 95"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Popoto", + "Bay Leaves", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Dragon Meat", + "San d'Or. Carrot", + "Rarab Tail", + }, + }, + ["Copper Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Firesand", + }, + }, + ["Copper Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + }, + }, + ["Copper Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ore", + "Copper Ore", + "Copper Ore", + "Copper Ore", + }, + }, + ["Copper Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ore", + "Copper Nugget", + "Copper Nugget", + "Copper Nugget", + "Copper Nugget", + "Copper Nugget", + "Copper Nugget", + }, + }, + ["Copper Nugget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Meteorite", + "Panacea", + }, + }, + ["Copper Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Copper Ingot", + }, + }, + ["Copper Ring 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 5", + }, + }, + ["Coral Bangles"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Coral Fragment", + "Coral Fragment", + "Giant Femur", + }, + }, + ["Coral Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coral Fragment", + "Darksteel Cap", + }, + }, + ["Coral Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Coral Fragment", + "Coral Fragment", + "Leather Trousers", + }, + }, + ["Coral Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Coral Fragment", + "Coral Fragment", + }, + }, + ["Coral Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Coral Fragment", + "Coral Fragment", + "Leather Gloves", + }, + }, + ["Coral Gorget"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheep Leather", + "Coral Fragment", + }, + }, + ["Coral Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Coral Fragment", + "Coral Fragment", + "Leather Highboots", + }, + }, + ["Coral Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Pearl", + "Black Pearl", + "Coral Fragment", + }, + }, + ["Coral Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Coeurl Leather", + "Coral Fragment", + "Coral Fragment", + }, + }, + ["Coral Horn"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oxblood", + }, + }, + ["Coral Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Coeurl Leather", + "Wyvern Scales", + "Coral Fragment", + }, + }, + ["Coral Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Wyvern Scales", + "Coral Fragment", + }, + }, + ["Coral Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Coral Fragment", + "Coral Fragment", + }, + }, + ["Coral Ring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 80", + }, + }, + ["Coral Scale Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Sheep Leather", + "Coral Fragment", + "Coral Fragment", + "Coral Fragment", + "Coral Fragment", + "Leather Vest", + }, + }, + ["Coral Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Linen Cloth", + "Coral Fragment", + }, + }, + ["Coral Sword"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coral Fragment", + "Coral Fragment", + "Coral Fragment", + "Coral Fragment", + "Katzbalger", + }, + }, + ["Coral Visor"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheep Leather", + "Coral Fragment", + "Coral Fragment", + }, + }, + ["Cornette"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Brass Ingot", + "Bone Chip", + }, + }, + ["Cornstarch"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Millioncorn", + "Millioncorn", + }, + }, + ["Corsair's Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Demon Horn", + }, + }, + ["Corsair's Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Marine Hat", + }, + }, + ["Corselet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Mercury", + "Lm. Bf. Leather", + "Ovinnik Leather", + "Marid Leather", + "Marid Hair", + "Scintillant Ingot", + "Star Sapphire", + }, + }, + ["Corsette"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Cloth", + "Dhalmel Leather", + "Coeurl Whisker", + "Waistbelt", + "Scarlet Ribbon", + }, + }, + ["Cotton Brais"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + "Sheep Leather", + }, + }, + ["Cotton Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Cotton Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Thread", + "Cotton Thread", + }, + }, + ["Cotton Dogi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Cotton Doublet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Cotton Gaiters"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + "Sheep Leather", + }, + }, + ["Cotton Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Cotton Hachimaki"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Cotton Headband"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Carbon Fiber", + }, + }, + ["Cotton Headband 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 20", + }, + }, + ["Cotton Headgear"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Cotton Kyahan"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Linen Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Cotton Sitabaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Cotton Cloth", + "Linen Cloth", + }, + }, + ["Cotton Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Grass Thread", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Cotton Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Cotton Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + "Spindle", + }, + }, + ["Cotton Tofu"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Bittern", + "Soy Milk", + }, + }, + ["Couse"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Ash Lumber", + }, + }, + ["Crab Stewpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fish Stock", + "Woozyshroom", + "Land Crab Meat", + "Coral Fungus", + "Distilled Water", + "Cotton Tofu", + "Cibol", + "Shungiku", + }, + }, + ["Crab Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Land Crab Meat", + "Distilled Water", + }, + }, + ["Cracker"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Firesand", + "Bast Parchment", + "Bast Parchment", + }, + }, + ["Cracker 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Alch. Kit 15", + }, + }, + ["Crayfish Ball"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Crayfish", + "Crayfish", + "Crayfish", + "Distilled Water", + }, + }, + ["Crayfish Ball 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Gold Lobster", + "Distilled Water", + }, + }, + ["Crayfish Ball 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Distilled Water", + "Istakoz", + }, + }, + ["Cream Puff"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Rock Salt", + "Vanilla", + "Distilled Water", + "Bird Egg", + "Uleguerand Milk", + }, + }, + ["Credenza"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Teak Lumber", + "Teak Lumber", + "Teak Lumber", + "Teak Lumber", + "Jacaranda Lbr.", + }, + }, + ["Cricket Cage"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Rattan Lumber", + "Rattan Lumber", + "Dogwd. Lumber", + "Bell Cricket", + }, + }, + ["Crimson Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pigeon's Blood", + "Ocl. Earring", + }, + }, + ["Crimson Jelly"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Maple Sugar", + "Gelatin", + "Apple Mint", + "Clot Plasma", + "San d'Or. Grape", + "Distilled Water", + }, + }, + ["Crimson Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pigeon's Blood", + "Orichalcum Ring", + }, + }, + ["Crossbow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Chestnut Lumber", + "Glass Fiber", + }, + }, + ["Crossbow Bolt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Ash Lumber", + }, + }, + ["Crow Beret"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Black C. Feather", + "Bird Feather", + "Sheep Leather", + }, + }, + ["Crow Bracers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Sheep Leather", + }, + }, + ["Crow Gaiters"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Sheep Leather", + "Ram Leather", + "Tiger Leather", + }, + }, + ["Crow Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Sheep Leather", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Crow Jupon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Sheep Leather", + }, + }, + ["Crumhorn"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beetle Jaw", + "Demon Horn", + }, + }, + ["Crystal Rose"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scintillant Ingot", + "F. Glass Sheet", + "F. Glass Sheet", + "F. Glass Sheet", + }, + }, + ["Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Flint Stone", + "Flint Stone", + "Cotton Thread", + "Grass Cloth", + "Cotton Cloth", + }, + }, + ["Cuir Bandana"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ram Leather", + "Beeswax", + "Leather Bandana", + }, + }, + ["Cuir Bouilli"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Beeswax", + "Leather Vest", + }, + }, + ["Cuir Gloves"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Beeswax", + "Leather Gloves", + }, + }, + ["Cuir Highboots"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Beeswax", + "Leather Highboots", + }, + }, + ["Cuir Trousers"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Beeswax", + "Leather Trousers", + }, + }, + ["Cuir Trousers 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Leath. Kit 45", + }, + }, + ["Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Sheep Leather", + }, + }, + ["Culverin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Adaman Ingot", + "Mahogany Lbr.", + }, + }, + ["Cunning Brain Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Hare Meat", + "G. Sheep Meat", + "Cockatrice Meat", + }, + }, + ["Curdled Plasma Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Fiend Blood", + "Beastman Blood", + "Bird Blood", + }, + }, + ["Cursed Beverage"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Malboro Vine", + "Divine Sap", + "Kitron", + "Selbina Milk", + "Distilled Water", + }, + }, + ["Cursed Breastplate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Ocl. Sheet", + "Drk. Adm. Sheet", + "Drk. Adm. Sheet", + "Cerber. Leather", + "Cerber. Leather", + "Scintillant Ingot", + "Rubber Harness", + }, + }, + ["Cursed Breeches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Chain", + "Adaman Chain", + "Linen Cloth", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Cursed Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Angel Skin", + "Darksteel Cap", + }, + }, + ["Cursed Celata"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Brass Sheet", + "Adaman Sheet", + "Adaman Chain", + "Sheep Leather", + }, + }, + ["Cursed Clogs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Undead Skin", + "Marid Leather", + "Marid Leather", + "Netherpact Chain", + "Platinum Silk", + }, + }, + ["Cursed Coat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Marid Leather", + "Imp. Silk Cloth", + "Imp. Silk Cloth", + "Netherfield Chain", + "Platinum Silk", + }, + }, + ["Cursed Crown"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Gold Ingot", + "Siren's Hair", + }, + }, + ["Cursed Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Angelstone", + "Angelstone", + "Velvet Cloth", + "Karakul Leather", + "Imp. Silk Cloth", + "Netherspirit Chain", + "Platinum Silk", + }, + }, + ["Cursed Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Ocl. Ingot", + "Platinum Sheet", + "Platinum Chain", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + "Darksteel Cuirass", + }, + }, + ["Cursed Cuishes"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Drk. Adm. Sheet", + "Marid Leather", + "Scintillant Ingot", + "Rubber Chausses", + }, + }, + ["Cursed Cuisses"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Dragon Blood", + "Dragon Cuisses", + }, + }, + ["Cursed Dalmatica"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Chain", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Rainbow Cloth", + "Ram Leather", + "Behem. Leather", + "Siren's Macrame", + }, + }, + ["Cursed Diechlings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Sheet", + "Cermet Chunk", + "Darksteel Cuisses", + }, + }, + ["Cursed Finger Gauntlets"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Dragon Blood", + "Dragon Fng. Gnt.", + }, + }, + ["Cursed Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Drk. Adm. Sheet", + "Scintillant Ingot", + "Rubber Gloves", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Cursed Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Wyvern Scales", + "Angel Skin", + }, + }, + ["Cursed Greaves"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Dragon Blood", + "Dragon Greaves", + }, + }, + ["Cursed Haidate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Divine Lumber", + "Animal Glue", + "Urushi", + "Haidate", + }, + }, + ["Cursed Handschuhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Cermet Chunk", + "Dst. Gauntlets", + }, + }, + ["Cursed Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Tiger Leather", + "Coral Fragment", + "Oxblood", + "Angel Skin", + }, + }, + ["Cursed Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Velvet Cloth", + "Tiger Leather", + "Marid Leather", + "Imp. Silk Cloth", + "Nethereye Chain", + "Platinum Silk", + }, + }, + ["Cursed Hauberk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Adaman Sheet", + "Adaman Chain", + "Gold Thread", + "Rainbow Cloth", + "Sheep Leather", + "Southern Pearl", + "Hauberk", + }, + }, + ["Cursed Helm"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Ocl. Sheet", + "Karakul Leather", + "Drk. Adm. Sheet", + "Scintillant Ingot", + "Rubber Cap", + }, + }, + ["Cursed Kabuto"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Divine Lumber", + "Animal Glue", + "Urushi", + "Zunari Kabuto", + }, + }, + ["Cursed Kote"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Divine Lumber", + "Animal Glue", + "Urushi", + "Kote", + }, + }, + ["Cursed Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Tiger Leather", + "Wyvern Scales", + "Angel Skin", + }, + }, + ["Cursed Mail"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Dragon Blood", + "Dragon Blood", + "Dragon Mail", + }, + }, + ["Cursed Mask"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Dragon Blood", + "Dragon Mask", + }, + }, + ["Cursed Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Wool Cloth", + "Rainbow Cloth", + "Saruta Cotton", + "Siren's Hair", + }, + }, + ["Cursed Mufflers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Adaman Sheet", + "Thick Mufflers", + }, + }, + ["Cursed Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Rainbow Cloth", + "Manticore Lth.", + "Siren's Macrame", + }, + }, + ["Cursed Sabatons"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Drk. Adm. Sheet", + "Drk. Adm. Sheet", + "Marid Leather", + "Marid Leather", + "Scintillant Ingot", + "Rubber Soles", + }, + }, + ["Cursed Schaller"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Sheet", + "Gold Ingot", + "Platinum Sheet", + "Platinum Chain", + "Sheep Leather", + "Cermet Chunk", + }, + }, + ["Cursed Schuhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Cermet Chunk", + "Cermet Chunk", + "Dst. Sabatons", + }, + }, + ["Cursed Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Rainbow Cloth", + "Siren's Macrame", + }, + }, + ["Cursed Sollerets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Adaman Sheet", + "Adaman Chain", + "Thick Sollerets", + }, + }, + ["Cursed Soup"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kitron", + "Persikos", + "Honey", + "Royal Jelly", + "Distilled Water", + }, + }, + ["Cursed Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Cloth", + "Tiger Leather", + "Angel Skin", + }, + }, + ["Cursed Sune-Ate"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Divine Lumber", + "Animal Glue", + "Urushi", + "Sune-Ate", + }, + }, + ["Cursed Togi"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Ancient Lumber", + "Divine Lumber", + "Divine Lumber", + "Tiger Leather", + "Animal Glue", + "Urushi", + "Hara-Ate", + }, + }, + ["Cursed Trews"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Velvet Cloth", + "Marid Leather", + "Imp. Silk Cloth", + "Imp. Silk Cloth", + "Nethercant Chain", + "Platinum Silk", + }, + }, + ["Cutlass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Cutlet Sandwich"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Rock Salt", + "Distilled Water", + "Pork Cutlet", + }, + }, + ["Cvl. Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wolf Hide", + "Sentinel's Mantle", + }, + }, + ["Cyan Orb"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Cyan Coral", + }, + }, + ["Cypress Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cypress Log", + }, + }, + ["Cypress Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bundling Twine", + "Cypress Log", + "Cypress Log", + "Cypress Log", + }, + }, + ["Cythara Anglica"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Ebony Lumber", + "Ancient Lumber", + "Ancient Lumber", + "Coeurl Whisker", + }, + }, + ["Czar's Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "T. Bgd. Leather", + "Koenigs Belt", + }, + }, + ["D. Fruit au Lait"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Honey", + "Selbina Milk", + "Dragon Fruit", + "Dragon Fruit", + }, + }, + ["Dabo"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Ash Lumber", + "Ash Lumber", + "Scintillant Ingot", + "Dark Ixion Tail", + "Dk. Ixion Ferrule", + }, + }, + ["Dagger (Weapon)"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rusty Dagger", + }, + }, + ["Dagger (Weapon) 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Iron Ingot", + }, + }, + ["Dakatsu-No-Nodowa"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silk Thread", + "Beryllium Ingot", + "Wyrm Blood", + }, + }, + ["Damage Gauge"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Light Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Damascus Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Relic Iron", + "Wootz Ore", + "Vanadium Ore", + "Vanadium Ore", + }, + }, + ["Dance Shoes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Moccasins", + }, + }, + ["Dancing Herbal Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Frost Turnip", + "Beaugreens", + "Beaugreens", + "Napa", + }, + }, + ["Dandy Spectacles"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "F. Glass Sheet", + }, + }, + ["Dark Adaman Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dark Adaman", + }, + }, + ["Dark Adaman Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Darksteel Ore", + "Darksteel Ore", + "Adaman Ore", + }, + }, + ["Dark Amood"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Silver Ingot", + "Garnet", + "Moblumin Ingot", + }, + }, + ["Dark Anima"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Malevolent Mem.", + "Malevolent Mem.", + "Malevolent Mem.", + "Malevolent Mem.", + }, + }, + ["Dark Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dark Ore", + }, + }, + ["Dark Bronze Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ore", + "Copper Ore", + "Tin Ore", + "Darksteel Ore", + }, + }, + ["Dark Bronze Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Bronze", + }, + }, + ["Dark Bronze Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Bronze", + "Dark Bronze", + "Dark Bronze", + "Dark Bronze", + "Dark Bronze", + "Dark Bronze", + "Workshop Anvil", + }, + }, + ["Dark Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Dark Cluster", + }, + }, + ["Dark Fewell"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Slime Oil", + "Black Rock", + "Catalytic Oil", + }, + }, + ["Dark Ixion Ferrule"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dark Ixion Horn", + }, + }, + ["Dark Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Dark Mezraq"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Platinum Ingot", + "Wamoura Silk", + }, + }, + ["Dark Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dark Bead", + "Orichalcum Ring", + }, + }, + ["Dark Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Dark Bead", + }, + }, + ["Darkling Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Revival Root", + "Imp Wing", + }, + }, + ["Darksteel Armet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Sheet", + "Darksteel Sheet", + "Gold Ingot", + "Sheep Leather", + "Mercury", + }, + }, + ["Darksteel Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Oak Lumber", + }, + }, + ["Darksteel Baselard"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Darksteel Ingot", + }, + }, + ["Darksteel Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Yew Lumber", + "Dst. Bolt Heads", + }, + }, + ["Darksteel Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Yew Lumber", + "Yew Lumber", + "Yew Lumber", + "Dst. Bolt Heads", + "Dst. Bolt Heads", + "Dst. Bolt Heads", + "Bundling Twine", + }, + }, + ["Darksteel Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + }, + }, + ["Darksteel Breeches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Chain", + "Darksteel Chain", + "Linen Cloth", + "Ram Leather", + "Ram Leather", + }, + }, + ["Darksteel Buckler"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Sheet", + "Darksteel Sheet", + "Walnut Lumber", + }, + }, + ["Darksteel Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Darksteel Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + }, + }, + ["Darksteel Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Mandrel", + }, + }, + ["Darksteel Claws"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Beetle Jaw", + }, + }, + ["Darksteel Claymore"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Chestnut Lumber", + "Ram Leather", + }, + }, + ["Darksteel Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Gold Ingot", + "Ram Leather", + "Ram Leather", + "Mercury", + }, + }, + ["Darksteel Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Ram Leather", + }, + }, + ["Darksteel Falchion"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + }, + }, + ["Darksteel Falx"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Black Pearl", + "Buffalo Leather", + }, + }, + ["Darksteel Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Gold Ingot", + "Mercury", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Darksteel Gorget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Ram Leather", + }, + }, + ["Darksteel Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Darksteel Hexagun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Ebony Lumber", + "Silver Ingot", + }, + }, + ["Darksteel Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Darksteel Ore", + }, + }, + ["Darksteel Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ore", + "Dst. Nugget", + "Dst. Nugget", + "Dst. Nugget", + "Dst. Nugget", + "Dst. Nugget", + "Dst. Nugget", + }, + }, + ["Darksteel Jambiya"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Silver Ingot", + "Sunstone", + "Mercury", + "Ladybug Wing", + }, + }, + ["Darksteel Katars"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Iron Sheet", + "Tiger Leather", + }, + }, + ["Darksteel Kilij"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Platinum Ingot", + "Platinum Ingot", + "Ruby", + "Garnet", + "Marid Leather", + }, + }, + ["Darksteel Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Oak Lumber", + }, + }, + ["Darksteel Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Sheet", + "Oak Lumber", + }, + }, + ["Darksteel Kris"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Painite", + }, + }, + ["Darksteel Kukri"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mahogany Lbr.", + "Cockatrice Skin", + }, + }, + ["Darksteel Kukri 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 65", + }, + }, + ["Darksteel Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Ash Lumber", + "Ash Lumber", + }, + }, + ["Darksteel Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Darksteel Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 60", + }, + }, + ["Darksteel Mace 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + }, + }, + ["Darksteel Maul"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Mahogany Lbr.", + }, + }, + ["Darksteel Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Tiger Leather", + }, + }, + ["Darksteel Mufflers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Chain Mittens", + }, + }, + ["Darksteel Nodowa"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Silk Thread", + }, + }, + ["Darksteel Pick"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Elm Lumber", + }, + }, + ["Darksteel Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + }, + }, + ["Darksteel Sabatons"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Gold Ingot", + "Ram Leather", + "Ram Leather", + "Mercury", + }, + }, + ["Darksteel Sainti"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Platinum Ingot", + "Platinum Ingot", + "Mercury", + }, + }, + ["Darksteel Scales"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + }, + }, + ["Darksteel Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Yew Lumber", + "Grass Cloth", + }, + }, + ["Darksteel Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + }, + }, + ["Darksteel Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Workshop Anvil", + }, + }, + ["Darksteel Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Ash Lumber", + "Wyvern Scales", + "Wyvern Scales", + "Wyvern Scales", + "Wyvern Scales", + }, + }, + ["Darksteel Sollerets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Greaves", + }, + }, + ["Darksteel Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Linen Cloth", + "Tiger Leather", + }, + }, + ["Darksteel Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Raptor Skin", + }, + }, + ["Darksteel Tabar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Oak Lumber", + }, + }, + ["Darksteel Voulge"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Gold Ingot", + }, + }, + ["Dart"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chocobo Fthr.", + "Chocobo Fthr.", + "Bat Fang", + "Animal Glue", + }, + }, + ["Dashing Subligar"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Stinky Subligar", + }, + }, + ["Date Tea"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Im. Tea Leaves", + "Distilled Water", + "Date", + }, + }, + ["Dawn Mulsum"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Holy Water", + "Grape Juice", + "White Honey", + }, + }, + ["Death Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Deathstone", + "Platinum Earring", + }, + }, + ["Death Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Deathstone", + "Ptm. Earring +1", + }, + }, + ["Death Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Deathstone", + "Platinum Ring", + }, + }, + ["Death Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Deathstone", + "Platinum Ring +1", + }, + }, + ["Death Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Yew Lumber", + "Grass Cloth", + "Fiend Blood", + }, + }, + ["Deathbone Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Bone Knife", + }, + }, + ["Debahocho"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Willow Lumber", + }, + }, + ["Decaying Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Flan Meat", + "Distilled Water", + "Rotten Meat", + }, + }, + ["Deductive Brocade Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brl. Gold Thread", + "Brocade Obi", + }, + }, + ["Deductive Gold Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brl. Gold Thread", + "Gold Obi", + }, + }, + ["Deep-Fried Shrimp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "White Bread", + "Bird Egg", + "Black Prawn", + "Black Prawn", + }, + }, + ["Deepbed Soil"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Beech Log", + "Woozyshroom", + "Sleepshroom", + "Danceshroom", + }, + }, + ["Degen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Silver Ingot", + }, + }, + ["Demon Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Demon Arrowhd.", + "Blk. Chc. Fltchg.", + }, + }, + ["Demon Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Demon Horn", + }, + }, + ["Demon Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Demon Horn", + "Demon Horn", + "Demon Horn", + "Shagreen File", + }, + }, + ["Demon Helm"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheep Leather", + "Demon Skull", + "Demon Horn", + "Demon Horn", + }, + }, + ["Demon Slayer"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Dragon Blood", + "Ameretat Vine", + "Adaman Kilij", + }, + }, + ["Demon's Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Behem. Leather", + "Demon Skull", + "Demon Skull", + }, + }, + ["Demon's Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Demon Horn", + }, + }, + ["Demon's Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Fish Scales", + "Demon Horn", + }, + }, + ["Demon's Ring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 70", + }, + }, + ["Deodorizer"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Olive Oil", + "Chamomile", + "Sage", + }, + }, + ["Deodorizer 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Olive Oil", + "Olive Oil", + "Chamomile", + "Chamomile", + "Sage", + "Sage", + "Triturator", + }, + }, + ["Deodorizer 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Alch. Kit 10", + }, + }, + ["Desert Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Sheep Leather", + "Sheep Leather", + "Yowie Skin", + }, + }, + ["Desert Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Yowie Skin", + "Yowie Skin", + }, + }, + ["Desk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Elm Lumber", + "Linen Cloth", + }, + }, + ["Detonation Sphere"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Shoalweed", + }, + }, + ["Detonation Sphere 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Fetich Legs", + }, + }, + ["Detonation Sphere 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Soiled Letter", + }, + }, + ["Detonation Sphere 4"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beryl Memosphere", + }, + }, + ["Detonation Sphere 5"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wind Crest Card", + }, + }, + ["Devotee's Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Silk Cloth", + "Zealot's Mitts", + }, + }, + ["Dexterity Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Malboro Vine", + "Sweet William", + "Dried Mugwort", + "Honey", + "Distilled Water", + }, + }, + ["Dhalmel Hair"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dhalmel Hide", + "Dhalmel Hide", + "Dhalmel Hide", + }, + }, + ["Dhalmel Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Dhalmel Hide", + "Distilled Water", + }, + }, + ["Dhalmel Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Dhalmel Hide", + "Dhalmel Hide", + "Dhalmel Hide", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Dhalmel Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Dhalmel Hide", + "Distilled Water", + }, + }, + ["Dhalmel Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Dhalmel Hide", + }, + }, + ["Dhalmel Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Pie Dough", + "Black Pepper", + "Rock Salt", + "Dhalmel Meat", + "Wild Onion", + "San d'Or. Carrot", + "Coral Fungus", + }, + }, + ["Dhalmel Steak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Olive Oil", + "Dhalmel Meat", + }, + }, + ["Dhalmel Stew"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Popoto", + "Cinnamon", + "Rock Salt", + "Dhalmel Meat", + "Wild Onion", + "Mithran Tomato", + "Distilled Water", + }, + }, + ["Diamond Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Diamond", + "Platinum Earring", + }, + }, + ["Diamond Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Diamond", + "Ptm. Earring +1", + }, + }, + ["Diamond Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Mahogany Lbr.", + "Platinum Sheet", + "Diamond", + "Diamond", + }, + }, + ["Diamond Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Diamond", + "Platinum Ring", + }, + }, + ["Diamond Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Diamond", + "Platinum Ring +1", + }, + }, + ["Diamond Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Platinum Sheet", + "Diamond", + "Diamond", + "Diamond", + "Diamond", + "Kite Shield", + }, + }, + ["Dija Sword"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Dragon Blood", + "Yggdreant Root", + "Bastard Sword", + }, + }, + ["Dispel Couse"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bwtch. Ash Lbr.", + "Couse", + }, + }, + ["Distilled Water"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Tahrongi Cactus", + }, + }, + ["Divine Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Divine Log", + }, + }, + ["Divine Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Divine Log", + "Divine Log", + "Divine Log", + "Bundling Twine", + }, + }, + ["Divine Sap"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Divine Log", + }, + }, + ["Divine Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Holy Water", + "Broadsword", + }, + }, + ["Dmc. Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Damascus Ingot", + }, + }, + ["Dogwood Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dogwood Log", + }, + }, + ["Dogwood Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dogwood Log", + "Dogwood Log", + "Dogwood Log", + "Bundling Twine", + }, + }, + ["Dominus Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sanctified Lbr.", + "Numinous Shield", + }, + }, + ["Donderbuss"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Damascus Ingot", + "Ormolu Ingot", + "Rockfin Tooth", + }, + }, + ["Dorado Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Noble Lady", + "Distilled Water", + "Ground Wasabi", + }, + }, + ["Doublet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Doublet 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 10", + }, + }, + ["Dragon Blood"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Dragon Heart", + }, + }, + ["Dragon Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dragon Bone", + "Darksteel Cap", + }, + }, + ["Dragon Claws"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Beetle Jaw", + "Dragon Talon", + "Dragon Talon", + }, + }, + ["Dragon Claws 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone. Kit 90", + }, + }, + ["Dragon Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Wyvern Scales", + "Wyvern Scales", + "Leather Trousers", + }, + }, + ["Dragon Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Wyvern Scales", + "Wyvern Scales", + "Leather Gloves", + }, + }, + ["Dragon Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Wyvern Scales", + "Wyvern Scales", + "Leather Highboots", + }, + }, + ["Dragon Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Buffalo Leather", + "Buffalo Leather", + "Dragon Bone", + "Wyrm Horn", + }, + }, + ["Dragon Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wyvern Scales", + "Buffalo Leather", + "Buffalo Leather", + "Dragon Bone", + }, + }, + ["Dragon Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Silver Thread", + "Wyvern Scales", + "Wyvern Scales", + "Wyvern Scales", + "Dragon Scales", + "Leather Vest", + }, + }, + ["Dragon Mask"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheep Leather", + "Wyvern Scales", + "Wyvern Scales", + }, + }, + ["Dragon Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wyvern Scales", + "Buffalo Leather", + "Dragon Bone", + }, + }, + ["Dragon Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dragon Talon", + "Dragon Talon", + }, + }, + ["Dragon Slayer"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Ameretat Vine", + "Demon Blood", + "Adaman Kilij", + }, + }, + ["Dragon Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Ginger", + "Popoto", + "Black Pepper", + "Dragon Meat", + "Frost Turnip", + "Wild Onion", + "Distilled Water", + }, + }, + ["Dragon Steak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Bay Leaves", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Dragon Meat", + "San d'Or. Carrot", + "Rarab Tail", + }, + }, + ["Dragon Steak 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 95", + }, + }, + ["Dragon Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sarcenet Cloth", + "Buffalo Leather", + "Dragon Bone", + }, + }, + ["Dragon Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Brass Tank", + "D. Fruit au Lait", + "D. Fruit au Lait", + "D. Fruit au Lait", + "D. Fruit au Lait", + }, + }, + ["Dragoon's Collar"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Claw", + "Dark Matter", + "Cyan Coral", + "Andalusite Crystal", + "Moldy Collar", + }, + }, + ["Dresser"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Gold Ingot", + "Gold Thread", + "Velvet Cloth", + }, + }, + ["Dried Berry"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Rolanberry", + "Rolanberry", + "Rolanberry", + }, + }, + ["Dried Date"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Date", + }, + }, + ["Dried Marjoram"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Fresh Marjoram", + "Fresh Marjoram", + "Fresh Marjoram", + "Fresh Marjoram", + "Fresh Marjoram", + "Fresh Marjoram", + "Fresh Marjoram", + "Fresh Marjoram", + }, + }, + ["Dried Mugwort"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Fresh Mugwort", + "Fresh Mugwort", + "Fresh Mugwort", + "Fresh Mugwort", + "Fresh Mugwort", + "Fresh Mugwort", + "Fresh Mugwort", + "Fresh Mugwort", + }, + }, + ["Drk. Adm. Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Adaman", + }, + }, + ["Drk. Adm. Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Adaman", + "Dark Adaman", + "Dark Adaman", + "Dark Adaman", + "Dark Adaman", + "Dark Adaman", + "Workshop Anvil", + }, + }, + ["Duelist's Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Plovid Flesh", + "Dark Matter", + "Khoma Thread", + "Moldy Sword", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Pyrope Crystal", + }, + }, + ["Duelist's Torque"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Waktza Crest", + "Dark Matter", + "Khoma Thread", + "Pyrope Crystal", + "Moldy Torque", + }, + }, + ["Dull Gold Thread"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Silk Thread", + "Ice Anima", + "Ice Anima", + "Light Anima", + }, + }, + ["Durium Chain"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Durium Ingot", + "Durium Ingot", + }, + }, + ["Durium Chain 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Mandrel", + }, + }, + ["Durium Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ore", + "Durium Ore", + "Durium Ore", + "Durium Ore", + }, + }, + ["Durium Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Durium Ingot", + }, + }, + ["Durium Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Workshop Anvil", + }, + }, + ["Dusk Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Tiger Gloves", + }, + }, + ["Dusk Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Behem. Leather", + "Wyvern Skin", + "Northern Jerkin", + }, + }, + ["Dusk Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Tiger Ledelsens", + }, + }, + ["Dusk Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Coeurl Mask", + }, + }, + ["Dusk Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Tiger Trousers", + }, + }, + ["Dux Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Sheep Leather", + "Dragon Scales", + "Turtle Shell", + "Hahava's Mail", + "Squamous Hide", + }, + }, + ["Dux Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Dragon Scales", + "Turtle Shell", + "Squamous Hide", + "Leather Gloves", + }, + }, + ["Dux Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Dragon Scales", + "Turtle Shell", + "Squamous Hide", + "Leather Highboots", + }, + }, + ["Dux Scale Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Dragon Scales", + "Turtle Shell", + "Turtle Shell", + "Turtle Shell", + "Hahava's Mail", + "Squamous Hide", + "Leather Vest", + }, + }, + ["Dux Visor"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dragon Scales", + "Turtle Shell", + "Hahava's Mail", + "Squamous Hide", + }, + }, + ["Dweomer Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Jacaranda Lbr.", + "Dweomer Steel", + }, + }, + ["Dweomer Maul"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mahogany Lbr.", + "Dweomer Steel", + }, + }, + ["Dweomer Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Yew Lumber", + "Grass Cloth", + "Fiend Blood", + "Dweomer Steel", + }, + }, + ["Dweomer Steel"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Swamp Ore", + }, + }, + ["Dynamic Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Behem. Leather", + "Mercury", + "Umbril Ooze", + }, + }, + ["Dynamo II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Sieglinde Putty", + "Homncl. Nerves", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Dynamo III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Sieglinde Putty", + "Homncl. Nerves", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Dyrnwyn"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Moonbow Steel", + "Moonbow Urushi", + "Cypress Lumber", + "Balmung", + }, + }, + ["Ea Cuffs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Sheet", + "Bztavian Stinger", + "Defiant Scarf", + "Niobium Ore", + "Niobium Ore", + "Niobium Ore", + }, + }, + ["Ea Hat"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Bztavian Stinger", + "Defiant Scarf", + "Niobium Ore", + "Niobium Ore", + "Niobium Ore", + }, + }, + ["Ea Houppelande"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Bztavian Stinger", + "Defiant Scarf", + "Defiant Scarf", + "Niobium Ore", + "Niobium Ingot", + }, + }, + ["Ea Pigaches"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Bztavian Stinger", + "Defiant Scarf", + "Niobium Ore", + "Niobium Ore", + "Niobium Ore", + }, + }, + ["Ea Slops"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Bztavian Stinger", + "Defiant Scarf", + "Niobium Ore", + "Niobium Ingot", + }, + }, + ["Earth Anima"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Profane Memory", + "Profane Memory", + "Profane Memory", + "Profane Memory", + }, + }, + ["Earth Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Puk Fletching", + "Earth Arrowhds.", + }, + }, + ["Earth Arrowheads"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Marid Tusk", + }, + }, + ["Earth Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Earth Ore", + }, + }, + ["Earth Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Earth Cluster", + }, + }, + ["Earth Fewell"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Yellow Rock", + "Catalytic Oil", + }, + }, + ["Earth Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lithic W. Scale", + "Dragon Greaves", + }, + }, + ["Earth Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Earth Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Earth Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Earth Bead", + }, + }, + ["Ebon Armet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Drk. Adm. Sheet", + "Drk. Adm. Sheet", + "Scintillant Ingot", + "Scintillant Ingot", + "Iridium", + }, + }, + ["Ebon Beret"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Scintillant Ingot", + "Ruszor Leather", + "Cambric", + "Cambric", + }, + }, + ["Ebon Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mlbd. Sheet", + "Platinum Ingot", + "Amph. Leather", + "Shagreen", + }, + }, + ["Ebon Brais"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Amph. Leather", + "Shagreen", + "Studded Trousers", + }, + }, + ["Ebon Breastplate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Ocl. Sheet", + "Drk. Adm. Sheet", + "Drk. Adm. Sheet", + "Scintillant Ingot", + "Scintillant Ingot", + "Iridium", + }, + }, + ["Ebon Clogs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Tiger Leather", + "Tiger Leather", + "Molybden. Ingot", + "Cambric", + "Cambric", + }, + }, + ["Ebon Frock"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Chain", + "Behem. Leather", + "Taffeta Cloth", + "Scintillant Ingot", + "Ruszor Leather", + "Cambric", + "Cambric", + }, + }, + ["Ebon Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Drk. Adm. Sheet", + "Drk. Adm. Sheet", + "Scintillant Ingot", + "Iridium", + "Studded Gloves", + }, + }, + ["Ebon Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Amph. Leather", + "Amph. Leather", + "Shagreen", + }, + }, + ["Ebon Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mlbd. Sheet", + "Platinum Sheet", + "Angel Skin", + "Red Textile Dye", + "Amph. Leather", + "Amph. Leather", + "Shagreen", + }, + }, + ["Ebon Hose"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Drk. Adm. Sheet", + "Drk. Adm. Sheet", + "Scintillant Ingot", + "Iridium", + }, + }, + ["Ebon Leggings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Wool Thread", + "Ram Leather", + "Drk. Adm. Sheet", + "Drk. Adm. Sheet", + "Scintillant Ingot", + "Iridium", + }, + }, + ["Ebon Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mlbd. Sheet", + "Amph. Leather", + "Shagreen", + }, + }, + ["Ebon Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Scintillant Ingot", + "Garglle. Shank", + "Ruszor Leather", + "Cambric", + "Cambric", + }, + }, + ["Ebon Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Scintillant Ingot", + "Cambric", + "Cambric", + }, + }, + ["Ebonite"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Sulfur", + "Flan Meat", + "Flan Meat", + }, + }, + ["Ebony Harp"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Ebony Lumber", + "Coeurl Whisker", + }, + }, + ["Ebony Harp 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 71", + }, + }, + ["Ebony Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Log", + }, + }, + ["Ebony Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Log", + "Ebony Log", + "Ebony Log", + "Bundling Twine", + }, + }, + ["Ebony Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Ebony Lumber", + }, + }, + ["Ebony Sabots"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Sheep Leather", + }, + }, + ["Ebony Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Giant Bird Fthr.", + }, + }, + ["Echidna's Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bldwd. Lumber", + "Bldwd. Lumber", + "Damascene Cloth", + "Simian Mane", + "Gabbrath Horn", + }, + }, + ["Echo Drops"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Honey", + "Distilled Water", + }, + }, + ["Echo Drops 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Sage", + "Triturator", + "Honey", + "Honey", + "Honey", + "Distilled Water", + }, + }, + ["Ecru Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Desk", + "White Text. Dye", + }, + }, + ["Eel Kabob"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Black Eel", + }, + }, + ["Eel Kabob 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Yilanbaligi", + }, + }, + ["Egg Sandwich"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "White Bread", + "Hard-boiled Egg", + "Graubg. Lettuce", + }, + }, + ["Egg Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Rock Salt", + "Lizard Egg", + "Distilled Water", + }, + }, + ["Egg Soup 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Rock Salt", + "Distilled Water", + "Bird Egg", + }, + }, + ["Eight-Sided Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Walnut Lumber", + "Walnut Lumber", + }, + }, + ["Eisenbrust"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Bronze Sheet", + "Iron Sheet", + "Iron Sheet", + "Silver Ingot", + "Sheep Leather", + "Mercury", + }, + }, + ["Eisendiechlings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Iron Sheet", + "Dhalmel Leather", + "Sheep Leather", + }, + }, + ["Eisenhentzes"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Iron Sheet", + "Silver Ingot", + "Mercury", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Eisenschaller"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Sheet", + "Iron Sheet", + "Silver Ingot", + "Sheep Leather", + "Mercury", + }, + }, + ["Eisenschuhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Silver Ingot", + "Dhalmel Leather", + "Sheep Leather", + "Mercury", + }, + }, + ["Ej Necklace"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Oxblood", + "Siren's Macrame", + "Wivre Maul", + "Carrier Crab Crpc.", + "Rockfin Tooth", + "Rockfin Tooth", + }, + }, + ["Elan Strap"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cerberus Hide", + "Cehuetzi Pelt", + }, + }, + ["Eldritch Bone Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wail. Bone Chip", + "Bone Hairpin", + }, + }, + ["Eldritch Horn Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wailing Ram Horn", + "Horn Hairpin", + }, + }, + ["Electrified Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ladybug Wing", + "Gnat Wing", + "Panopt Tears", + "Snap. Secretion", + }, + }, + ["Electrum Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Firesand", + "Electrum Ingot", + }, + }, + ["Electrum Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Electrum Ingot", + "Electrum Ingot", + }, + }, + ["Electrum Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mandrel", + "Electrum Ingot", + "Electrum Ingot", + "Electrum Ingot", + "Electrum Ingot", + "Electrum Ingot", + "Electrum Ingot", + }, + }, + ["Electrum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ore", + "Gold Ore", + "Gold Ore", + "Gold Ore", + }, + }, + ["Elite Beret"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Phoenix Feather", + "War Beret", + }, + }, + ["Elixir"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mistletoe", + "Revival Root", + "Dragon Blood", + "Royal Jelly", + "Distilled Water", + }, + }, + ["Elixir Tank"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sheep Leather", + "Brass Tank", + "Elixir", + "Elixir", + "Elixir", + "Elixir", + }, + }, + ["Elixir Vitae"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mistletoe", + "Revival Root", + "Imp Wing", + "Chimera Blood", + "Distilled Water", + }, + }, + ["Elm Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elm Log", + }, + }, + ["Elm Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elm Log", + "Elm Log", + "Elm Log", + "Bundling Twine", + }, + }, + ["Elm Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elm Lumber", + "Elm Lumber", + }, + }, + ["Elm Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Elm Lumber", + "Elm Lumber", + }, + }, + ["Elm Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elm Lumber", + "Ram Horn", + }, + }, + ["Elshena"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Maple Sugar", + "Olive Oil", + "Imperial Flour", + "Woozyshroom", + "Scream Fungus", + "Puffball", + "Bird Egg", + }, + }, + ["Elshimo Palm"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Willow Log", + "Rattan Lumber", + "Red Gravel", + "Elshimo Coconut", + "Humus", + }, + }, + ["Emerald Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Emerald", + "Platinum Earring", + }, + }, + ["Emerald Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Emerald", + "Ptm. Earring +1", + }, + }, + ["Emerald Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Emerald", + "Platinum Ring", + }, + }, + ["Emerald Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Emerald", + "Platinum Ring +1", + }, + }, + ["Emperor Roe"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Morinabaligi", + }, + }, + ["Emperor Roe 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Emperor Fish", + }, + }, + ["Empwr. Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Enhancing Mantle", + }, + }, + ["Enchanted Ink"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Black Ink", + "Magicked Blood", + }, + }, + ["Enfeeblement Kit of Blindness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fine Parchment", + "Fine Parchment", + "Enchanted Ink", + "Enchanted Ink", + "Padded Box", + "Blinding Potion", + }, + }, + ["Enfeeblement Kit of Poison"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fine Parchment", + "Fine Parchment", + "Enchanted Ink", + "Enchanted Ink", + "Padded Box", + "Poison Potion", + }, + }, + ["Enfeeblement Kit of Silence"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fine Parchment", + "Fine Parchment", + "Enchanted Ink", + "Enchanted Ink", + "Padded Box", + "Silencing Potion", + }, + }, + ["Enfeeblement Kit of Sleep"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fine Parchment", + "Fine Parchment", + "Enchanted Ink", + "Enchanted Ink", + "Padded Box", + "Sleeping Potion", + }, + }, + ["Engetsuto"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Dogwd. Lumber", + "Scintillant Ingot", + }, + }, + ["Enju"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Ancient Lumber", + "Cotton Thread", + "Raptor Skin", + "Midrium Ingot", + "Mantid Carapace", + }, + }, + ["Enriching Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Moonbow Steel", + "Moonbow Stone", + "Niobium Ingot", + "Enhancing Sword", + }, + }, + ["Enthralling Brocade Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sh. Gold Thread", + "Brocade Obi", + }, + }, + ["Enthralling Gold Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sh. Gold Thread", + "Gold Obi", + }, + }, + ["Epee"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Mythril Ingot", + "Gold Ingot", + "Platinum Ingot", + "Angelstone", + "Mercury", + }, + }, + ["Ephedra Ring"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Holy Water", + "Hallowed Water", + "Mythril Ring", + }, + }, + ["Eremite's Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Tooth", + "Hermit's Ring", + }, + }, + ["Eremite's Wand"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Willow Lumber", + "Hermit's Wand", + }, + }, + ["Eris' Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Seashell", + "Nemesis Earring", + }, + }, + ["Erlking's Blade"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Dweomer Steel", + }, + }, + ["Erlking's Kheten"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Rosewood Lbr.", + "Dweomer Steel", + }, + }, + ["Erlking's Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Peiste Leather", + "Dweomer Steel", + }, + }, + ["Erlking's Tabar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Oak Lumber", + "Dweomer Steel", + }, + }, + ["Errant Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Raxa", + "Peace Cape", + }, + }, + ["Errant Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Turquoise", + "Turquoise", + "Gold Thread", + "Silk Cloth", + "Rainbow Cloth", + "Sheep Leather", + }, + }, + ["Errant Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pearl", + "Rainbow Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Ram Leather", + "Ram Leather", + }, + }, + ["Errant Houppelande"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Chain", + "Rainbow Thread", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + "Rainbow Cloth", + "Rainbow Cloth", + "Ram Leather", + }, + }, + ["Errant Pigaches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Velvet Cloth", + "Undead Skin", + "Ram Leather", + "Ram Leather", + }, + }, + ["Errant Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + "Ram Leather", + }, + }, + ["Espadon"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Ether"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Bat Wing", + "Bat Wing", + "Dryad Root", + "Distilled Water", + }, + }, + ["Ether 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 50", + }, + }, + ["Ether Cotton"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Dried Marjoram", + "Cotton Cloth", + "Ahriman Wing", + "Treant Bulb", + "Distilled Water", + }, + }, + ["Ether Drop"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Bat Wing", + "Bat Wing", + "Dryad Root", + "Distilled Water", + }, + }, + ["Ether Holly"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Dried Marjoram", + "Holly Lumber", + "Ahriman Wing", + "Treant Bulb", + "Distilled Water", + }, + }, + ["Ether Leather"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Dried Marjoram", + "Ram Leather", + "Ahriman Wing", + "Treant Bulb", + "Distilled Water", + }, + }, + ["Ether Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Brass Tank", + "Ether", + "Ether", + "Ether", + "Ether", + }, + }, + ["Ethereal Oak Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Log", + "Ice Anima", + "Wind Anima", + "Dark Anima", + }, + }, + ["Ethereal Vermilion Lacquer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Sulfur", + "Lightning Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Etoile Gorget"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Pelt", + "Dark Matter", + "S. Faulpie Leather", + "Sunstone Crystal", + "Moldy Gorget", + }, + }, + ["Etoile Knife"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Horn", + "Dark Matter", + "Ruthenium Ore", + "Moldy Dagger", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Sunstone Crystal", + }, + }, + ["Etourdissante"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "P. Brass Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Durium Ingot", + "Buffalo Leather", + "Paralyze Potion", + }, + }, + ["Evader Earring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "P. Brass Ingot", + "P. Brass Ingot", + }, + }, + ["Exactitude Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Lizard Skin", + "Immortal Molt", + }, + }, + ["Exalted Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Akaso Thread", + "Akaso Cloth", + "Exalted Lumber", + "Exalted Lumber", + }, + }, + ["Exalted Crossbow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Akaso Thread", + "Bismuth Ingot", + "Exalted Lumber", + }, + }, + ["Exalted Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Exalted Log", + }, + }, + ["Exalted Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bundling Twine", + "Exalted Log", + "Exalted Log", + "Exalted Log", + }, + }, + ["Exalted Spear"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Akaso Thread", + "Exalted Lumber", + "Ra'Kaznar Ingot", + }, + }, + ["Exalted Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Exalted Lumber", + "Exalted Lumber", + }, + }, + ["Exorcismal Oak Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Ice Anima", + "Earth Anima", + "Light Anima", + }, + }, + ["Eye Drops"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Chamomile", + "Ahriman Tears", + "Distilled Water", + }, + }, + ["Eye Drops 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Chamomile", + "Chamomile", + "Ahriman Tears", + "Ahriman Tears", + "Triturator", + "Distilled Water", + }, + }, + ["Eyeball Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Apple Vinegar", + "Beastman Blood", + "Hecteyes Eye", + "Hecteyes Eye", + "Hecteyes Eye", + "Gelatin", + "Frost Turnip", + "Distilled Water", + }, + }, + ["Faceguard"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Sheep Leather", + }, + }, + ["Fairweather Fetish"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Saruta Cotton", + "Bast Parchment", + }, + }, + ["Falchion"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + }, + }, + ["Falsiam Vase"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Darksteel Ingot", + "Tin Ingot", + }, + }, + ["Falx"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Mythril Ingot", + "Holly Lumber", + "Pearl", + "Dhalmel Leather", + }, + }, + ["Fane Baselard"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Adaman", + "Dweomer Steel", + }, + }, + ["Fane Hexagun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Ebony Lumber", + "Ebony Lumber", + "Silver Ingot", + "Dweomer Steel", + }, + }, + ["Fang Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Yagudo Fltchg.", + "Fang Arrowhd.", + }, + }, + ["Fang Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Blk. Tiger Fang", + }, + }, + ["Fang Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Blk. Tiger Fang", + "Blk. Tiger Fang", + "Blk. Tiger Fang", + "Shagreen File", + }, + }, + ["Fang Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Blk. Tiger Fang", + "Blk. Tiger Fang", + }, + }, + ["Fang Necklace"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Bone Chip", + "Bone Chip", + "Blk. Tiger Fang", + "Bat Fang", + "Bat Fang", + "Bat Fang", + "Bat Fang", + }, + }, + ["Fang Necklace 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone. Kit 15", + }, + }, + ["Fastwater Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Fast. Rod", + }, + }, + ["Fastwater Fishing Rod 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 55", + }, + }, + ["Fastwater Fishing Rod 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elm Lumber", + "Wool Thread", + }, + }, + ["Faulpie Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Distilled Water", + "S. Faulpie Leather", + }, + }, + ["Faulpie Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Distilled Water", + "S. Faulpie Leather", + }, + }, + ["Faussar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mahogany Lbr.", + "Lizard Skin", + }, + }, + ["Fay Crozier"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gargouille Eye", + "Feywld. Lumber", + }, + }, + ["Fay Gendawa"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Rainbow Cloth", + "Rafflesia Vine", + "Gargouille Horn", + "Feywld. Lumber", + }, + }, + ["Fay Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Ash Lumber", + "Feywld. Lumber", + }, + }, + ["Fay Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Turquoise", + "Gargouille Horn", + "Feywld. Lumber", + }, + }, + ["Feasting Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Teak Lumber", + "Teak Lumber", + "Jacaranda Lbr.", + }, + }, + ["Feather Collar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Cloth", + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Bird Feather", + "Bird Feather", + }, + }, + ["Federal Mercenary's Hammock"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Lauan Lumber", + "Holly Lumber", + "Holly Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Wisteria Lumber", + }, + }, + ["Felicifruit Gelatin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Maple Sugar", + "Gelatin", + "San d'Or. Grape", + "Distilled Water", + "Felicifruit", + "Felicifruit", + }, + }, + ["Feyweald Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Feyweald Log", + }, + }, + ["Fictile Pot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Holly Lumber", + "Kaolin", + "Kaolin", + }, + }, + ["Field Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Grass Cloth", + "Ram Leather", + "Ram Leather", + }, + }, + ["Field Boots 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 40", + }, + }, + ["Field Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Dhalmel Leather", + "Ram Leather", + }, + }, + ["Field Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Linen Cloth", + "Wool Cloth", + "Wool Cloth", + }, + }, + ["Field Tunica"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Linen Cloth", + "Wool Cloth", + "Wool Cloth", + "Sheep Leather", + "Ram Leather", + }, + }, + ["Fighting Fish Tank"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Lauan Lumber", + "Crawler Calculus", + "Sieglinde Putty", + "Glass Sheet", + "Goldfish Set", + "Lamp Marimo", + "Betta", + }, + }, + ["Fin Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Kalkanbaligi", + "Ground Wasabi", + }, + }, + ["Fine Linen Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Thread", + "Linen Thread", + "Wind Anima", + "Earth Anima", + "Light Anima", + }, + }, + ["Fine Parchment"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Parchment", + "Pumice Stone", + }, + }, + ["Finesse Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coquecigr. Skin", + "Beak Gloves", + }, + }, + ["Fire Anima"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Burning Memory", + "Burning Memory", + "Burning Memory", + "Burning Memory", + }, + }, + ["Fire Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Fire Arrowheads", + "Bird Fletchings", + }, + }, + ["Fire Arrowheads"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Slime Oil", + "Iron Ingot", + "Grass Cloth", + }, + }, + ["Fire Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Fire Ore", + }, + }, + ["Fire Biscuit"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Kazham Peppers", + "Selbina Butter", + "Crawler Egg", + "Honey", + "Acorn", + "Acorn", + "Acorn", + }, + }, + ["Fire Bracers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Incomb. Wool", + "Wool Bracers", + }, + }, + ["Fire Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Fire Cluster", + }, + }, + ["Fire Fewell"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Slime Oil", + "Red Rock", + "Catalytic Oil", + }, + }, + ["Fire Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fire Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Fire Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Fire Bead", + }, + }, + ["Fire Sword"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Firesand", + "Iron Sword", + }, + }, + ["Firesand"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bomb Ash", + "Bomb Ash", + "Yuhtunga Sulfur", + }, + }, + ["Firesand 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bomb Ash", + "Bomb Ash", + "Sulfur", + }, + }, + ["Firesand 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Sulfur", + "Sulfur", + "Triturator", + }, + }, + ["Firesand 4"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Alch. Kit 40", + }, + }, + ["Firesand 5"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sulfur", + "Cluster Ash", + }, + }, + ["Firesand 6"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sulfur", + "Djinn Ash", + }, + }, + ["Firnaxe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Thokcha Ingot", + "Heavy Dst. Axe", + }, + }, + ["Fish Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Bastore Sardine", + "Bastore Sardine", + "Bastore Sardine", + "Bastore Sardine", + }, + }, + ["Fish Broth 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Hamsi", + "Hamsi", + "Hamsi", + "Hamsi", + }, + }, + ["Fish Broth 3"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Senroh Sardine", + "Senroh Sardine", + "Senroh Sardine", + "Senroh Sardine", + }, + }, + ["Fish Broth 4"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Uskumru", + "Uskumru", + }, + }, + ["Fish Broth 5"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Bluetail", + "Bluetail", + }, + }, + ["Fish Broth 6"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Uskumru", + "Uskumru", + }, + }, + ["Fish Broth 7"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Lakerda", + }, + }, + ["Fish Broth 8"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gugru Tuna", + }, + }, + ["Fish Mithkabob"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bastore Sardine", + "Nebimonite", + "Bluetail", + "Shall Shell", + "Shall Shell", + }, + }, + ["Fish Mithkabob 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hamsi", + "Uskumru", + "Ahtapot", + "Istiridye", + "Istiridye", + }, + }, + ["Fish Scales"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Gavial Fish", + }, + }, + ["Fish and Chips"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Popoto", + "Apple Vinegar", + "Olive Oil", + "Tiger Cod", + "Tiger Cod", + "Bird Egg", + "Moval. Water", + }, + }, + ["Fish and Chips 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Popoto", + "Apple Vinegar", + "Olive Oil", + "Blindfish", + "Bird Egg", + "Moval. Water", + }, + }, + ["Fisherman's Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Grass Cloth", + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Fisherman's Boots 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 20", + }, + }, + ["Fisherman's Feast"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tonosama R.Ball", + "Sausage", + "Sausage", + "Salmon Rice Ball", + "Apkallu Egg", + "Graubg. Lettuce", + "Winterflower", + }, + }, + ["Fisherman's Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Fisherman's Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Fisherman's Tunica"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + "Linen Cloth", + "Sheep Leather", + }, + }, + ["Fisherman's Tunica 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 30", + }, + }, + ["Fizzy Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Millioncorn", + "Pine Nuts", + "Lucerewe Meat", + }, + }, + ["Flamberge"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Mahogany Lbr.", + "Cockatrice Skin", + }, + }, + ["Flame Blade"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Firesand", + "Falchion", + }, + }, + ["Flame Claymore"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Iron Ingot", + "Claymore", + }, + }, + ["Flame Degen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Firesand", + "Degen", + }, + }, + ["Flame Holder"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Slime Oil", + "Cotton Thread", + "Beeswax", + "Wyvern Skin", + "Super Cermet", + "Cluster Arm", + }, + }, + ["Flame Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fire Bead", + "Orichalcum Ring", + }, + }, + ["Flanged Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Darksteel Ingot", + "Mahogany Lbr.", + "Gold Ingot", + "Smildn. Leather", + }, + }, + ["Flashbulb"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Glass Fiber", + "Sieglinde Putty", + "Glass Sheet", + "Lamp Marimo", + "Water Tank", + }, + }, + ["Flax Headband"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Carbon Fiber", + }, + }, + ["Flaxseed Oil"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Flax Flower", + "Flax Flower", + }, + }, + ["Flete Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Kapor Lumber", + "Kapor Lumber", + "Scintillant Ingot", + }, + }, + ["Fleuret"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Silver Ingot", + "Light Opal", + }, + }, + ["Flexible Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lam. Water Cell", + "Lam. Earth Cell", + "Holly Pole", + }, + }, + ["Flint Caviar"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Rock Salt", + "Emperor Roe", + }, + }, + ["Flint Glass Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Shell Powder", + "Silica", + "Silica", + "Silica", + "Silica", + "Minium", + "Minium", + }, + }, + ["Floral Nightstand"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Ebony Lumber", + "Gold Ingot", + }, + }, + ["Flounder Meuniere"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Selbina Milk", + "Dil", + }, + }, + ["Flounder Meuniere 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Selbina Milk", + "Black Sole", + }, + }, + ["Flower Stand"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Yew Lumber", + }, + }, + ["Fluorite"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ramuite", + }, + }, + ["Fluorite Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fluorite", + "Gold Ring", + }, + }, + ["Fluorite Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fluorite", + "Gold Ring +1", + }, + }, + ["Fluoro-flora"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Tufa", + "Red Gravel", + "Orobon Lure", + "Wildgrass Seeds", + "Super Ether", + "Humus", + }, + }, + ["Flute"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Lumber", + "Parchment", + }, + }, + ["Fly Lure"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chocobo Fthr.", + "Bat Fang", + "Animal Glue", + }, + }, + ["Focus Collar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Chain", + "Flawed Garnet", + }, + }, + ["Foppish Tunica"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Thread", + "Silk Cloth", + "Celaeno's Cloth", + "Penelope's Cloth", + "Defiant Scarf", + "Defiant Scarf", + }, + }, + ["Foulard"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Thread", + "Silk Thread", + "Rainbow Thread", + "Rainbow Thread", + "Arachne Thread", + }, + }, + ["Foulweather Frog"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Caedarva Frog", + }, + }, + ["Foulweather Frog 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Elshimo Frog", + }, + }, + ["Fowler's Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Woolly Pelage", + }, + }, + ["Fragrant Dhalmel Hide"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dhalmel Hide", + "Wind Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Fragrant Ram Skin"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ram Skin", + "Wind Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Freshwater Aquarium"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Petrified Log", + "Oak Lumber", + "Sieglinde Putty", + "Glass Sheet", + "Freshwater Set", + "Pipira", + "Pipira", + "Pipira", + }, + }, + ["Freshwater Set"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Silica", + "River Foliage", + "Desalinator", + "Holy Water", + }, + }, + ["Fried Pototo"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Olive Oil", + "White Bread", + "Bird Egg", + }, + }, + ["Frigid Core"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Adaman Ore", + "Adaman Ore", + "Adaman Ore", + "Ice Anima", + "Ice Anima", + "Dark Anima", + }, + }, + ["Frigid Orichalcum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + "Ice Anima", + "Ice Anima", + "Dark Anima", + }, + }, + ["Frigid Skin"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Raptor Skin", + "Ice Anima", + "Ice Anima", + "Dark Anima", + }, + }, + ["Frizzante Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Hare Meat", + "Karakul Meat", + "Ziz Meat", + }, + }, + ["Frog Lure"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Glass Fiber", + "Copper Frog", + }, + }, + ["Frosty Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brilliant Snow", + "Snowman Cap", + }, + }, + ["Fruit Parfait"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Sugar", + "Apple Mint", + "Faerie Apple", + "Saruta Orange", + "Kazham Pineapl.", + "Yagudo Cherry", + "Pamamas", + "Uleguerand Milk", + }, + }, + ["Fuma Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Mythril Sheet", + "Gold Ingot", + "Mercury", + }, + }, + ["Furusumi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Kapor Log", + "Animal Glue", + "Distilled Water", + "Soot", + }, + }, + ["Fusion Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Aluminum Ingot", + }, + }, + ["Futhark Claymore"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Defiant Scarf", + "Dark Matter", + "Niobium Ore", + "Moldy G. Sword", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Apatite Crystal", + }, + }, + ["Futhark Torque"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Waktza Crest", + "Dark Matter", + "Khoma Thread", + "Apatite Crystal", + "Moldy Torque", + }, + }, + ["Gaia Doublet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Earth Doublet", + }, + }, + ["Gaia Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cockatrice Skin", + "Earth Mantle", + }, + }, + ["Gaiters"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + }, + }, + ["Gallipot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Walnut Log", + "Bamboo Stick", + "Silica", + "Djinn Ash", + "Karugo Clay", + "Karugo Clay", + "Karugo Clay", + "Karugo Clay", + }, + }, + ["Gambison"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Garden Bangles"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Mercury", + "Dryad Root", + "Fiend Blood", + "Grt. Boyahda Moss", + "4Lf. Korrin Bud", + }, + }, + ["Gargouille Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Gargouille Horn", + }, + }, + ["Gargouille Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Shagreen File", + "Gargouille Horn", + "Gargouille Horn", + "Gargouille Horn", + }, + }, + ["Garish Crown"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Molt", + "Beetle Jaw", + "Coeurl Whisker", + "Bloodthread", + }, + }, + ["Garish Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Saruta Cotton", + "Sheep Leather", + "Scarlet Linen", + "Bloodthread", + }, + }, + ["Garish Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Scarlet Linen", + "Scarlet Linen", + "Bloodthread", + "Bloodthread", + }, + }, + ["Garish Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Sheep Leather", + "Bloodthread", + }, + }, + ["Garish Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Velvet Cloth", + "Sheep Leather", + "Scarlet Linen", + "Scarlet Linen", + "Scarlet Linen", + "Bloodthread", + }, + }, + ["Garlic Cracker"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Tarutaru Rice", + "Rock Salt", + "Distilled Water", + }, + }, + ["Garnet Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Garnet", + "Mythril Ring", + }, + }, + ["Garnet Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Garnet", + "Mythril Ring +1", + }, + }, + ["Gateau aux Fraises"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Rolanberry", + "Rolanberry", + "Selbina Milk", + "Distilled Water", + "Bird Egg", + }, + }, + ["Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Gavial Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Titanictus Shell", + "H.Q. Pugil Scls.", + "Leather Trousers", + }, + }, + ["Gavial Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Titanictus Shell", + "H.Q. Pugil Scls.", + "Leather Gloves", + }, + }, + ["Gavial Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Titanictus Shell", + "H.Q. Pugil Scls.", + "Leather Highboots", + }, + }, + ["Gavial Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Sheep Leather", + "Titanictus Shell", + "Titanictus Shell", + "H.Q. Pugil Scls.", + "H.Q. Pugil Scls.", + "Leather Vest", + }, + }, + ["Gavial Mask"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheep Leather", + "Titanictus Shell", + "H.Q. Pugil Scls.", + }, + }, + ["Gefechtbrust"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Mercury", + "Cerber. Leather", + "Largantua's Shard", + "Largantua's Shard", + "Malatrix's Shard", + "Malatrix's Shard", + }, + }, + ["Gefechtdiechlings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Buffalo Leather", + "Cerber. Leather", + "Largantua's Shard", + "Malatrix's Shard", + }, + }, + ["Gefechthentzes"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Mercury", + "Largantua's Shard", + "Malatrix's Shard", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Gefechtschaller"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Mercury", + "Cerber. Leather", + "Scintillant Ingot", + "Umbril Ooze", + "Largantua's Shard", + "Malatrix's Shard", + }, + }, + ["Gefechtschuhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Mercury", + "Buffalo Leather", + "Cerber. Leather", + "Largantua's Shard", + "Malatrix's Shard", + }, + }, + ["Gelatin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Chicken Bone", + "Chicken Bone", + "Distilled Water", + }, + }, + ["Gelatin 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Distilled Water", + }, + }, + ["Gelatin 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Giant Femur", + "Distilled Water", + }, + }, + ["Gemshorn"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Giant Femur", + "Beetle Jaw", + }, + }, + ["Gendawa"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Ancient Lumber", + "Rainbow Cloth", + "Coeurl Whisker", + "Taurus Horn", + }, + }, + ["General's Shield"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Gold Ingot", + "Platinum Sheet", + "Sheep Leather", + "Mercury", + }, + }, + ["Gerdr Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ocl. Chain", + "Faulpie Leather", + "Faulpie Leather", + "Wyrm Ash", + }, + }, + ["Ghillie Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Ruszor Fang", + "Ruszor Fang", + }, + }, + ["Ghost Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Velvet Cloth", + "Spectral Serum", + }, + }, + ["Giant Bird Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "G. Bird Plume", + "G. Bird Plume", + }, + }, + ["Giant Bird Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "G. Bird Plume", + "G. Bird Plume", + "G. Bird Plume", + "G. Bird Plume", + "G. Bird Plume", + "G. Bird Plume", + "Zephyr Thread", + }, + }, + ["Gilded Chest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Gold Ingot", + }, + }, + ["Gilded Shelf"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Gimlet Spear"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Bronze Spear", + }, + }, + ["Ginger Cookie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Ginger", + "Maple Sugar", + "Lizard Egg", + "Distilled Water", + }, + }, + ["Ginger Cookie 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Ginger", + "Maple Sugar", + "Distilled Water", + "Bird Egg", + }, + }, + ["Girandola"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Beeswax", + "Beeswax", + }, + }, + ["Gladius"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Ram Horn", + }, + }, + ["Glass Fiber"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Goblin Mask", + }, + }, + ["Glass Fiber 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Moblin Mask", + }, + }, + ["Glass Fiber 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Flint Stone", + "Flint Stone", + "Flint Stone", + "Flint Stone", + "Flint Stone", + "Flint Stone", + "Flint Stone", + "Flint Stone", + }, + }, + ["Glass Fiber 4"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Meteorite", + }, + }, + ["Glass Fiber Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Glass Rod", + }, + }, + ["Glass Fiber Fishing Rod 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cotton Thread", + "Glass Fiber", + "Glass Fiber", + "Glass Fiber", + "Glass Fiber", + }, + }, + ["Glass Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Shell Powder", + "Silica", + "Silica", + "Silica", + "Silica", + "Silica", + "Silica", + }, + }, + ["Glossy Bugard Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Bugard Skin", + "Wind Anima", + "Wind Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Glossy Bugard Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Bugard Skin", + "Wind Anima", + "Wind Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Glowfly Cage"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Rattan Lumber", + "Rattan Lumber", + "Dogwd. Lumber", + "Glowfly", + }, + }, + ["Gnat Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gnat Wing", + "Gnat Wing", + }, + }, + ["Gnat Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Gnat Wing", + "Gnat Wing", + "Gnat Wing", + "Gnat Wing", + "Gnat Wing", + "Gnat Wing", + }, + }, + ["Gnole Sainti"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Gnole Claw", + "Gnole Claw", + "Teak Lumber", + }, + }, + ["Goblin Bread"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Horo Flour", + "Bone Chip", + "Rock Salt", + "Poison Flour", + "Crawler Egg", + "Puffball", + "Distilled Water", + }, + }, + ["Goblin Bug Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Rotten Meat", + "Lugworm", + "Shell Bug", + "Shell Bug", + }, + }, + ["Goblin Chocolate"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Kukuru Bean", + "Kukuru Bean", + "Kukuru Bean", + "Wijnruit", + "Honey", + "Selbina Milk", + "Cobalt Jellyfish", + "Sunflower Seeds", + }, + }, + ["Goblin Coif"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Linen Cloth", + "Undead Skin", + "Sheep Leather", + "Artificial Lens", + "Artificial Lens", + "Moblin Thread", + "Goblin Cutting", + }, + }, + ["Goblin Drink"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "La Theine Cbg.", + "Frost Turnip", + "Wild Onion", + "San d'Or. Carrot", + "Watermelon", + "Distilled Water", + "Gysahl Greens", + "Elshimo Newt", + }, + }, + ["Goblin Mushpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Rock Salt", + "Sleepshroom", + "Danceshroom", + "Scream Fungus", + "Distilled Water", + "Sobbing Fungus", + "Deathball", + }, + }, + ["Goblin Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Ginger", + "Black Pepper", + "Crawler Egg", + "Honey", + "Eggplant", + "Crayfish", + "Sunflower Seeds", + }, + }, + ["Goblin Stew"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Horo Flour", + "Chicken Bone", + "Fish Bones", + "Fiend Blood", + "Rock Salt", + "Puffball", + "Distilled Water", + "Rotten Meat", + }, + }, + ["Goblin Stir-Fry"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Ginger", + "Olive Oil", + "Trilobite", + "Hare Meat", + "La Theine Cbg.", + "Eggplant", + "Rarab Tail", + }, + }, + ["Gold Algol"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Divine Lumber", + "Gold Ingot", + "Gold Ingot", + "Super Cermet", + "Super Cermet", + "Super Cermet", + "Super Cermet", + "Scintillant Ingot", + }, + }, + ["Gold Armet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Gold Ingot", + "Sheep Leather", + "Mercury", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Gold Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Yagudo Fltchg.", + "Gold Arrowheads", + }, + }, + ["Gold Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Gold Ingot", + }, + }, + ["Gold Bangles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Gold Bangles 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 70", + }, + }, + ["Gold Brocade"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Thread", + "Rainbow Thread", + "Rainbow Thread", + "Gold Thread", + "Gold Thread", + }, + }, + ["Gold Buckler"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Targe", + }, + }, + ["Gold Buckler 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 80", + }, + }, + ["Gold Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Firesand", + }, + }, + ["Gold Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Gold Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Mandrel", + }, + }, + ["Gold Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Ram Leather", + "Ram Leather", + "Mercury", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Gold Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Ram Leather", + "Mercury", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Gold Dust"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Brass Ingot", + }, + }, + ["Gold Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Gold Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Cermet Chunk", + "Cermet Chunk", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Gold Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Ingot", + }, + }, + ["Gold Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Beastcoin", + "Gold Beastcoin", + "Gold Beastcoin", + "Gold Beastcoin", + }, + }, + ["Gold Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ore", + "Gold Ore", + "Gold Ore", + "Gold Ore", + }, + }, + ["Gold Ingot 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ore", + "Gold Nugget", + "Gold Nugget", + "Gold Nugget", + "Gold Nugget", + "Gold Nugget", + "Gold Nugget", + }, + }, + ["Gold Nugget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Auric Sand", + "Auric Sand", + "Auric Sand", + "Auric Sand", + }, + }, + ["Gold Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Gold Thread", + }, + }, + ["Gold Obi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 70", + }, + }, + ["Gold Patas"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Patas", + }, + }, + ["Gold Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Gold Sabatons"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Ram Leather", + "Ram Leather", + "Mercury", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Gold Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + }, + }, + ["Gold Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Workshop Anvil", + }, + }, + ["Gold Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Mercury", + "Saber", + }, + }, + ["Gold Thread"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Silk Thread", + }, + }, + ["Gold Thread 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Silk Thread", + "Silk Thread", + "Silk Thread", + "Spindle", + }, + }, + ["Golden Coil"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Mandrel", + }, + }, + ["Golden Gear"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Gold Sheet", + }, + }, + ["Golden Spear"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Partisan", + }, + }, + ["Goldfish Bowl"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Lauan Lumber", + "Crawler Calculus", + "Sieglinde Putty", + "Glass Sheet", + "Goldfish Set", + "Tiny Goldfish", + "Blk. Bubble-Eye", + }, + }, + ["Goldsmithing Set 25"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Silver Ingot", + "Lizard Belt", + }, + }, + ["Goldsmithing Set 45"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Peridot", + "Mythril Earring", + }, + }, + ["Goldsmithing Set 65"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Moonstone", + "Gold Earring", + }, + }, + ["Goldsmithing Set 70"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Goldsmithing Set 75"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Thread", + "Uchigatana", + }, + }, + ["Goldsmithing Set 80"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Targe", + }, + }, + ["Goldsmithing Set 85"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + }, + }, + ["Goldsmithing Set 90"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Gold Sheet", + "Emerald", + "Ruby", + "Diamond", + "Topaz", + "Sapphire", + "Spinel", + "Torque", + }, + }, + ["Goldsmithing Set 94"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Ph. Gold Ingot", + "Ph. Gold Ingot", + }, + }, + ["Gorget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Sheep Leather", + }, + }, + ["Gorkhali Kukri"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Thokcha Ingot", + "Griffon Leather", + }, + }, + ["Goshenite Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Goshenite", + "Mythril Earring", + }, + }, + ["Goshenite Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Goshenite", + "Mythril Earring +1", + }, + }, + ["Goshenite Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Goshenite", + "Mythril Ring", + }, + }, + ["Goshenite Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Goshenite", + "Mythril Ring +1", + }, + }, + ["Goulash"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Coeurl Meat", + "Mithran Tomato", + "Distilled Water", + "Paprika", + }, + }, + ["Goulash 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Mithran Tomato", + "Distilled Water", + "Lynx Meat", + "Paprika", + }, + }, + ["Gracile Grip"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mandrel", + "Rhodium Ingot", + "Waktza Crest", + }, + }, + ["Grape Daifuku"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Sticky Rice", + "Cornstarch", + "Distilled Water", + "Royal Grape", + "Royal Grape", + "Azuki Bean", + }, + }, + ["Grape Juice"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "San d'Or. Grape", + "San d'Or. Grape", + "San d'Or. Grape", + "San d'Or. Grape", + }, + }, + ["Grass Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Thread", + "Grass Thread", + }, + }, + ["Grass Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Moko Grass", + "Moko Grass", + }, + }, + ["Grass Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Moko Grass", + "Moko Grass", + "Moko Grass", + "Moko Grass", + "Moko Grass", + "Moko Grass", + "Spindle", + }, + }, + ["Grasshopper Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Skull Locust", + "Skull Locust", + "King Locust", + "Mushrm. Locust", + "La Theine Cbg.", + "Gysahl Greens", + }, + }, + ["Great Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Chestnut Lumber", + "Velvet Cloth", + "Scorpion Claw", + "Coeurl Whisker", + }, + }, + ["Great Club"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Mahogany Lbr.", + }, + }, + ["Greataxe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Mythril Ingot", + "Holly Lumber", + }, + }, + ["Greatsword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Holly Lumber", + "Dhalmel Leather", + }, + }, + ["Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Chain", + "Ram Leather", + }, + }, + ["Green 3-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "3-Drawer Almirah", + "Gold Thread", + "Green Text. Dye", + }, + }, + ["Green 6-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "6-Drawer Almirah", + "Gold Thread", + "Green Text. Dye", + }, + }, + ["Green 9-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "9-Drawer Almirah", + "Gold Thread", + "Green Text. Dye", + }, + }, + ["Green Beret"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Cloth", + "Silk Cloth", + "Chocobo Fthr.", + "Giant Bird Fthr.", + }, + }, + ["Green Curry"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blue Peas", + "Bay Leaves", + "Curry Powder", + "Holy Basil", + "Crayfish", + "Distilled Water", + "Beaugreens", + }, + }, + ["Green Curry Bun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Olive Oil", + "Green Curry", + "Bird Egg", + }, + }, + ["Green Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Jadeite", + "Gold Earring", + }, + }, + ["Green Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Jadeite", + "Gold Earring +1", + }, + }, + ["Green Hobby Bo"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Hickory Lumber", + "Dogwd. Lumber", + "Onyx", + "Onyx", + "Grn. Chocobo Dye", + }, + }, + ["Green Mahogany Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mahogany Bed", + "Wool Thread", + "Green Text. Dye", + }, + }, + ["Green Noble's Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Noble's Bed", + "Gold Thread", + "Green Text. Dye", + }, + }, + ["Green Quiche"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Rock Salt", + "Danceshroom", + "Selbina Milk", + "Stone Cheese", + "Bird Egg", + "Beaugr. Saute", + }, + }, + ["Green Quiche 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 60", + }, + }, + ["Green Ribbon"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silk Cloth", + }, + }, + ["Green Round Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Linen Cloth", + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Platinum Silk", + "Teak Lumber", + "Green Text. Dye", + }, + }, + ["Green Storm Lantern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Brass Ingot", + "Silver Ingot", + "Silk Cloth", + "Glass Sheet", + "Sailcloth", + "Green Text. Dye", + }, + }, + ["Green Tarutaru Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Tarutaru Desk", + "Green Text. Dye", + }, + }, + ["Green Tarutaru Standing Screen"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Taru F. Screen", + "Green Text. Dye", + }, + }, + ["Green Textile Dye"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Im. Tea Leaves", + }, + }, + ["Grenade"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Ash Lumber", + "Bomb Ash", + "Yuhtunga Sulfur", + "Firesand", + }, + }, + ["Grenade 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Ash Lumber", + "Bomb Ash", + "Firesand", + "Sulfur", + }, + }, + ["Grenade 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Ash Lumber", + "Firesand", + "Firesand", + "Cluster Ash", + }, + }, + ["Griffon Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Griffon Hide", + "Distilled Water", + }, + }, + ["Griffon Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Griffon Hide", + "Distilled Water", + }, + }, + ["Grilled Hare"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Hare Meat", + }, + }, + ["Griot Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Chain", + "Silver Chain", + "Qdv. Silv. Ingot", + }, + }, + ["Guatambu Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Guatambu Log", + }, + }, + ["Guatambu Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bundling Twine", + "Guatambu Log", + "Guatambu Log", + "Guatambu Log", + }, + }, + ["Gueridon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Rosewood Lbr.", + "Gold Ingot", + }, + }, + ["Gully"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Mahogany Lbr.", + }, + }, + ["Gully 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 91", + }, + }, + ["Gust Claymore"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tin Ingot", + "Iron Sheet", + "Claymore", + }, + }, + ["Gust Sword"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tin Ingot", + "Steel Sheet", + "Greatsword", + }, + }, + ["Gust Tongue"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tin Ingot", + "Darksteel Sheet", + "Flamberge", + }, + }, + ["Gysahl Bomb"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Firesand", + "Bast Parchment", + "Gysahl Greens", + }, + }, + ["Gyudon"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ginger", + "Tarutaru Rice", + "Soy Stock", + "Wild Onion", + "Buffalo Meat", + "Cotton Tofu", + "Shungiku", + "Shirataki", + }, + }, + ["Hachimaki"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Grass Cloth", + "Grass Cloth", + }, + }, + ["Hachiman Domaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Darksteel Chain", + "Darksteel Chain", + "Gold Thread", + "Tiger Leather", + "Viridian Urushi", + "Dark Scales", + "Dark Scales", + }, + }, + ["Hachiman Hakama"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Chain", + "Darksteel Chain", + "Gold Thread", + "Velvet Cloth", + "Scarlet Linen", + "Kejusu Satin", + }, + }, + ["Hachiman Jinpachi"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Sheet", + "Adaman Chain", + "Silk Cloth", + "Urushi", + "Kejusu Satin", + }, + }, + ["Hachiman Kote"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Chain", + "Darksteel Chain", + "Gold Ingot", + "Tiger Leather", + "Viridian Urushi", + }, + }, + ["Hachiman Sune-Ate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Darksteel Sheet", + "Darksteel Sheet", + "Gold Ingot", + "Rainbow Thread", + "Velvet Cloth", + "Tiger Leather", + "Mercury", + }, + }, + ["Hades Sainti"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Bldwd. Lumber", + "Cerberus Claw", + "Cerberus Claw", + }, + }, + ["Haidate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Silk Thread", + "Silk Cloth", + "Sheep Leather", + }, + }, + ["Hailstorm Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Monsoon Tekko", + }, + }, + ["Hajduk Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Khimaira Horn", + "Khimaira Horn", + }, + }, + ["Hakutaku Eye Cluster"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Fiend Blood", + "Wooden Hktk. Eye", + "Burning Hktk. Eye", + "Earthen Hktk. Eye", + "Golden Hktk. Eye", + "Damp Hktk. Eye", + }, + }, + ["Halberd"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Ingot", + "Ash Lumber", + "Wool Thread", + }, + }, + ["Halcyon Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Halcyon Rod", + }, + }, + ["Halcyon Rod 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Glass Fiber", + "Glass Fiber", + }, + }, + ["Half Partition"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + }, + }, + ["Hallowed Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hallowed Water", + "Divine Sword", + }, + }, + ["Hallowed Water"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Fire Anima", + "Ice Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Halo Claymore"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Mythril Claymore", + }, + }, + ["Ham and Ch. Crepe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Mhaura Garlic", + "Mithran Tomato", + "Bird Egg", + "Sausage", + "Chalaimbille", + "Uleguerand Milk", + }, + }, + ["Hammermill"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Coeurl Whisker", + "Goblin Grease", + "Myth.Gear Mach.", + "Warhammer", + "Warhammer", + "Wind Fan", + }, + }, + ["Hanafubuki"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Sakurafubuki", + }, + }, + ["Handgonne"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Thokcha Ingot", + "Wyrm Horn", + }, + }, + ["Hanger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Happo Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Mercury", + "Waktza Rostrum", + "Bismuth Sheet", + }, + }, + ["Hara-Ate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Iron Sheet", + "Iron Chain", + "Iron Chain", + "Silk Thread", + "Silk Cloth", + "Sheep Leather", + }, + }, + ["Hard Leather Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Leath. Kit 60", + }, + }, + ["Hard Leather Ring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tiger Leather", + }, + }, + ["Hard-boiled Egg"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lizard Egg", + "Distilled Water", + }, + }, + ["Hard-boiled Egg 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Distilled Water", + "Bird Egg", + }, + }, + ["Harp"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Chestnut Lumber", + "Coeurl Whisker", + }, + }, + ["Harp Stool"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Mahogany Lbr.", + "Wolf Felt", + }, + }, + ["Harpoon"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Grass Thread", + "Sheep Tooth", + }, + }, + ["Haruspex Coat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Chain", + "Gold Thread", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + "Akaso Cloth", + "Raaz Leather", + }, + }, + ["Haruspex Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Silk Cloth", + "Star Sapphire", + "Star Sapphire", + "Akaso Cloth", + "Raaz Leather", + }, + }, + ["Haruspex Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Silver Thread", + "Gold Thread", + "Raxa", + "Akaso Cloth", + "Raaz Leather", + }, + }, + ["Haruspex Pigaches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Raxa", + "Akaso Cloth", + "Raaz Hide", + "Raaz Leather", + }, + }, + ["Haruspex Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Thread", + "Raxa", + "Raxa", + "Akaso Cloth", + "Raaz Leather", + }, + }, + ["Haste Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Light Ram Lth.", + "Waistbelt", + }, + }, + ["Hatchet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Maple Lumber", + }, + }, + ["Hatzoaar Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Peiste Leather", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + "Urunday Lumber", + }, + }, + ["Haubergeon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Damascus Ingot", + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Chain", + "Darksteel Chain", + "Darksteel Chain", + "Velvet Cloth", + "Silk Cloth", + }, + }, + ["Hauberk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Darksteel Chain", + "Velvet Cloth", + "Silk Cloth", + "Haubergeon", + }, + }, + ["Haunted Muleta"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Lumber", + "Spectral Crimson", + "Spect. Goldenrod", + }, + }, + ["Hawker's Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Fiend Blood", + "Beastman Blood", + "Dragon Blood", + "Archer's Knife", + }, + }, + ["Hawkeye"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Ingot", + "Yagudo Feather", + "Yagudo Feather", + "Animal Glue", + }, + }, + ["Hayabusa"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Im. Wootz Ingot", + "Manta Leather", + "Scintillant Ingot", + }, + }, + ["Headgear"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + }, + }, + ["Headgear 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cloth. Kit 5", + }, + }, + ["Healing Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Vivio Femur", + "Bone Harness", + }, + }, + ["Healing Justaucorps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Vi. Scorpion Claw", + "Justaucorps", + }, + }, + ["Healing Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Vi. Wyv. Scale", + "Dragon Mail", + }, + }, + ["Healing Vest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Vi. Sh. Leather", + "Studded Vest", + }, + }, + ["Heat Capacitor II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Fire Anima", + "Golden Coil", + "Golden Coil", + "Ocl. Gearbox", + }, + }, + ["Heat Seeker"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Lightning Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Heater Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold. Kit 55", + }, + }, + ["Heater Shield 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Kite Shield", + }, + }, + ["Heatsink"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Sieglinde Putty", + "Myth.Gear Mach.", + "Water Tank", + "Hydro Pump", + }, + }, + ["Heavy Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Oak Lumber", + }, + }, + ["Heavy Crossbow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mahogany Lbr.", + "Ebony Lumber", + "Giant Femur", + "Carbon Fiber", + }, + }, + ["Heavy Darksteel Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Mahogany Lbr.", + }, + }, + ["Hedgehog Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Pie Dough", + "Blue Peas", + "Rock Salt", + "Lizard Egg", + "King Truffle", + "San d'Or. Carrot", + "Buffalo Meat", + }, + }, + ["Heko Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Hellfire"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Walnut Lumber", + "Gold Ingot", + }, + }, + ["Hellish Bugle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Imp Horn", + "Colibri Beak", + }, + }, + ["Hellish Bugle 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone. Kit 85", + }, + }, + ["Hellsteak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Bay Leaves", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Wild Onion", + "San d'Or. Carrot", + "Cerberus Meat", + }, + }, + ["Hemolele Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Urunday Lumber", + "Chapuli Horn", + }, + }, + ["Hemp Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Grass Thread", + }, + }, + ["Hepatizon Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Urunday Lumber", + "Hepatizon Ingot", + "Hepatizon Ingot", + "Hepatizon Ingot", + }, + }, + ["Hepatizon Baghnakhs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Raaz Leather", + "Maliya. Coral Orb", + "Maliya. Coral Orb", + "Maliya. Coral Orb", + "Hepatizon Ingot", + }, + }, + ["Hepatizon Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ore", + "Mythril Ore", + "Mythril Ore", + "Hepatizon Ore", + }, + }, + ["Hepatizon Rapier"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Mercury", + "Star Sapphire", + "Hepatizon Ingot", + "Hepatizon Ingot", + }, + }, + ["Hepatizon Sapara"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Hepatizon Ingot", + "Hepatizon Ingot", + }, + }, + ["Herb Crawler Eggs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Ginger", + "Maple Sugar", + "Olive Oil", + "Crawler Egg", + "Wild Onion", + "San d'Or. Carrot", + "Distilled Water", + }, + }, + ["Herb Paste"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Toko. Wildgrass", + "Toko. Wildgrass", + "La Theine Millet", + "Lizard Egg", + "Distilled Water", + }, + }, + ["Herb Quus"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Dried Marjoram", + "Bay Leaves", + "Black Pepper", + "Rock Salt", + "Quus", + "Quus", + "Quus", + }, + }, + ["Herbal Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Frost Turnip", + "Frost Turnip", + "Beaugreens", + "Beaugreens", + }, + }, + ["Hermes Quencher"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Mugwort", + "Flytrap Leaf", + "Honey", + "Jacknife", + "Moval. Water", + }, + }, + ["Hermes' Sandals"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Karakul Leather", + "Lynx Leather", + "Dark Ixion Tail", + }, + }, + ["Heroic Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Scales", + "Ram Leather", + "Ram Leather", + "Lindwurm Skin", + }, + }, + ["Hexagun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Walnut Lumber", + "Bldwd. Lumber", + "Gold Ingot", + "Mercury", + }, + }, + ["Hexed Bliaut"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Gold Thread", + "Velvet Cloth", + "Kukulkan's Skin", + "Muculent Ingot", + "Serica Cloth", + "Serica Cloth", + }, + }, + ["Hexed Bonnet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Malboro Fiber", + "Muculent Ingot", + "Penelope's Cloth", + }, + }, + ["Hexed Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Kukulkan's Skin", + "Lynx Leather", + "Serica Cloth", + }, + }, + ["Hexed Coif"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Ethereal Squama", + "Belladonna Sap", + "Velvet Hat", + }, + }, + ["Hexed Coronet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "Freya's Tear", + "Cerber. Leather", + "A.U. Brass Ingot", + "A.U Brass Sheet", + }, + }, + ["Hexed Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Red Grs. Thread", + "Lynx Leather", + "Muculent Ingot", + "Serica Cloth", + }, + }, + ["Hexed Domaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scarletite Ingot", + "Scarletite Ingot", + "Gold Ingot", + "Taffeta Cloth", + "Urushi", + "Sealord Leather", + }, + }, + ["Hexed Doublet"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Ethereal Squama", + "Belladonna Sap", + "Belladonna Sap", + "Velvet Robe", + }, + }, + ["Hexed Gages"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Ethereal Squama", + "Belladonna Sap", + "Velvet Cuffs", + }, + }, + ["Hexed Gamashes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Malboro Fiber", + "Marid Leather", + "Befouled Silver", + "Staghorn Coral", + "Staghorn Coral", + }, + }, + ["Hexed Gambieras"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "Ormolu Ingot", + "A.U. Brass Ingot", + "Pelt of Dawon", + "Black Sollerets", + }, + }, + ["Hexed Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "A.U. Brass Ingot", + "Pelt of Dawon", + "Black Gadlings", + }, + }, + ["Hexed Hakama"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scarletite Ingot", + "Gold Ingot", + "Gold Thread", + "Taffeta Cloth", + "Red Grass Cloth", + "Sealord Leather", + "Sealord Leather", + }, + }, + ["Hexed Haubert"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "Ormolu Ingot", + "Ormolu Ingot", + "Freya's Tear", + "Bloodthread", + "A.U. Brass Ingot", + "Plastron", + }, + }, + ["Hexed Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "Behem. Leather", + "Pelt of Dawon", + "Sealord Leather", + "Sealord Leather", + }, + }, + ["Hexed Jacket"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Malboro Fiber", + "Befouled Silver", + "Penelope's Cloth", + "Staghorn Coral", + "Sealord Leather", + }, + }, + ["Hexed Kecks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Malboro Fiber", + "Taffeta Cloth", + "Penelope's Cloth", + "Staghorn Coral", + "Sealord Leather", + }, + }, + ["Hexed Mitra"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Kukulkan's Skin", + "Muculent Ingot", + "Serica Cloth", + }, + }, + ["Hexed Nails"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Ethereal Squama", + "Belladonna Sap", + "Ebony Sabots", + }, + }, + ["Hexed Slops"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Revival Root", + "Ethereal Squama", + "Belladonna Sap", + "Velvet Slops", + }, + }, + ["Hexed Somen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scarletite Ingot", + "Gold Ingot", + "Taffeta Cloth", + "Urushi", + "Sealord Leather", + }, + }, + ["Hexed Sune-Ate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scarletite Ingot", + "Gold Sheet", + "Taffeta Cloth", + "Amph. Leather", + "Sealord Leather", + }, + }, + ["Hexed Tekko"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scarletite Ingot", + "Gold Sheet", + "Durium Chain", + "Taffeta Cloth", + "Urushi", + "Sealord Leather", + }, + }, + ["Hexed Tights"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Silver Thread", + "Red Grs. Thread", + "Shagreen", + "Ethereal Squama", + "Serica Cloth", + }, + }, + ["Hexed Wristbands"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Velvet Cloth", + "Marid Leather", + "Befouled Silver", + "Staghorn Coral", + "Sealord Leather", + }, + }, + ["Heyoka Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Yggdreant Root", + "Macuil Horn", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Heyoka Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Yggdreant Root", + "Macuil Horn", + "Macuil Horn", + "Faulpie Leather", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Heyoka Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Yggdreant Root", + "Macuil Horn", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Heyoka Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Yggdreant Root", + "Macuil Horn", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Heyoka Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Yggdreant Root", + "Macuil Horn", + "Faulpie Leather", + "Faulpie Leather", + "Faulpie Leather", + }, + }, + ["Hi-Ether"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Bat Wing", + "Bat Wing", + "Bat Wing", + "Bat Wing", + "Dryad Root", + "Distilled Water", + }, + }, + ["Hi-Ether 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Dryad Root", + "Soulfl. Tentacle", + "Distilled Water", + }, + }, + ["Hi-Ether Drop"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Bat Wing", + "Bat Wing", + "Bat Wing", + "Bat Wing", + "Dryad Root", + "Distilled Water", + }, + }, + ["Hi-Ether Drop 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Dryad Root", + "Soulfl. Tentacle", + "Distilled Water", + }, + }, + ["Hi-Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Malboro Vine", + "Distilled Water", + }, + }, + ["Hi-Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Ameretat Vine", + "Distilled Water", + }, + }, + ["Hi-Potion 3"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Rafflesia Vine", + "Distilled Water", + }, + }, + ["Hi-Potion 4"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 60", + }, + }, + ["Hi-Potion Drop"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Malboro Vine", + "Distilled Water", + }, + }, + ["Hi-Potion Drop 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Ameretat Vine", + "Distilled Water", + }, + }, + ["Hi-Potion Drop 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Rafflesia Vine", + "Distilled Water", + }, + }, + ["Hibari"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Lizard Skin", + }, + }, + ["Hickory Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Hickory Lumber", + "Hickory Lumber", + }, + }, + ["Hien"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Lizard Skin", + }, + }, + ["Hien 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 70", + }, + }, + ["High Breath Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Fragrant Ram Skin", + "Ram Mantle", + }, + }, + ["High Ebonite"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Sulfur", + "Flan Meat", + "Flan Meat", + "Flan Meat", + }, + }, + ["High Healing Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Vivio Crab Shell", + "Carapace Harness", + }, + }, + ["High Mana Cloak"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mag. Silk Cloth", + "White Cloak", + }, + }, + ["High Mana Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "M. Ches. Lumber", + "Chestnut Wand", + }, + }, + ["Himantes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Raptor Skin", + "Lizard Cesti", + }, + }, + ["Himesama R. Ball"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Pamtam Kelp", + "Rock Salt", + "Distilled Water", + "Buffalo Meat", + "Burdock", + }, + }, + ["Hiraishin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Silver Ingot", + }, + }, + ["Hirenjaku"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Tama-Hagane", + "Elm Lumber", + "Ocl. Ingot", + "Ruby", + "Silk Thread", + "Manta Leather", + }, + }, + ["Holly Clogs"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Holly Lumber", + "Sheep Leather", + }, + }, + ["Holly Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Holly Log", + }, + }, + ["Holly Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Holly Log", + "Holly Log", + "Holly Log", + "Bundling Twine", + }, + }, + ["Holly Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Holly Lumber", + "Holly Lumber", + }, + }, + ["Holly Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Holly Lumber", + "Sheep Tooth", + }, + }, + ["Holy Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Holy Bolt Heads", + }, + }, + ["Holy Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Ash Lumber", + "Holy Bolt Heads", + "Holy Bolt Heads", + "Holy Bolt Heads", + "Bundling Twine", + }, + }, + ["Holy Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Holy Water", + "Holy Water", + }, + }, + ["Holy Breastplate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Blsd. Mtl. Sheet", + "Blsd. Mtl. Sheet", + "Blsd. Mtl. Sheet", + "Silver Ingot", + "Sheep Leather", + "Ram Leather", + "Ram Leather", + }, + }, + ["Holy Degen"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Mythril Degen", + }, + }, + ["Holy Lance"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Holy Water", + "Mythril Lance", + }, + }, + ["Holy Leather"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Ram Leather", + "Holy Water", + }, + }, + ["Holy Mace"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Mythril Mace", + }, + }, + ["Holy Maul"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Maul", + }, + }, + ["Holy Shield"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mana Barrel", + "Holy Water", + "Holy Water", + "Hard Shield", + }, + }, + ["Holy Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Mythril Sword", + }, + }, + ["Holy Wand"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Mythic Wand", + }, + }, + ["Holy Water"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Distilled Water", + }, + }, + ["Holy Water 2"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Triturator", + "Distilled Water", + "Distilled Water", + "Distilled Water", + }, + }, + ["Homura"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Toad Oil", + "Firesand", + "Nodachi", + }, + }, + ["Honey"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beehive Chip", + "Beehive Chip", + "Beehive Chip", + "Beehive Chip", + }, + }, + ["Honeyed Egg"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Honey", + "Bird Egg", + }, + }, + ["Hoplon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Chestnut Lumber", + "Walnut Lumber", + "Ram Leather", + }, + }, + ["Horn"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beetle Jaw", + "Ram Horn", + }, + }, + ["Horn Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Bird Fletchings", + "Horn Arrowheads", + }, + }, + ["Horn Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Ram Horn", + }, + }, + ["Horn Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Ram Horn", + "Ram Horn", + "Ram Horn", + "Shagreen File", + }, + }, + ["Horn Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ram Horn", + }, + }, + ["Horn Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Fish Scales", + "Ram Horn", + }, + }, + ["Horn Trophy"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Buffalo Horn", + "Buffalo Horn", + "Sheep Chammy", + "Teak Lumber", + }, + }, + ["Hornet Fleuret"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Pearl", + "Moonstone", + "Giant Femur", + "Giant Stinger", + }, + }, + ["Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Dhalmel Leather", + }, + }, + ["Hosodachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Tama-Hagane", + "Ash Lumber", + "Silver Ingot", + "Silver Thread", + "Raptor Skin", + "Cermet Chunk", + }, + }, + ["Hume Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Hume Rod", + }, + }, + ["Hume Fishing Rod 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Silver Thread", + }, + }, + ["Hume Fishing Rod 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 74", + }, + }, + ["Humidified Velvet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Wool Thread", + "Wool Thread", + "Earth Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Humidified Velvet 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Cotton Thread", + "Cotton Thread", + "Earth Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Humpty Dumpty"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silk Cloth", + "Rock Salt", + "Pine Nuts", + "Simsim", + "Asphodel", + "Kazham Pineapl.", + "Apkallu Egg", + "Burdock", + }, + }, + ["Humus"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Bay Leaves", + "Elm Log", + }, + }, + ["Hunter's Cotton"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Thread", + "Cotton Thread", + "Carap. Powder", + "Distilled Water", + }, + }, + ["Hunting Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Dhalmel Leather", + }, + }, + ["Hushed Baghnakhs"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Muting Potion", + "Slc. Baghnakhs", + }, + }, + ["Hushed Baghnakhs 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 20", + }, + }, + ["Hushed Dagger"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Muting Potion", + "Silence Dagger", + }, + }, + ["Hydra Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Titanictus Shell", + "Hydra Scale", + "Leather Trousers", + }, + }, + ["Hydra Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Titanictus Shell", + "Hydra Scale", + "Leather Gloves", + }, + }, + ["Hydra Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Titanictus Shell", + "Hydra Scale", + "Leather Highboots", + }, + }, + ["Hydra Kofte"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Imperial Rice", + "Imperial Flour", + "Wild Onion", + "Hydra Meat", + "Apkallu Egg", + }, + }, + ["Hydra Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Karakul Leather", + "Titanictus Shell", + "Titanictus Shell", + "Hydra Scale", + "Hydra Scale", + "Leather Vest", + }, + }, + ["Hydra Mask"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Karakul Leather", + "Titanictus Shell", + "Hydra Scale", + }, + }, + ["Hydro Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Animal Glue", + "Greataxe", + }, + }, + ["Hydro Baghnakhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Animal Glue", + "Brass Baghnakhs", + }, + }, + ["Hydro Chopper"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Animal Glue", + "Heavy Dst. Axe", + }, + }, + ["Hydro Claws"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Animal Glue", + "Claws", + }, + }, + ["Hydro Cutter"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Animal Glue", + "Heavy Axe", + }, + }, + ["Hydro Patas"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Animal Glue", + "Bone Patas", + }, + }, + ["Hydro Pump"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Chestnut Lumber", + "Coeurl Whisker", + "Carbon Fiber", + "Animal Glue", + "Water Cluster", + }, + }, + ["Hyo"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Cotton Thread", + "Velvet Cloth", + }, + }, + ["Hyper Ether"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Treant Bulb", + "Taurus Wing", + "Taurus Wing", + "Moval. Water", + }, + }, + ["Hyper Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Hecteyes Eye", + "Flytrap Leaf", + "Moval. Water", + }, + }, + ["Ic Pilav"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Black Pepper", + "Rock Salt", + "Pine Nuts", + "Imperial Rice", + "Buburimu Grape", + "Distilled Water", + "Ziz Meat", + }, + }, + ["Icarus Wing"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Giant Bird Fthr.", + "Giant Bird Fthr.", + "Giant Bird Fthr.", + "Giant Bird Fthr.", + "Giant Bird Fthr.", + "Giant Bird Fthr.", + "Beeswax", + "Beeswax", + }, + }, + ["Ice Anima"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Bitter Memory", + "Bitter Memory", + "Bitter Memory", + "Bitter Memory", + }, + }, + ["Ice Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Ice Arrowheads", + "Insect Fltchg.", + }, + }, + ["Ice Arrowheads"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Copper Ingot", + "Cermet Chunk", + }, + }, + ["Ice Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ice Ore", + }, + }, + ["Ice Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Ice Cluster", + }, + }, + ["Ice Fewell"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Slime Oil", + "Translucent Rock", + "Catalytic Oil", + }, + }, + ["Ice Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ice Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Ice Lance"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Rock Salt", + "Distilled Water", + "Cermet Lance", + }, + }, + ["Ice Maker"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Super Cermet", + "Flan Meat", + "Karakul Wool", + "Snoll Arm", + "Mega Battery", + }, + }, + ["Ice Shield"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Rock Salt", + "Distilled Water", + "Diamond Shield", + }, + }, + ["Ice Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Ice Bead", + }, + }, + ["Ice Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Frigid Skin", + "Raptor Trousers", + }, + }, + ["Icecap Rolanberry"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Maple Sugar", + "Gelatin", + "Vanilla", + "Crawler Egg", + "Rolanberry", + "Selbina Milk", + "Distilled Water", + }, + }, + ["Icecap Rolanberry 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Maple Sugar", + "Gelatin", + "Crawler Egg", + "Rolanberry", + "Selbina Milk", + "Distilled Water", + }, + }, + ["Iga Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Gold Ingot", + "P. Brass Sheet", + "Mercury", + }, + }, + ["Igqira Huaraches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Coeurl Whisker", + "Bugard Tusk", + "H.Q. Bugard Skin", + "Harajnite Shell", + }, + }, + ["Igqira Lappa"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Coeurl Whisker", + "Manticore Lth.", + "Uragnite Shell", + "H.Q. Bugard Skin", + "M-bugard Tusk", + }, + }, + ["Igqira Manillas"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Garnet", + "Manticore Hair", + "Uragnite Shell", + "Bugard Tusk", + "Avatar Blood", + }, + }, + ["Igqira Tiara"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Garnet", + "Coral Fragment", + "Coral Fragment", + "Coral Fragment", + "Manticore Hair", + }, + }, + ["Igqira Weskit"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Lapis Lazuli", + "Dhalmel Leather", + "Dragon Talon", + "Manticore Hair", + "Bugard Tusk", + "Avatar Blood", + "H.Q. Bugard Skin", + }, + }, + ["Ikra Gunkan"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Pamtam Kelp", + "Rice Vinegar", + "Distilled Water", + "Salmon Roe", + }, + }, + ["Impaction Sphere"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Frayed Arrow", + }, + }, + ["Impaction Sphere 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Papyrus", + }, + }, + ["Impaction Sphere 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Star Spinel", + }, + }, + ["Impaction Sphere 4"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Test Answers", + }, + }, + ["Impaction Sphere 5"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lightning Crest Card", + }, + }, + ["Imperial Cermet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + "Cermet Chunk", + "Silica", + }, + }, + ["Imperial Coffee"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Coffee Powder", + "Distilled Water", + }, + }, + ["Imperial Egg"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Platinum Ingot", + "Ocl. Ingot", + "Deathstone", + "Angelstone", + "Mercury", + "Pigeon's Blood", + "Bird Egg", + }, + }, + ["Imperial Silk Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Gold Thread", + "Wamoura Silk", + }, + }, + ["Imperial Tapestry"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Turquoise", + "Gold Thread", + "Gold Thread", + "Marid Hair", + "Wamoura Cloth", + "Imp. Silk Cloth", + "Imp. Silk Cloth", + }, + }, + ["Imperial Wootz Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Khroma Ore", + "Khroma Ore", + "Wootz Ore", + }, + }, + ["Incombustible Wool"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Thread", + "Wool Thread", + "Fire Anima", + "Ice Anima", + "Dark Anima", + }, + }, + ["Indurated Gold Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ore", + "Gold Ore", + "Gold Ore", + "Gold Ore", + "Earth Anima", + "Earth Anima", + "Light Anima", + }, + }, + ["Induration Sphere"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Rusty Key", + }, + }, + ["Induration Sphere 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Giant Fish Bones", + }, + }, + ["Induration Sphere 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Exoray Mold", + }, + }, + ["Induration Sphere 4"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Ice Crest Card", + }, + }, + ["Induration Sphere 5"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Teal Memosphere", + }, + }, + ["Inferno Axe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Firesand", + "Butterfly Axe", + }, + }, + ["Inferno Core"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Adaman Ore", + "Adaman Ore", + "Adaman Ore", + "Fire Anima", + "Fire Anima", + "Dark Anima", + }, + }, + ["Inferno Sabots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Namtar Bone", + "Ebony Sabots", + }, + }, + ["Inferno Sword"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Firesand", + "Two-Hand. Sword", + }, + }, + ["Inhibitor"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Fire Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Inhibitor II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Fire Anima", + "Glass Sheet", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Insect Ball"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Millioncorn", + "Distilled Water", + "Little Worm", + }, + }, + ["Insect Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Insect Wing", + "Insect Wing", + }, + }, + ["Insect Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Insect Wing", + "Insect Wing", + "Insect Wing", + "Insect Wing", + "Insect Wing", + "Insect Wing", + "Zephyr Thread", + }, + }, + ["Insipid Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Apkallufa", + "Yorchete", + "Senroh Sardine", + }, + }, + ["Intelligence Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Coeurl Whisker", + "Olive Flower", + "Dried Mugwort", + "Honey", + "Distilled Water", + }, + }, + ["Invisible Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Calig. Wolf Hide", + "Wolf Mantle", + }, + }, + ["Invitriol"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Treant Bulb", + "Treant Bulb", + "Fire Anima", + "Water Anima", + "Dark Anima", + }, + }, + ["Ioskeha Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "P. Brass Chain", + "Wyrm Blood", + "Plovid Flesh", + }, + }, + ["Iqonde Crossbow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Damascus Ingot", + "Ebony Lumber", + "Carbon Fiber", + "Craklaw Pincer", + "Yggdreant Bole", + }, + }, + ["Irenic Strap"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Behemoth Hide", + "Rockfin Fin", + }, + }, + ["Irmik Helvasi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Semolina", + "Pine Nuts", + "Selbina Milk", + "White Honey", + "White Honey", + "White Honey", + }, + }, + ["Iron Arrow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Ash Lumber", + "Chocobo Fthr.", + "Chocobo Fthr.", + }, + }, + ["Iron Arrow 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Iron Arrowheads", + "Chocobo Fltchg.", + }, + }, + ["Iron Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + }, + }, + ["Iron Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Smith. Kit 20", + }, + }, + ["Iron Bread"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Rock Salt", + "Distilled Water", + }, + }, + ["Iron Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Firesand", + }, + }, + ["Iron Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + }, + }, + ["Iron Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Mandrel", + }, + }, + ["Iron Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Scales", + "Iron Scales", + "Cotton Thread", + "Leather Trousers", + }, + }, + ["Iron Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Scales", + "Iron Scales", + "Cotton Thread", + "Leather Gloves", + }, + }, + ["Iron Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Scales", + "Iron Scales", + "Cotton Thread", + "Leather Highboots", + }, + }, + ["Iron Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Iron Ore", + }, + }, + ["Iron Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Nugget", + "Iron Nugget", + "Iron Nugget", + "Iron Nugget", + "Iron Nugget", + "Iron Nugget", + }, + }, + ["Iron Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Iron Sheet", + }, + }, + ["Iron Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Lizard Skin", + }, + }, + ["Iron Musketeer's Armet +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Irn.Msk. Armet", + }, + }, + ["Iron Musketeer's Cuirass +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Irn.Msk. Cuirass", + }, + }, + ["Iron Musketeer's Cuisses +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Irn.Msk. Cuisses", + }, + }, + ["Iron Musketeer's Gambison +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Irn.Msk. Gambison", + }, + }, + ["Iron Musketeer's Gauntlets +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Irn.Msk. Gauntlets", + }, + }, + ["Iron Musketeer's Sabatons +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Irn.Msk. Sabatons", + }, + }, + ["Iron Scale Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Scales", + "Iron Scales", + "Iron Scales", + "Iron Scales", + "Cotton Thread", + "Sheep Leather", + "Leather Vest", + }, + }, + ["Iron Scales"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Sheet", + }, + }, + ["Iron Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + }, + }, + ["Iron Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Workshop Anvil", + }, + }, + ["Iron Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Cotton Cloth", + "Lizard Skin", + }, + }, + ["Iron Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Lizard Skin", + }, + }, + ["Iron Visor"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Scales", + "Sheep Leather", + }, + }, + ["Iron-splitter"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Walnut Lumber", + "Walnut Lumber", + }, + }, + ["Isula Sideboard"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Jacaranda Lbr.", + "Jacaranda Lbr.", + "Jacaranda Lbr.", + "Jacaranda Lbr.", + "Jacaranda Lbr.", + }, + }, + ["Ivory Sickle"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Platinum Ingot", + "Ram Leather", + "Oversized Fang", + }, + }, + ["Iyo Scale"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + }, + }, + ["Izayoi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Im. Wootz Ingot", + "Elm Lumber", + "Rainbow Thread", + "Manta Leather", + "A.U. Brass Ingot", + }, + }, + ["Jacaranda Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Jacaranda Log", + }, + }, + ["Jacaranda Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bundling Twine", + "Jacaranda Log", + "Jacaranda Log", + "Jacaranda Log", + }, + }, + ["Jack-o'-Lantern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ogre Pumpkin", + "Beeswax", + }, + }, + ["Jack-o'-Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Pie Dough", + "Maple Sugar", + "Cinnamon", + "Ogre Pumpkin", + "Selbina Milk", + "Distilled Water", + "Apkallu Egg", + }, + }, + ["Jadagna"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tr. Brz. Ingot", + "Tr. Brz. Ingot", + "Jadagna -1", + }, + }, + ["Jadeite"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Garudite", + }, + }, + ["Jadeite Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Jadeite", + "Gold Ring", + }, + }, + ["Jadeite Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Jadeite", + "Gold Ring +1", + }, + }, + ["Jagdplaute"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Platinum Ingot", + "Emerald", + "Ruby", + "Topaz", + "Mercury", + "Manticore Fang", + "Darksteel Sword", + }, + }, + ["Jamadhars"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Iron Sheet", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Jambiya"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Mercury", + "Pigeon's Blood", + "Marid Tusk", + "Scintillant Ingot", + }, + }, + ["Januwiyah"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tr. Brz. Sheet", + "Tr. Brz. Sheet", + "Januwiyah -1", + }, + }, + ["Jaridah Bazubands"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Steel Sheet", + "Karakul Leather", + "Marid Hair", + "Mohbwa Cloth", + }, + }, + ["Jaridah Khud"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Marid Leather", + "Marid Hair", + "Karakul Cloth", + }, + }, + ["Jaridah Nails"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Karakul Leather", + "Marid Leather", + "Marid Hair", + "Karakul Cloth", + }, + }, + ["Jaridah Peti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Sheet", + "Darksteel Chain", + "Brass Chain", + "Velvet Cloth", + "Karakul Leather", + "Marid Leather", + "Karakul Cloth", + }, + }, + ["Jaridah Salvars"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Karakul Leather", + "Marid Hair", + "Karakul Cloth", + "Karakul Cloth", + }, + }, + ["Jester's Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Cloth", + "Silk Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Jester's Headband"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Linen Cloth", + "Dodge Headband", + }, + }, + ["Jet Sickle"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Mandibular Sickle", + }, + }, + ["Jeunoan Armoire"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Rosewood Lbr.", + "Ebony Lumber", + "Ebony Lumber", + "Gold Ingot", + }, + }, + ["Jeunoan Dresser"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Rosewood Lbr.", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Gold Ingot", + }, + }, + ["Jeweled Collar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Emerald", + "Ruby", + "Diamond", + "Topaz", + "Sapphire", + "Spinel", + "Torque", + }, + }, + ["Jeweled Collar 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold. Kit 90", + }, + }, + ["Jindachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Iron Ingot", + "Tama-Hagane", + "Tama-Hagane", + "Ash Lumber", + "Cotton Thread", + "Raptor Skin", + }, + }, + ["Jinko"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Aquilaria Log", + }, + }, + ["Jolt Axe"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Bone Axe", + }, + }, + ["Jolt Counter"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Moonbow Steel", + "Moonbow Stone", + "Ruthenium Ingot", + "Cross-Counters", + }, + }, + ["Juji Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Iron Sheet", + }, + }, + ["Junhanshi Habaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Rainbow Cloth", + "Rainbow Cloth", + "Manta Leather", + }, + }, + ["Junior Musketeer's Chakram +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Jr.Msk. Chakram", + }, + }, + ["Junior Musketeer's Tuck +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Jr.Msk. Tuck", + }, + }, + ["Junkenshi Habaki"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + "Manta Leather", + }, + }, + ["Junrenshi Habaki"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Manta Leather", + }, + }, + ["Jusatsu"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Black Ink", + "Beastman Blood", + "Bast Parchment", + }, + }, + ["Justaucorps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Beetle Shell", + "Scorpion Claw", + "Scorpion Claw", + "Wool Robe", + }, + }, + ["Kabenro"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Beeswax", + "Water Lily", + "Water Lily", + }, + }, + ["Kabura Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Ram Horn", + "Kari. Arrowhd.", + "G. Bird Fltchg.", + }, + }, + ["Kabutowari"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Darksteel Ingot", + "Tama-Hagane", + "Elm Lumber", + "Cotton Thread", + "Raptor Skin", + }, + }, + ["Kaginawa"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Grass Thread", + "Manticore Hair", + }, + }, + ["Kaman"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Elm Lumber", + "Silk Thread", + "Wool Cloth", + }, + }, + ["Kamayari"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Tama-Hagane", + "Oak Lumber", + "Silk Thread", + }, + }, + ["Kanesada +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Rosewood Lbr.", + "Silver Thread", + "Kanesada", + }, + }, + ["Kapor Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Kapor Log", + }, + }, + ["Kapor Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Kapor Log", + "Kapor Log", + "Kapor Log", + "Bundling Twine", + }, + }, + ["Karakul Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Thread", + "Karakul Thread", + "Karakul Thread", + }, + }, + ["Karakul Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Karakul Skin", + "Im. Tea Leaves", + "Distilled Water", + }, + }, + ["Karakul Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Karakul Skin", + "Karakul Skin", + "Karakul Skin", + "Tanning Vat", + "Im. Tea Leaves", + "Im. Tea Leaves", + "Im. Tea Leaves", + "Distilled Water", + }, + }, + ["Karakul Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Karakul Wool", + "Karakul Wool", + }, + }, + ["Karakul Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Spindle", + "Karakul Wool", + "Karakul Wool", + "Karakul Wool", + "Karakul Wool", + "Karakul Wool", + "Karakul Wool", + }, + }, + ["Karakul Wool"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Karakul Skin", + "Karakul Skin", + }, + }, + ["Karimata Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Tama-Hagane", + }, + }, + ["Karni Yarik"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Wild Onion", + "Eggplant", + "Mithran Tomato", + "Karakul Meat", + }, + }, + ["Kaskara"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Bugard Skin", + }, + }, + ["Katars"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Bronze Sheet", + "Ram Leather", + }, + }, + ["Katzbalger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Raptor Skin", + "Broadsword", + }, + }, + ["Katzbalger 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 80", + }, + }, + ["Kawahori-Ogi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Animal Glue", + "Bast Parchment", + }, + }, + ["Kazaridachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Tama-Hagane", + "Ancient Lumber", + "Gold Ingot", + "Gold Thread", + "Wyvern Skin", + }, + }, + ["Keen Zaghnal"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Earth Cell", + "Brass Zaghnal", + }, + }, + ["Kendatsuba Hakama"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Cehuetzi Pelt", + "Defiant Sweat", + "Cypress Lumber", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Kendatsuba Jinpachi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Cehuetzi Pelt", + "Defiant Sweat", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Kendatsuba Samue"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Cloth", + "Cehuetzi Pelt", + "Defiant Sweat", + "Defiant Sweat", + "Cypress Lumber", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Kendatsuba Sune-Ate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Cehuetzi Pelt", + "Defiant Sweat", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Kendatsuba Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Cehuetzi Pelt", + "Defiant Sweat", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Kenpogi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + }, + }, + ["Keppu"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tin Ingot", + "Darksteel Sheet", + "Muketsu", + }, + }, + ["Keppu 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smith. Kit 76", + }, + }, + ["Kheten"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Darksteel Ingot", + "Rosewood Lbr.", + }, + }, + ["Khimaira Bonnet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Hippogryph Fthr.", + "Hippogryph Fthr.", + "Eft Skin", + "Buffalo Leather", + "Khimaira Mane", + "Khimaira Mane", + }, + }, + ["Khimaira Gamash."] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Hippogryph Fthr.", + "Buffalo Leather", + "Buffalo Leather", + "Khimaira Mane", + "Khimaira Mane", + }, + }, + ["Khimaira Jacket"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Manticore Lth.", + "Buffalo Horn", + "Eft Skin", + "Buffalo Leather", + "Buffalo Leather", + "Khimaira Mane", + "Khimaira Mane", + }, + }, + ["Khimaira Jambiya"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Gold Ingot", + "Mercury", + "Star Sapphire", + "Khimaira Horn", + }, + }, + ["Khimaira Kecks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Manticore Lth.", + "Buffalo Leather", + "Buffalo Leather", + "Khimaira Mane", + "Khimaira Mane", + "Khimaira Mane", + "Khimaira Mane", + }, + }, + ["Khimaira Wrist."] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Manticore Lth.", + "Buffalo Leather", + "Khimaira Mane", + "Khimaira Mane", + }, + }, + ["Khoma Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Thought Crystal", + "Hope Crystal", + "Fulfillment Crystal", + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + }, + }, + ["Khoma Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + }, + }, + ["Khromated Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Karakul Skin", + "Khroma Nugget", + "Distilled Water", + }, + }, + ["Khromated Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Karakul Skin", + "Karakul Skin", + "Karakul Skin", + "Tanning Vat", + "Khroma Nugget", + "Khroma Nugget", + "Khroma Nugget", + "Distilled Water", + }, + }, + ["Kilij"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Ebony Lumber", + "Gold Ingot", + "Gold Ingot", + "Lapis Lazuli", + "Turquoise", + "Marid Leather", + }, + }, + ["Killedar Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adamantoise Shell", + "Eltoro Leather", + "Gabbrath Horn", + }, + }, + ["Killer's Kilij"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Fiend Blood", + "Dragon Blood", + "Avatar Blood", + "Beast Blood", + "Chimera Blood", + "Ameretat Vine", + "Demon Blood", + "Adaman Kilij", + }, + }, + ["Kilo Battery"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Tin Ingot", + "Silver Ingot", + "Cermet Chunk", + "Rock Salt", + "Lightning Cluster", + "Distilled Water", + }, + }, + ["Kilo Fan"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Crab Shell", + "Giant Femur", + "Beeswax", + "Bat Wing", + "Wind Cluster", + }, + }, + ["Kilo Pump"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Chestnut Lumber", + "Coeurl Whisker", + "Coeurl Whisker", + "Carbon Fiber", + "Animal Glue", + "Water Cluster", + }, + }, + ["Kinesis Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ratatoskr Pelt", + "Nomad's Mantle", + }, + }, + ["Kinkobo"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ethrl. Vermilion", + "Primate Staff", + }, + }, + ["Kite Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Darksteel Sheet", + "Ash Lumber", + }, + }, + ["Kite Shield 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smith. Kit 50", + }, + }, + ["Kitron Juice"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kitron", + }, + }, + ["Kitron Macaron"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Almond", + "Kitron", + "Lizard Egg", + }, + }, + ["Klouskap Sash"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cashmere Wool", + "Penelope's Cloth", + "Defiant Scarf", + }, + }, + ["Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Elm Lumber", + }, + }, + ["Knight's Beads"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Waktza Crest", + "Dark Matter", + "Khoma Thread", + "Diamond Crystal", + "Moldy Necklace", + }, + }, + ["Knight's Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Ram Leather", + }, + }, + ["Kodachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Mythril Ingot", + "Tama-Hagane", + "Ash Lumber", + "Cotton Thread", + "Lizard Skin", + }, + }, + ["Kodoku"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Elshimo Frog", + "Lugworm", + "Shell Bug", + }, + }, + ["Kodoku 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Caedarva Frog", + "Lugworm", + "Shell Bug", + }, + }, + ["Koen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Toad Oil", + "Brimsand", + "Homura", + }, + }, + ["Koenig Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Gold Ingot", + "Gold Sheet", + "General's Shield", + }, + }, + ["Koenigs Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Chain", + "Manticore Lth.", + "Manticore Lth.", + }, + }, + ["Koenigs Belt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 90", + }, + }, + ["Koenigs Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Gold Ingot", + "Mercury", + "Diamond Knuckles", + }, + }, + ["Koga Shinobi-Gatana"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Plating", + "Dark Matter", + "Ruthenium Ore", + "Moldy Katana", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Tanzanite Crystal", + }, + }, + ["Kohlrouladen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Black Pepper", + "Rock Salt", + "La Theine Cbg.", + "Selbina Milk", + "Ruszor Meat", + }, + }, + ["Kongou Inaho"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Firesand", + "Copper Nugget", + }, + }, + ["Konigskuchen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Pie Dough", + "Maple Sugar", + "Selbina Milk", + "San d'Or. Grape", + "Yagudo Cherry", + "Distilled Water", + "Bird Egg", + }, + }, + ["Konjak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Seashell", + "Distilled Water", + "Konjak Tuber", + }, + }, + ["Konron Hassen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bomb Ash", + "Firesand", + "Bast Parchment", + "Copper Nugget", + }, + }, + ["Kororito"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Shinobi-Gatana", + }, + }, + ["Kotatsu Table"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Rosewood Lbr.", + "Cotton Cloth", + "Cotton Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Bomb Arm", + }, + }, + ["Kote"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Iron Chain", + "Iron Chain", + "Silk Thread", + "Silk Cloth", + }, + }, + ["Kotetsu +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Rosewood Lbr.", + "Silver Thread", + "Kotetsu", + }, + }, + ["Kris"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Steel Ingot", + "Black Pearl", + }, + }, + ["Krousis Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Imperial Topaz", + "Platinum Ring", + }, + }, + ["Kujaku"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Hirenjaku", + }, + }, + ["Kukri"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Chestnut Lumber", + "Lizard Skin", + }, + }, + ["Kunai"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Lizard Skin", + }, + }, + ["Kunitsuna"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dark Matter", + "Vulcanite Ore", + "Vulcanite Ore", + "Butachi", + }, + }, + ["Kunwu Iron"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ore", + "Kunwu Ore", + "Kunwu Ore", + "Kunwu Ore", + }, + }, + ["Kunwu Iron Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kunwu Iron", + }, + }, + ["Kusamochi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sticky Rice", + "Fresh Mugwort", + "Cornstarch", + "Distilled Water", + }, + }, + ["Kwahu Kachina Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sealord Leather", + "Ra'Kaznar Ingot", + "Macuil Plating", + }, + }, + ["Kyahan"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + "Sheep Leather", + }, + }, + ["Kyofu"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tin Ingot", + "Iron Sheet", + "Shinobi-Gatana", + }, + }, + ["Kyoshu Sitabaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Cotton Cloth", + "Lineadach", + }, + }, + ["Kyudogi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Kejusu Satin", + "Sailcloth", + "Sheep Chammy", + "Cerber. Leather", + "Scintillant Ingot", + "Yoichi's Sash", + "Imp. Silk Cloth", + }, + }, + ["Lacquer Tree Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lacquer Tree Log", + }, + }, + ["Lacquer Tree Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lacquer Tree Log", + "Lacquer Tree Log", + "Lacquer Tree Log", + "Bundling Twine", + }, + }, + ["Lacquer Tree Sap"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Lacquer Tree Log", + }, + }, + ["Lacryma Sickle"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "Ram Leather", + "Urunday Lumber", + "Rockfin Tooth", + }, + }, + ["Lady Bell"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Lauan Lumber", + }, + }, + ["Ladybug Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ladybug Wing", + "Electrum Chain", + }, + }, + ["Ladybug Earring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 75", + }, + }, + ["Ladybug Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ladybug Wing", + "Ladybug Wing", + }, + }, + ["Ladybug Ring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 65", + }, + }, + ["Lamia Garland"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Brass Chain", + "Garnet", + "Manta Leather", + "Uragnite Shell", + "A.U. Brass Ingot", + }, + }, + ["Lamia Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manta Skin", + "Lamia Skin", + "Mohbwa Thread", + }, + }, + ["Lamian Kaman"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Scorpion Claw", + "Marid Tusk", + "Lamian Kaman -1", + }, + }, + ["Laminated Buffalo Leather"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Animal Glue", + "Buffalo Leather", + "Distilled Water", + }, + }, + ["Laminated Ram Leather"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Animal Glue", + "Distilled Water", + }, + }, + ["Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Ash Lumber", + "Ash Lumber", + }, + }, + ["Lancewood Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lancewood Log", + }, + }, + ["Lancewood Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lancewood Log", + "Lancewood Log", + "Lancewood Log", + "Bundling Twine", + }, + }, + ["Lanner Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Lancewood Lbr.", + "Karakul Cloth", + "Wyrdstrand", + }, + }, + ["Lapis Lazuli"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Blue Rock", + }, + }, + ["Lapis Lazuli 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Aqua Geode", + }, + }, + ["Lapis Lazuli Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lapis Lazuli", + "Silver Earring", + }, + }, + ["Lapis Lazuli Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lapis Lazuli", + "Silver Earring +1", + }, + }, + ["Lapis Lazuli Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lapis Lazuli", + "Silver Ring", + }, + }, + ["Lapis Lazuli Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lapis Lazuli", + "Silver Ring +1", + }, + }, + ["Lauan Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lauan Log", + }, + }, + ["Lauan Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lauan Log", + "Lauan Log", + "Lauan Log", + "Bundling Twine", + }, + }, + ["Lauan Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Lauan Lumber", + "Lauan Lumber", + }, + }, + ["Lavalier"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Manticore Hair", + }, + }, + ["Leather Bandana"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheep Leather", + }, + }, + ["Leather Bandana 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Leath. Kit 5", + }, + }, + ["Leather Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Chain", + "Sheep Leather", + }, + }, + ["Leather Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Leather Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Ram Leather", + }, + }, + ["Leather Highboots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Sheep Leather", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Leather Pot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hickory Lumber", + "Karakul Leather", + "Rheiyoh Leather", + "Karakul Thread", + "Kaolin", + "Kaolin", + }, + }, + ["Leather Pouch"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Sheep Leather", + "Sheep Leather", + "Rabbit Hide", + }, + }, + ["Leather Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dhalmel Leather", + }, + }, + ["Leather Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Raptor Skin", + "Lauan Shield", + }, + }, + ["Leather Shield 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 50", + }, + }, + ["Leather Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Cloth", + "Grass Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Leather Vest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Sheep Leather", + "Sheep Leather", + "Lizard Skin", + }, + }, + ["Leather Vest 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 10", + }, + }, + ["Leathercraft Set 25"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Iron Chain", + "Dhalmel Leather", + }, + }, + ["Leathercraft Set 45"] = { + ["crystal"] = "Fluid Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Beeswax", + "Leather Trousers", + }, + }, + ["Leathercraft Set 66"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Iron Scales", + "Ram Leather", + "Ram Leather", + "Tiger Leather", + }, + }, + ["Leathercraft Set 70"] = { + ["crystal"] = "Frost Crystal", + ["ingredients"] = { + "Wool Thread", + "Behemoth Hide", + }, + }, + ["Leathercraft Set 75"] = { + ["crystal"] = "Frost Crystal", + ["ingredients"] = { + "Wool Thread", + "Tiger Hide", + }, + }, + ["Leathercraft Set 79"] = { + ["crystal"] = "Frost Crystal", + ["ingredients"] = { + "Marid Hide", + "Karakul Thread", + }, + }, + ["Leathercraft Set 85"] = { + ["crystal"] = "Frost Crystal", + ["ingredients"] = { + "Wool Thread", + "Coeurl Hide", + }, + }, + ["Leathercraft Set 90"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Gold Chain", + "Manticore Lth.", + "Manticore Lth.", + }, + }, + ["Leathercraft Set 95"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Grass Thread", + "Peiste Skin", + "Peiste Skin", + }, + }, + ["Lebkuchen House"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Baking Soda", + "Honey", + "Cinna-cookie", + "Bbl. Chocolate", + "Distilled Water", + "Bird Egg", + }, + }, + ["Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Leo Crossbow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Lion Crossbow", + }, + }, + ["Lethe Consomme"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Eastern Ginger", + "San d'Or. Carrot", + "Tiger Cod", + "Distilled Water", + }, + }, + ["Lethe Potage"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Popoto", + "Eastern Ginger", + "Bastore Bream", + "Distilled Water", + }, + }, + ["Leucous Voulge"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Holly Lumber", + "Platinum Ingot", + "Cermet Chunk", + "Super Cermet", + "Super Cermet", + }, + }, + ["Light Anima"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Radiant Memory", + "Radiant Memory", + "Radiant Memory", + "Radiant Memory", + }, + }, + ["Light Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Light Ore", + }, + }, + ["Light Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Light Cluster", + }, + }, + ["Light Crossbow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Ash Lumber", + "Grass Thread", + }, + }, + ["Light Fewell"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Slime Oil", + "White Rock", + "Catalytic Oil", + }, + }, + ["Light Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Light Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Light Opal"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "White Rock", + }, + }, + ["Light Opal 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Light Geode", + }, + }, + ["Light Ram Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Ram Skin", + "Ice Anima", + "Lightning Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Light Ram Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Ram Skin", + "Ice Anima", + "Lightning Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Light Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Light Bead", + "Orichalcum Ring", + }, + }, + ["Light Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Light Bead", + }, + }, + ["Light Steel Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Ice Anima", + "Lightning Anima", + "Light Anima", + }, + }, + ["Lightning Anima"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Strtlng. Memory", + "Strtlng. Memory", + "Strtlng. Memory", + "Strtlng. Memory", + }, + }, + ["Lightning Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Ltng. Arrowhd.", + "Insect Fltchg.", + }, + }, + ["Lightning Arrow 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Steel Ingot", + "Maple Lumber", + "Insect Wing", + "Insect Wing", + }, + }, + ["Lightning Arrowheads"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Copper Ingot", + "Steel Ingot", + }, + }, + ["Lightning Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lightning Ore", + }, + }, + ["Lightning Bow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ose Whisker", + "Kaman", + }, + }, + ["Lightning Fewell"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Slime Oil", + "Purple Rock", + "Catalytic Oil", + }, + }, + ["Lightning Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lightning Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Lightweight Steel Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Light Steel", + }, + }, + ["Lightweight Steel Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Light Steel", + "Light Steel", + "Light Steel", + "Light Steel", + "Light Steel", + "Light Steel", + "Workshop Anvil", + }, + }, + ["Lik Kabob"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lik", + "Bomb Arm", + }, + }, + ["Lilac Corsage"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silk Cloth", + "Spider Web", + "Lilac", + "Twinthread", + }, + }, + ["Linen Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Thread", + "Linen Thread", + }, + }, + ["Linen Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sardonyx", + "Sardonyx", + "Linen Thread", + "Cotton Cloth", + "Linen Cloth", + }, + }, + ["Linen Doublet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Linen Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Cotton Cloth", + "Linen Cloth", + "Saruta Cotton", + }, + }, + ["Linen Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Linen Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Linen Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Cotton Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Linen Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Flax Flower", + "Flax Flower", + }, + }, + ["Linen Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Flax Flower", + "Flax Flower", + "Flax Flower", + "Flax Flower", + "Flax Flower", + "Flax Flower", + "Spindle", + }, + }, + ["Liquefaction Sphere"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Bomb Coal", + }, + }, + ["Liquefaction Sphere 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Ancient Salt", + }, + }, + ["Liquefaction Sphere 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Fetich Arms", + }, + }, + ["Liquefaction Sphere 4"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Rusty Medal", + }, + }, + ["Liquefaction Sphere 5"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Fire Crest Card", + }, + }, + ["Lithic Wyvern Scale"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wyvern Scales", + "Earth Anima", + "Earth Anima", + "Light Anima", + }, + }, + ["Little Comet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Firesand", + "Rain Lily", + "Bast Parchment", + "Bast Parchment", + }, + }, + ["Little Worm Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Animal Glue", + "Leather Pouch", + "Worm Mulch", + }, + }, + ["Living Key"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Slime Oil", + "Beeswax", + "Malboro Vine", + }, + }, + ["Living Key 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Slime Oil", + "Beeswax", + "Rafflesia Vine", + }, + }, + ["Lizard Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Chain", + "Lizard Skin", + }, + }, + ["Lizard Cesti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Cesti", + }, + }, + ["Lizard Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Leather Gloves", + }, + }, + ["Lizard Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Lizard Helm 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 15", + }, + }, + ["Lizard Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Lizard Skin", + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Lizard Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Lizard Skin", + "Leather Highboots", + }, + }, + ["Lizard Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Lizard Skin", + "Lizard Molt", + }, + }, + ["Lizard Strap"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Lizard Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Lizard Skin", + "Leather Trousers", + }, + }, + ["Loach Slop"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Soy Stock", + "2Leaf Mandra Bud", + "Distilled Water", + "Bird Egg", + "Cibol", + "Brass Loach", + "Brass Loach", + "Burdock", + }, + }, + ["Longbow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Lumber", + "Yew Lumber", + "Linen Cloth", + "Ram Horn", + "Coeurl Whisker", + }, + }, + ["Longsword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Dhalmel Leather", + }, + }, + ["Lord's Armet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Mercury", + "Darksteel Armet", + }, + }, + ["Lord's Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Platinum Ingot", + "Gold Sheet", + "Gold Sheet", + "Gold Sheet", + "Mercury", + "Darksteel Cuirass", + }, + }, + ["Lord's Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Mercury", + "Darksteel Cuisses", + }, + }, + ["Lord's Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Mercury", + "Dst. Gauntlets", + }, + }, + ["Lord's Sabatons"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Dst. Sabatons", + }, + }, + ["Loudspeaker"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Treant Bulb", + "Glass Sheet", + "Baking Soda", + "Colibri Beak", + "Water Tank", + }, + }, + ["Loudspeaker II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Treant Bulb", + "Treant Bulb", + "Glass Sheet", + "Baking Soda", + "Baking Soda", + "Colibri Beak", + "Water Tank", + }, + }, + ["Loudspeaker III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Treant Bulb", + "Treant Bulb", + "Baking Soda", + "Baking Soda", + "Colibri Beak", + "F. Glass Sheet", + "Water Tank", + }, + }, + ["Loudspeaker IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Treant Bulb", + "Treant Bulb", + "Baking Soda", + "Colibri Beak", + "F. Glass Sheet", + "F. Glass Sheet", + "Water Tank", + }, + }, + ["Loudspeaker V"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Treant Bulb", + "Treant Bulb", + "Baking Soda", + "Colibri Beak", + "F. Glass Sheet", + "F. Glass Sheet", + "F. Glass Sheet", + "Water Tank", + }, + }, + ["Love Chocolate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Parchment", + "Heart Chocolate", + "Scarlet Ribbon", + }, + }, + ["Lu Shang's Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Lu Rod", + }, + }, + ["Lu Shang's Fishing Rod +1"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "B. Lu. Rod +1", + }, + }, + ["Lucent Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lucent Steel", + "Heavy Axe", + }, + }, + ["Lucent Iron Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Earth Anima", + "Lightning Anima", + "Light Anima", + }, + }, + ["Lucent Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lucent Steel", + "Lance", + }, + }, + ["Lucent Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lucent Iron", + "Scythe", + }, + }, + ["Lucent Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lucent Iron", + "Two-Hand. Sword", + }, + }, + ["Lucky Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Bladefish", + "Buffalo Meat", + }, + }, + ["Lucky Carrot Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "San d'Or. Carrot", + "San d'Or. Carrot", + "San d'Or. Carrot", + "Snoll Arm", + }, + }, + ["Lugworm Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Animal Glue", + "Leather Pouch", + "Lugworm Sand", + }, + }, + ["Luminous Core"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Adaman Ore", + "Adaman Ore", + "Adaman Ore", + "Lightning Anima", + "Lightning Anima", + "Dark Anima", + }, + }, + ["Luminous Shell"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Crab Shell", + "Lightning Anima", + "Lightning Anima", + "Dark Anima", + }, + }, + ["Luxurious Chest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Gold Ingot", + }, + }, + ["Lynx Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Lynx Hide", + "Distilled Water", + }, + }, + ["Lynx Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Lynx Hide", + "Distilled Water", + }, + }, + ["Lynx Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tanning Vat", + "Lynx Hide", + "Lynx Hide", + "Lynx Hide", + "Distilled Water", + }, + }, + ["Lynx Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Lynx Hide", + }, + }, + ["M. Counteragent"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Seashell", + "Salinator", + "Distilled Water", + "Distilled Water", + }, + }, + ["Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + }, + }, + ["Mache Earring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Shadow Gem", + "Hepatizon Ingot", + "Tartarian Soul", + }, + }, + ["Macuahuitl"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bugard Tusk", + "Rhinochimera", + "Macuahuitl -1", + }, + }, + ["Magic Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ram Leather", + "Mercury", + "Toad Oil", + }, + }, + ["Magical Cotton Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Thread", + "Cotton Thread", + "Earth Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Magical Linen Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Thread", + "Linen Thread", + "Earth Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Magical Silk Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Thread", + "Silk Thread", + "Earth Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Magma Steak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Bay Leaves", + "Black Pepper", + "Millioncorn", + "Olive Oil", + "Rock Salt", + "San d'Or. Carrot", + "Gabbrath Meat", + }, + }, + ["Magniplug"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Fire Bead", + "Homncl. Nerves", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Magniplug II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Fire Bead", + "Homncl. Nerves", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Maharaja's Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "G. Bgd. Leather", + "Koenigs Belt", + }, + }, + ["Mahogany Bed"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Wool Cloth", + }, + }, + ["Mahogany Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Log", + }, + }, + ["Mahogany Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Log", + "Mahogany Log", + "Mahogany Log", + "Bundling Twine", + }, + }, + ["Mahogany Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + }, + }, + ["Mahogany Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Mahogany Lbr.", + "Mahogany Lbr.", + }, + }, + ["Mahogany Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Turquoise", + "Demon Horn", + }, + }, + ["Mailbreaker"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Bilbo", + }, + }, + ["Makibishi"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Scales", + }, + }, + ["Malayo Crossbow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Durium Ingot", + "Giant Femur", + "Carbon Fiber", + "Urunday Lumber", + "Urunday Lumber", + }, + }, + ["Malfeasance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Damascus Ingot", + "Damascus Ingot", + "Ormolu Ingot", + "Squamous Hide", + "Yggdreant Bole", + "Hades' Claw", + "Tartarian Soul", + }, + }, + ["Malison Medallion"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Chain", + "Heliodor", + "Neutralizing Slv.", + "Holy Water", + "Holy Water", + "Hallowed Water", + }, + }, + ["Maliya Sickle"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Urunday Lumber", + "Raaz Leather", + "Maliya. Coral", + "Ra'Kaznar Ingot", + }, + }, + ["Maliyakaleya Orb"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Maliya. Coral", + }, + }, + ["Mammoth Tusk"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Giant Frozen Head", + }, + }, + ["Mamool Ja Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Karakul Leather", + "Blk. Tiger Fang", + "Blk. Tiger Fang", + "Coeurl Whisker", + "Mamool Ja Helmet", + "Marid Hair", + }, + }, + ["Mamushito"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Paralyze Potion", + "Shinobi-Gatana", + }, + }, + ["Mana Booster"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mercury", + "Fiend Blood", + "Brass Tank", + "Imperial Cermet", + "Mana Wand", + }, + }, + ["Mana Chestnut Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Log", + "Earth Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Mana Cloak"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mag. Lin. Cloth", + "Cloak", + }, + }, + ["Mana Conserver"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Dark Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Mana Converter"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mercury", + "Coeurl Whisker", + "Brass Tank", + "Brass Tank", + "Imperial Cermet", + }, + }, + ["Mana Jammer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blsd. Mtl. Sheet", + "Artificial Lens", + "Sieglinde Putty", + "Water Tank", + "Hydro Pump", + }, + }, + ["Mana Jammer II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blsd. Mtl. Sheet", + "Artificial Lens", + "Sieglinde Putty", + "Water Tank", + "Kilo Fan", + }, + }, + ["Mana Jammer III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blsd. Mtl. Sheet", + "Artificial Lens", + "Sieglinde Putty", + "Water Tank", + "Mega Pump", + }, + }, + ["Mana Jammer IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blsd. Mtl. Sheet", + "Artificial Lens", + "Sieglinde Putty", + "Water Tank", + "Kilo Pump", + "Mega Pump", + }, + }, + ["Mana Tank"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Sieglinde Putty", + "Glass Sheet", + "Hi-Ether Tank", + "Hydro Pump", + }, + }, + ["Mana Tank II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Sieglinde Putty", + "Glass Sheet", + "Hi-Ether Tank", + "Kilo Pump", + }, + }, + ["Mana Tank III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Sieglinde Putty", + "Glass Sheet", + "Hi-Ether Tank", + "Mega Pump", + }, + }, + ["Mana Tank IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Sieglinde Putty", + "Glass Sheet", + "Hi-Ether Tank", + "Kilo Pump", + "Mega Pump", + }, + }, + ["Mana Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mag. Ctn. Cloth", + "Tunic", + }, + }, + ["Mana Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "M. Will. Lumber", + "Willow Wand", + }, + }, + ["Mana Willow Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Log", + "Earth Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Manashell Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wailing Shell", + "Shell Ring", + }, + }, + ["Mandarin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Saruta Orange", + "Saruta Orange", + "Saruta Orange", + "Saruta Orange", + }, + }, + ["Mandibular Sickle"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Ebony Lumber", + "Ram Leather", + "Antlion Jaw", + }, + }, + ["Manji Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Darksteel Sheet", + }, + }, + ["Manoples"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Darksteel Sheet", + "Carbon Fiber", + "Scintillant Ingot", + }, + }, + ["Manta Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Manta Skin", + "Distilled Water", + }, + }, + ["Manta Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Manta Skin", + "Distilled Water", + }, + }, + ["Manta Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Manta Skin", + "Manta Skin", + "Manta Skin", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Manticore Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Manticore Hide", + "Distilled Water", + }, + }, + ["Manticore Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Manticore Hide", + "Distilled Water", + }, + }, + ["Manticore Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Manticore Hide", + "Manticore Hide", + "Manticore Hide", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Mantid Arrowhd."] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Mantid Foreleg", + }, + }, + ["Mantid Arrowhd. 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Shagreen File", + "Mantid Foreleg", + "Mantid Foreleg", + "Mantid Foreleg", + }, + }, + ["Maple Cake"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Maple Sugar", + "Olive Oil", + "Selbina Milk", + "Bird Egg", + "Apkallu Egg", + }, + }, + ["Maple Harp"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Maple Lumber", + "Maple Lumber", + "Coeurl Whisker", + }, + }, + ["Maple Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Log", + }, + }, + ["Maple Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Log", + "Maple Log", + "Maple Log", + "Bundling Twine", + }, + }, + ["Maple Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Maple Lumber", + "Maple Lumber", + }, + }, + ["Maple Sugar"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Maple Log", + }, + }, + ["Maple Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Maple Lumber", + "Maple Lumber", + "Maple Lumber", + "Maple Lumber", + }, + }, + ["Maple Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Maple Lumber", + "Chocobo Fthr.", + }, + }, + ["Marath Baghnakhs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mlbd. Sheet", + "Marid Leather", + "Gargouille Horn", + "Gargouille Horn", + "Gargouille Horn", + }, + }, + ["Marble Bed"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Aquamarine", + "Rainbow Thread", + "Silk Cloth", + "Sarcenet Cloth", + "Marble", + "Marble", + }, + }, + ["Marble Plaque"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Amethyst", + "Black Ink", + "Bast Parchment", + "Marble", + }, + }, + ["Marbled Drawers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Gold Ingot", + "Tufa", + "Tufa", + "Tufa", + }, + }, + ["Margherita Pizza"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Holy Basil", + "Pizza Dough", + "Mithran Tomato", + "Pomodoro Sauce", + "Chalaimbille", + }, + }, + ["Margherita Slice"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Holy Basil", + "Pizza Dough", + "Mithran Tomato", + "Pomodoro Sauce", + "Chalaimbille", + "Pizza Cutter", + }, + }, + ["Marid Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Apkal. Fletching", + "M. Tusk Arwhds.", + }, + }, + ["Marid Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Chain", + "Marid Leather", + "Marid Leather", + }, + }, + ["Marid Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Marid Hide", + "Im. Tea Leaves", + "Distilled Water", + }, + }, + ["Marid Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Tanning Vat", + "Marid Hide", + "Marid Hide", + "Marid Hide", + "Im. Tea Leaves", + "Im. Tea Leaves", + "Im. Tea Leaves", + "Distilled Water", + }, + }, + ["Marid Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Karakul Leather", + "Merrow Scale", + "Marid Tusk", + }, + }, + ["Marid Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Marid Hide", + "Karakul Thread", + }, + }, + ["Marid Mantle 2"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Leath. Kit 79", + }, + }, + ["Marid Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Merrow Scale", + "Marid Tusk", + }, + }, + ["Marid Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Marid Tusk", + "Marid Tusk", + }, + }, + ["Marid Tusk Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Marid Tusk", + }, + }, + ["Marid Tusk Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Shagreen File", + "Marid Tusk", + "Marid Tusk", + "Marid Tusk", + }, + }, + ["Marinara"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Olive Oil", + "Rock Salt", + "Spaghetti", + "Jacknife", + "Pomodoro Sauce", + "Kalamar", + "Bastore Sweeper", + }, + }, + ["Marinara Pizza"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Dried Marjoram", + "Holy Basil", + "Pizza Dough", + "Chalaimbille", + "Marinara Sauce", + }, + }, + ["Marinara Sauce"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Mithran Tomato", + "Anchovy", + }, + }, + ["Marinara Slice"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Dried Marjoram", + "Holy Basil", + "Pizza Dough", + "Chalaimbille", + "Marinara Sauce", + "Pizza Cutter", + }, + }, + ["Marine Stewpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fish Stock", + "Distilled Water", + "Mola Mola", + "Cotton Tofu", + "Cibol", + "Shungiku", + "Shirataki", + "Agaricus", + }, + }, + ["Maringna"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Olive Oil", + "Imperial Flour", + "Bird Egg", + "Vongola Clam", + "Bastore Sweeper", + "Gigant Octopus", + "Uleguerand Milk", + }, + }, + ["Marksman's Oil"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Goblin Grease", + "Slime Juice", + }, + }, + ["Marron Glace"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Maple Sugar", + "Chestnut", + "Chestnut", + "Baking Soda", + "Grape Juice", + }, + }, + ["Marron Glace 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Maple Sugar", + "Chestnut", + "Chestnut", + "Grape Juice", + }, + }, + ["Mars's Hexagun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Silver Ingot", + }, + }, + ["Master's Gi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Jujitsu Gi", + }, + }, + ["Master's Sitabaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Linen Cloth", + "Jujitsu Sitabaki", + }, + }, + ["Matamata Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Craklaw Pincer", + "Matamata Shell", + }, + }, + ["Matchlock Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Darksteel Ingot", + "Walnut Lumber", + }, + }, + ["Matka"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Karugo Clay", + "Karugo Clay", + "Karugo Clay", + "Karugo Clay", + "Karugo Clay", + }, + }, + ["Maul"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Oak Lumber", + }, + }, + ["Max-Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Sage", + "Sage", + "Dragon Blood", + "Reishi Mushroom", + "Distilled Water", + }, + }, + ["Max-Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 95", + }, + }, + ["Mdr. Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Midrium Ingot", + }, + }, + ["Meat Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Hare Meat", + "Dhalmel Meat", + "G. Sheep Meat", + }, + }, + ["Meat Jerky"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Rock Salt", + "G. Sheep Meat", + }, + }, + ["Meat Mithkabob"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Wild Onion", + "Ziz Meat", + }, + }, + ["Meat Mithkabob 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Wild Onion", + "Cockatrice Meat", + }, + }, + ["Meatball"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Hare Meat", + "Distilled Water", + }, + }, + ["Meatball 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cook. Kit 35", + }, + }, + ["Meatloaf"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Blue Peas", + "Black Pepper", + "Rock Salt", + "Wild Onion", + "Bird Egg", + "Buffalo Meat", + "Lynx Meat", + }, + }, + ["Mega Battery"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Iron Ingot", + "Silver Ingot", + "Cermet Chunk", + "Rock Salt", + "Lightning Cluster", + "Distilled Water", + }, + }, + ["Mega Fan"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Giant Femur", + "Scorpion Shell", + "Beeswax", + "Bat Wing", + "Wind Cluster", + }, + }, + ["Mega Pump"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Chestnut Lumber", + "Coeurl Whisker", + "Coeurl Whisker", + "Coeurl Whisker", + "Carbon Fiber", + "Animal Glue", + "Water Cluster", + }, + }, + ["Meifu Goma"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Cotton Thread", + "Firesand", + "Koma", + }, + }, + ["Melanzane"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Olive Oil", + "Rock Salt", + "Spaghetti", + "Wild Onion", + "Eggplant", + "Pomodoro Sauce", + }, + }, + ["Melee Fists"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hades' Claw", + "Dark Matter", + "S. Faulpie Leather", + "Moldy Weapon", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Sapphire Crystal", + }, + }, + ["Mellow Bird Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Dhalmel Meat", + "Lizard Egg", + "Cockatrice Meat", + "Bird Egg", + }, + }, + ["Melody Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Southern Pearl", + "Mythril Earring", + }, + }, + ["Melon Juice"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Thundermelon", + "Watermelon", + }, + }, + ["Melon Juice 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cook. Kit 40", + }, + }, + ["Melon Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Maple Sugar", + "Cinnamon", + "Lizard Egg", + "Thundermelon", + }, + }, + ["Melon Pie 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Maple Sugar", + "Cinnamon", + "Thundermelon", + "Bird Egg", + }, + }, + ["Melt Baselard"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Invitriol", + "Acid Baselard", + }, + }, + ["Melt Baselard 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 65", + }, + }, + ["Melt Claws"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Invitriol", + "Acid Claws", + }, + }, + ["Melt Dagger"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Invitriol", + "Acid Dagger", + }, + }, + ["Melt Katana"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Invitriol", + "Yoto", + }, + }, + ["Melt Knife"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Invitriol", + "Acid Knife", + }, + }, + ["Melt Kukri"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Invitriol", + "Acid Kukri", + }, + }, + ["Menemen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Selbina Butter", + "Black Pepper", + "Rock Salt", + "Wild Onion", + "Mithran Tomato", + "Puk Egg", + "Puk Egg", + }, + }, + ["Menemen 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 45", + }, + }, + ["Menetrier's Alb"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Sheep Leather", + "Ram Leather", + "Beeswax", + "Red Grs. Thread", + "Red Grass Cloth", + "Red Grass Cloth", + "Yel. Brass Chain", + }, + }, + ["Mensa Lunata"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Rosewood Lbr.", + "Gold Ingot", + }, + }, + ["Mensch Strap"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cerberus Hide", + "Yggdreant Root", + }, + }, + ["Mercury"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Cobalt Jellyfish", + "Cobalt Jellyfish", + "Cobalt Jellyfish", + "Cobalt Jellyfish", + }, + }, + ["Mercury 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Denizanasi", + "Denizanasi", + "Denizanasi", + "Denizanasi", + }, + }, + ["Messhikimaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bewitched Gold", + "Kazaridachi", + }, + }, + ["Metal Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Sheet", + "Holly Lumber", + }, + }, + ["Mettle Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Sheep Leather", + "Bone Chip", + "Samwell's Shank", + }, + }, + ["Mezraq"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Im. Wootz Ingot", + "Im. Wootz Ingot", + "Bldwd. Lumber", + "Platinum Ingot", + "Wamoura Silk", + }, + }, + ["Midare"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Mythril Ingot", + "Ash Lumber", + "Cotton Thread", + "Lizard Skin", + "T. Tama-hagane", + }, + }, + ["Midrium Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Midrium Ore", + "Midrium Ore", + "Midrium Ore", + "Midrium Ore", + }, + }, + ["Midrium Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Midrium Ingot", + }, + }, + ["Midrium Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Workshop Anvil", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + }, + }, + ["Mighty Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mighty Sardonyx", + "Sardonyx Ring", + }, + }, + ["Mighty Sardonyx"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sardonyx", + "Fire Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Mikazuki"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Tama-Hagane", + "Ash Lumber", + "Cotton Thread", + "Lizard Skin", + }, + }, + ["Mille Feuille"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pie Dough", + "Pie Dough", + "Pie Dough", + "Maple Sugar", + "Rolanberry", + "Selbina Milk", + "Distilled Water", + "Bird Egg", + }, + }, + ["Millionaire Desk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Ancient Lumber", + "Gold Sheet", + "Gold Sheet", + "Platinum Sheet", + "Granite", + "Granite", + "Granite", + }, + }, + ["Mind Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Bat Wing", + "Casablanca", + "Dried Mugwort", + "Honey", + "Distilled Water", + }, + }, + ["Minnow"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Glass Fiber", + }, + }, + ["Minnow 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Glass Fiber", + }, + }, + ["Miracle Mulch"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Chocobo Bedding", + "Dung", + }, + }, + ["Mirage Stole"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Yggdreant Bole", + "Dark Matter", + "Cypress Log", + "Lapis Lazuli Crystal", + "Moldy Stole", + }, + }, + ["Mirage Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Plovid Flesh", + "Dark Matter", + "Khoma Thread", + "Moldy Sword", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Lapis Lazuli Crystal", + }, + }, + ["Misericorde"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Adaman Ingot", + }, + }, + ["Miso Ramen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Millioncorn", + "Rarab Tail", + "Porxie Pork", + "Ramen Noodles", + "Miso Ramen Soup", + "Bamboo Shoots", + }, + }, + ["Miso Ramen Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Ginger", + "Chicken Bone", + "Chicken Bone", + "Distilled Water", + "Miso", + "Soy Sauce", + }, + }, + ["Miso Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adoulinian Kelp", + "Cotton Tofu", + "Cibol", + "Miso", + "Dried Bonito", + }, + }, + ["Mist Crown"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smth. Btl. Jaw", + "Garish Crown", + }, + }, + ["Mist Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smooth Velvet", + "Garish Mitts", + }, + }, + ["Mist Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smth. Shp. Lth.", + "Garish Pumps", + }, + }, + ["Mist Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smooth Velvet", + "Garish Slacks", + }, + }, + ["Mist Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smooth Velvet", + "Garish Tunic", + }, + }, + ["Mithran Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Mithran Rod", + }, + }, + ["Mithran Fishing Rod 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rattan Lumber", + "Rainbow Thread", + }, + }, + ["Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Grass Cloth", + "Cotton Cloth", + "Saruta Cotton", + }, + }, + ["Mixed Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chapuli Wing", + "Porxie Wing", + }, + }, + ["Mixed Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Chapuli Wing", + "Chapuli Wing", + "Chapuli Wing", + "Porxie Wing", + "Porxie Wing", + "Porxie Wing", + }, + }, + ["Mizu-Deppo"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Chestnut Lumber", + "Distilled Water", + }, + }, + ["Moblin Putty"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Flaxseed Oil", + "Flaxseed Oil", + "Shell Powder", + "Shell Powder", + "Zincite", + "Zincite", + "Zincite", + }, + }, + ["Moblin Sheep Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Moblin Sheepskin", + "Distilled Water", + }, + }, + ["Moblin Sheep Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Moblin Sheepskin", + "Distilled Water", + }, + }, + ["Moblin Sheep Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Moblin Sheepskin", + "Moblin Sheepskin", + "Moblin Sheepskin", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Moblin Sheep Wool"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Moblin Sheepskin", + "Moblin Sheepskin", + }, + }, + ["Moblinweave"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moblin Thread", + "Moblin Thread", + "Moblin Thread", + }, + }, + ["Moblumin Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Moblumin Ingot", + }, + }, + ["Moccasins"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Dhalmel Leather", + "Raptor Skin", + }, + }, + ["Mohbwa Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mohbwa Thread", + "Mohbwa Thread", + "Mohbwa Thread", + }, + }, + ["Mohbwa Sash"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Red Grs. Thread", + "Red Grass Cloth", + "Mohbwa Cloth", + }, + }, + ["Mohbwa Scarf"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Mohbwa Cloth", + "Mohbwa Thread", + }, + }, + ["Mohbwa Scarf 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 55", + }, + }, + ["Mohbwa Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Mohbwa Grass", + "Mohbwa Grass", + }, + }, + ["Mohbwa Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Spindle", + "Mohbwa Grass", + "Mohbwa Grass", + "Mohbwa Grass", + "Mohbwa Grass", + "Mohbwa Grass", + "Mohbwa Grass", + }, + }, + ["Mokujin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Silk Cloth", + "Feyweald Log", + }, + }, + ["Mokuto"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Silencing Potion", + "Shinobi-Gatana", + }, + }, + ["Mole Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Snapping Mole", + "Snapping Mole", + "Helmet Mole", + "Loam", + "Lugworm", + "Shell Bug", + }, + }, + ["Mole Broth 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Snapping Mole", + "Snapping Mole", + "Helmet Mole", + "Loam", + "Little Worm", + "Shell Bug", + }, + }, + ["Molybdenum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Iron Ore", + "Iron Ore", + "Molybdenum Ore", + }, + }, + ["Molybdenum Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Molybden. Ingot", + }, + }, + ["Monk's Nodowa"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Yggdreant Root", + "Dark Matter", + "Azure Leaf", + "Sapphire Crystal", + "Moldy Nodowa", + }, + }, + ["Monster Axe"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Plating", + "Dark Matter", + "S. Faulpie Leather", + "Moldy Axe", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Topaz Crystal", + }, + }, + ["Mont Blanc"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Chestnut", + "Chestnut", + "Selbina Milk", + "Distilled Water", + "Bird Egg", + }, + }, + ["Montagna"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Maple Sugar", + "Olive Oil", + "Habaneros", + "Imperial Flour", + "Bird Egg", + "Buffalo Meat", + "Burdock", + }, + }, + ["Moon Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonstone", + "Gold Earring", + }, + }, + ["Moon Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold. Kit 65", + }, + }, + ["Moon Earring 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonstone", + "Gold Earring +1", + }, + }, + ["Moon Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonstone", + "Gold Ring", + }, + }, + ["Moon Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonstone", + "Gold Ring +1", + }, + }, + ["Moonbeam Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonbow Cloth", + "Moonlight Coral", + "S. Faulpie Leather", + }, + }, + ["Moonbeam Necklace"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonbow Stone", + "Moonlight Coral", + "Khoma Thread", + }, + }, + ["Moonbeam Nodowa"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonbow Steel", + "Moonlight Coral", + "Khoma Thread", + }, + }, + ["Moonbeam Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Moonbow Stone", + "Moonlight Coral", + "Cyan Coral", + }, + }, + ["Moonbow Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonbow Steel", + "Moonbow Cloth", + "Moonbow Leather", + "Khoma Belt", + }, + }, + ["Moonbow Whistle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonbow Urushi", + "Moonbow Stone", + "Brioso Whistle", + }, + }, + ["Moonring Blade"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Tama-Hagane", + "Gold Ingot", + "Mercury", + }, + }, + ["Moonstone"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Carbite", + }, + }, + ["Morion Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Earring", + "Morion Tathlum", + }, + }, + ["Mousai Crackows"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cashmere Thrd.", + "Yggdreant Bole", + "Plovid Effluvium", + "Hades' Claw", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Mousai Gages"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cashmere Thrd.", + "Cashmere Thrd.", + "Yggdreant Bole", + "Plovid Effluvium", + "Hades' Claw", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Mousai Manteel"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cashmere Cloth", + "Yggdreant Bole", + "Plovid Effluvium", + "Plovid Effluvium", + "Hades' Claw", + "Cyan Orb", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Mousai Seraweels"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cashmere Cloth", + "Yggdreant Bole", + "Plovid Effluvium", + "Hades' Claw", + "Cyan Orb", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Mousai Turban"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cashmere Cloth", + "Yggdreant Bole", + "Plovid Effluvium", + "Hades' Claw", + "Cyan Orb", + "Cyan Orb", + }, + }, + ["Movalpolos Water"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Carbon Dioxide", + "Distilled Water", + "Distilled Water", + "Distilled Water", + "Distilled Water", + }, + }, + ["Mufflers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Chain Mittens", + }, + }, + ["Muketsu"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Sakurafubuki", + }, + }, + ["Mulsum"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Honey", + "Grape Juice", + "Distilled Water", + }, + }, + ["Muscle Belt"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Gold Ingot", + "Manticore Lth.", + }, + }, + ["Mushroom Crepe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Black Pepper", + "Danceshroom", + "Puffball", + "Bird Egg", + "Beaugreens", + "Uleguerand Milk", + }, + }, + ["Mushroom Paella"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Tarutaru Rice", + "Saffron", + "Woozyshroom", + "Danceshroom", + "Wild Onion", + "Coral Fungus", + "Distilled Water", + }, + }, + ["Mushroom Risotto"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Selbina Butter", + "Tarutaru Rice", + "Black Pepper", + "Olive Oil", + "Danceshroom", + "Puffball", + "Distilled Water", + }, + }, + ["Mushroom Salad"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Olive Oil", + "Batagreens", + "Woozyshroom", + "King Truffle", + "Nopales", + "Burdock", + "Walnut", + "Agaricus", + }, + }, + ["Mushroom Saute"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Selbina Butter", + "Danceshroom", + "Reishi Mushroom", + "Misx. Parsley", + "Walnut", + "Agaricus", + }, + }, + ["Mushroom Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Danceshroom", + "Scream Fungus", + "Coral Fungus", + "Distilled Water", + }, + }, + ["Mushroom Stew"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Popoto", + "Black Pepper", + "Rock Salt", + "Danceshroom", + "Puffball", + "Coral Fungus", + "Distilled Water", + }, + }, + ["Musketeer Gun +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Musketeer Gun", + }, + }, + ["Musketeer's Pole +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Musketeer's Pole", + }, + }, + ["Musketeer's Sword +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Musketeer's Sword", + }, + }, + ["Musketoon"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Brass Ingot", + "Willow Lumber", + }, + }, + ["Muting Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Wind Anima", + "Water Anima", + "Dark Anima", + "2Leaf Mandra Bud", + "Scream Fungus", + }, + }, + ["Muting Potion 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Wind Anima", + "Water Anima", + "Dark Anima", + "Distilled Water", + "Sobbing Fungus", + "Sobbing Fungus", + }, + }, + ["Mutton Tortilla"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "La Theine Cbg.", + "G. Sheep Meat", + "Mithran Tomato", + "Tortilla", + "Tomato Juice", + "Stone Cheese", + }, + }, + ["Myrtle Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Desk", + "Green Text. Dye", + }, + }, + ["Mythic Harp"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Ancient Lumber", + "Coeurl Whisker", + }, + }, + ["Mythic Harp 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 90", + }, + }, + ["Mythic Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Ancient Lumber", + }, + }, + ["Mythic Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Phoenix Feather", + }, + }, + ["Mythril Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Chestnut Lumber", + }, + }, + ["Mythril Baselard"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Bell"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Tin Ingot", + "Manticore Hair", + "Molybden. Ingot", + "Scintillant Ingot", + }, + }, + ["Mythril Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Mtl. Bolt Heads", + }, + }, + ["Mythril Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Mtl. Bolt Heads", + "Mtl. Bolt Heads", + "Mtl. Bolt Heads", + "Bundling Twine", + }, + }, + ["Mythril Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Ingot", + }, + }, + ["Mythril Breastplate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Ram Leather", + "Ram Leather", + }, + }, + ["Mythril Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mandrel", + }, + }, + ["Mythril Claws"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Beetle Jaw", + }, + }, + ["Mythril Claymore"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Holly Lumber", + "Dhalmel Leather", + }, + }, + ["Mythril Coil"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mandrel", + }, + }, + ["Mythril Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 60", + }, + }, + ["Mythril Cuisses 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Ram Leather", + }, + }, + ["Mythril Dagger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Degen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Mythril Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Darksteel Sheet", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Mythril Gear Machine"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Sheet", + }, + }, + ["Mythril Gorget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Chain", + "Gold Ingot", + "Jadeite", + "Mercury", + }, + }, + ["Mythril Grip"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mandrel", + }, + }, + ["Mythril Heart"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Lockheart", + }, + }, + ["Mythril Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mtl. Beastcoin", + "Mtl. Beastcoin", + "Mtl. Beastcoin", + "Mtl. Beastcoin", + }, + }, + ["Mythril Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ore", + "Mythril Ore", + "Mythril Ore", + "Mythril Ore", + }, + }, + ["Mythril Ingot 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 40", + }, + }, + ["Mythril Ingot 4"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ore", + "Mythril Nugget", + "Mythril Nugget", + "Mythril Nugget", + "Mythril Nugget", + "Mythril Nugget", + "Mythril Nugget", + }, + }, + ["Mythril Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Chestnut Lumber", + }, + }, + ["Mythril Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Mythril Sheet", + "Chestnut Lumber", + }, + }, + ["Mythril Kukri"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Oak Lumber", + "Raptor Skin", + }, + }, + ["Mythril Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Ash Lumber", + "Ash Lumber", + }, + }, + ["Mythril Leggings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Darksteel Sheet", + "Ram Leather", + "Ram Leather", + }, + }, + ["Mythril Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Mesh Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Wind Anima", + "Wind Anima", + "Light Anima", + }, + }, + ["Mythril Nugget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Leaf", + "Panacea", + }, + }, + ["Mythril Pick"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Elm Lumber", + }, + }, + ["Mythril Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Mythril Ingot", + "Mythril Ingot", + }, + }, + ["Mythril Rod 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 45", + }, + }, + ["Mythril Sallet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Mythril Sheet", + "Darksteel Sheet", + "Sheep Leather", + }, + }, + ["Mythril Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Yew Lumber", + "Grass Cloth", + }, + }, + ["Mythril Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + }, + }, + ["Mythril Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Workshop Anvil", + }, + }, + ["Mythril Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Dhalmel Leather", + }, + }, + ["Mythril Zaghnal"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Walnut Lumber", + "Grass Cloth", + }, + }, + ["Nadziak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Oak Lumber", + "Gold Ingot", + "Mercury", + }, + }, + ["Nagan"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Mahogany Lbr.", + "Gold Ingot", + "Wyvern Skin", + }, + }, + ["Naigama"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bldwd. Lumber", + "Karakul Leather", + "Relic Steel", + "Marid Tusk", + "Scintillant Ingot", + }, + }, + ["Nakajimarai"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Rhodium Ingot", + "Umbril Ooze", + "Acuex Poison", + "Shinobi-Gatana", + }, + }, + ["Nanti Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Waktza Rostrum", + "Gua. Lumber", + }, + }, + ["Narasimha Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Narasimha Hide", + "Distilled Water", + }, + }, + ["Narasimha Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Narasimha Hide", + "Distilled Water", + }, + }, + ["Narasimha's Cesti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Narasimha Lth.", + "Cesti", + }, + }, + ["Narasimha's Vest"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Beeswax", + "Manticore Lth.", + "Narasimha Lth.", + "Cardinal Vest", + }, + }, + ["Nathushne"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Kidney Stone", + "Belladonna Sap", + "Healing Staff", + }, + }, + ["Navarin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "G. Sheep Meat", + "Wild Onion", + "Mithran Tomato", + "Distilled Water", + }, + }, + ["Navy Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Mythril Axe", + }, + }, + ["Nebimonite Bake"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Selbina Butter", + "Nebimonite", + }, + }, + ["Negoroshiki"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Steel Ingot", + "Darksteel Ingot", + "Oak Lumber", + }, + }, + ["Nepenthe Grip"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mandrel", + "Rhodium Ingot", + "Gabbrath Horn", + }, + }, + ["Nero di Seppia"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Black Pepper", + "Olive Oil", + "Holy Basil", + "Spaghetti", + "Wild Onion", + "Mithran Tomato", + "Kalamar", + }, + }, + ["Nero di Seppia 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Black Pepper", + "Olive Oil", + "Holy Basil", + "Spaghetti", + "Wild Onion", + "Mithran Tomato", + "Cone Calamary", + }, + }, + ["Neutralizing Silver Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ore", + "Silver Ore", + "Silver Ore", + "Silver Ore", + "Fire Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Ngoma"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Divine Log", + "Buffalo Leather", + }, + }, + ["Night Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Painite", + "Gold Earring", + }, + }, + ["Night Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Painite", + "Gold Earring +1", + }, + }, + ["Ninja Nodowa"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Yggdreant Root", + "Dark Matter", + "Azure Leaf", + "Tanzanite Crystal", + "Moldy Nodowa", + }, + }, + ["Niobium Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Niobium Ore", + "Niobium Ore", + "Niobium Ore", + "Niobium Ore", + }, + }, + ["Noble Himantes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Himantes", + }, + }, + ["Noble's Bed"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Gold Ingot", + "Gold Thread", + "Velvet Cloth", + "Silk Cloth", + }, + }, + ["Noble's Crown"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Gold Ingot", + "Topaz", + }, + }, + ["Noble's Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Cotton Cloth", + "Rainbow Cloth", + "Saruta Cotton", + }, + }, + ["Noble's Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Rainbow Cloth", + "Tiger Leather", + }, + }, + ["Noble's Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Rainbow Cloth", + "Rainbow Cloth", + }, + }, + ["Noble's Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Rainbow Cloth", + "Shining Cloth", + }, + }, + ["Noct Beret"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Chocobo Fthr.", + "Chocobo Fthr.", + "Sheep Leather", + }, + }, + ["Noct Brais"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Sheep Leather", + }, + }, + ["Noct Doublet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + "Sheep Leather", + }, + }, + ["Noct Gaiters"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Noct Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Sheep Leather", + }, + }, + ["Nodachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Iron Ingot", + "Tama-Hagane", + "Tama-Hagane", + "Ash Lumber", + "Cotton Thread", + "Lizard Skin", + }, + }, + ["Nodowa"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Silk Thread", + }, + }, + ["Nohkux Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Midrium Ingot", + "Midrium Ingot", + "Rhodium Ingot", + "Urunday Lumber", + }, + }, + ["Nomad's Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rabbit Hide", + "Traveler's Mantle", + }, + }, + ["Nopales Salad"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Olive Oil", + "Rock Salt", + "Coriander", + "Kitron", + "Wild Onion", + "Mithran Tomato", + "Nopales", + }, + }, + ["Northern Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Undead Skin", + "Tiger Jerkin", + }, + }, + ["Numinous Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 84", + }, + }, + ["Numinous Shield 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Ancient Lumber", + "Round Shield", + }, + }, + ["Nuna Gorget"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheep Leather", + "Craklaw Pincer", + }, + }, + ["Nurigomeyumi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "P. Brass Sheet", + "Wisteria Lumber", + "Wisteria Lumber", + "Urushi", + "Gendawa", + }, + }, + ["Nymph Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Oak Lumber", + "Faerie Shield", + }, + }, + ["Oak Bed"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Oak Cudgel"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + }, + }, + ["Oak Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Log", + }, + }, + ["Oak Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Log", + "Oak Log", + "Oak Log", + "Bundling Twine", + }, + }, + ["Oak Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Oak Lumber", + }, + }, + ["Oak Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Oak Lumber", + "Oak Lumber", + }, + }, + ["Oak Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Blk. Tiger Fang", + }, + }, + ["Oak Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + }, + }, + ["Ob. Gold Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Oberon's Gold", + }, + }, + ["Obelisk Lance"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Willow Lumber", + "Lance", + "Obelisk", + }, + }, + ["Oberon's Gold"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ore", + "Gold Ore", + "Gold Ore", + "Fool's Gold Ore", + }, + }, + ["Oberon's Knuckles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mahogany Lbr.", + "Gargouille Eye", + "Gargouille Eye", + "Oberon's Gold", + }, + }, + ["Oberon's Rapier"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Fluorite", + "Mercury", + "Oberon's Gold", + }, + }, + ["Oberon's Sainti"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Ebony Lumber", + "Platinum Ingot", + "Mercury", + "Oberon's Gold", + }, + }, + ["Obsidian Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Teak Lumber", + "Obsid. Arrowhd.", + "Gnat Fletchings", + }, + }, + ["Obsidian Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Obsidian", + "Obsidian", + }, + }, + ["Octopus Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Ground Wasabi", + "Gigant Octopus", + }, + }, + ["Octopus Sushi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Ground Wasabi", + "Contortopus", + "Contortopus", + }, + }, + ["Octopus Sushi 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Ground Wasabi", + "Contortacle", + "Contortacle", + "Contortacle", + }, + }, + ["Oden"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fish Stock", + "Konjak", + "Daikon", + "Chikuwa", + }, + }, + ["Odorous Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "White Steel", + "Magnolia Lumber", + }, + }, + ["Ogapepo Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Sheep Chammy", + "Sheep Chammy", + "Bztavian Wing", + "Bztavian Wing", + }, + }, + ["Ogre Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Coeurl Gloves", + }, + }, + ["Ogre Jambiya"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Silver Ingot", + "Sunstone", + "Mercury", + "Buggane Horn", + }, + }, + ["Ogre Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Undead Skin", + "Manticore Lth.", + "Coeurl Jerkin", + }, + }, + ["Ogre Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Coeurl Ledelsens", + }, + }, + ["Ogre Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Coeurl Mask", + }, + }, + ["Ogre Sickle"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Ebony Lumber", + "Ruszor Leather", + "Buggane Horn", + }, + }, + ["Ogre Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Manticore Lth.", + "Coeurl Trousers", + }, + }, + ["Oil-Soaked Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Gold Thread", + "Flaxseed Oil", + "Flaxseed Oil", + "Flaxseed Oil", + "Wamoura Silk", + }, + }, + ["Omelette Sandwich"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "White Bread", + "Apkallu Egg", + "Puk Egg", + "Graubg. Lettuce", + }, + }, + ["Onyx"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Black Rock", + }, + }, + ["Onyx 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Shadow Geode", + }, + }, + ["Onyx Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Onyx", + "Silver Earring", + }, + }, + ["Onyx Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Onyx", + "Silver Earring +1", + }, + }, + ["Onyx Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Onyx", + "Silver Ring", + }, + }, + ["Onyx Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Onyx", + "Silver Ring +1", + }, + }, + ["Opal Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Light Opal", + "Silver Earring", + }, + }, + ["Opal Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Light Opal", + "Silver Earring +1", + }, + }, + ["Opal Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Light Opal", + "Silver Ring", + }, + }, + ["Opal Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Light Opal", + "Silver Ring +1", + }, + }, + ["Opaline Boots"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Silk Cloth", + "Rainbow Cloth", + "Sheep Leather", + "Sheep Leather", + "Manticore Lth.", + "Twinthread", + }, + }, + ["Opaline Dress"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + "Rainbow Cloth", + "Twinthread", + "Twinthread", + }, + }, + ["Opaline Hose"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Thread", + "Silk Thread", + "Velvet Cloth", + "Velvet Cloth", + "Twinthread", + "Twinthread", + }, + }, + ["Opprimo"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Walnut Lumber", + "Thokcha Ingot", + "Thokcha Ingot", + "P. Brass Ingot", + }, + }, + ["Orange Cake"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Maple Sugar", + "Olive Oil", + "Selbina Milk", + "Saruta Orange", + "Bird Egg", + "Apkallu Egg", + }, + }, + ["Orange Juice"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Saruta Orange", + "Saruta Orange", + "Saruta Orange", + "Saruta Orange", + }, + }, + ["Orange Juice 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cook. Kit 10", + }, + }, + ["Orange Kuchen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Saruta Orange", + "Saruta Orange", + "Bird Egg", + }, + }, + ["Orange Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Brass Tank", + "Orange au Lait", + "Orange au Lait", + "Orange au Lait", + "Orange au Lait", + }, + }, + ["Orange au Lait"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Honey", + "Selbina Milk", + "Saruta Orange", + "Saruta Orange", + }, + }, + ["Orchestrion"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Melodious Plans", + "Timbre Case Kit", + "Musichinery Kit", + }, + }, + ["Orichalcum Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Ocl. Ingot", + }, + }, + ["Orichalcum Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + }, + }, + ["Orichalcum Dagger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Ocl. Ingot", + "Ruby", + }, + }, + ["Orichalcum Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Ocl. Ingot", + }, + }, + ["Orichalcum Gearbox"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Ocl. Ingot", + }, + }, + ["Orichalcum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + }, + }, + ["Orichalcum Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Ash Lumber", + "Ash Lumber", + "Ocl. Ingot", + "Ruby", + }, + }, + ["Orichalcum Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Ocl. Ingot", + }, + }, + ["Orichalcum Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Yew Lumber", + "Ocl. Ingot", + "Ruby", + "Grass Cloth", + }, + }, + ["Orichalcum Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + }, + }, + ["Orichalcum Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Workshop Anvil", + }, + }, + ["Orochi Nodowa"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Hydra Scale", + "Wamoura Silk", + }, + }, + ["Ortolana"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Olive Oil", + "Rock Salt", + "Spaghetti", + "Frost Turnip", + "Eggplant", + "Nopales", + }, + }, + ["Oshosi Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Sheet", + "Waktza Crest", + "Plovid Flesh", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Oshosi Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Waktza Crest", + "Plovid Flesh", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Oshosi Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Waktza Crest", + "Plovid Flesh", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Oshosi Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Waktza Crest", + "Plovid Flesh", + "Cypress Lumber", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Oshosi Vest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Waktza Crest", + "Plovid Flesh", + "Plovid Flesh", + "Cypress Lumber", + "Cypress Lumber", + "Cypress Lumber", + }, + }, + ["Osseous Serum"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Mercury", + }, + }, + ["Ouka Ranman"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Firesand", + "Amaryllis", + "Bast Parchment", + "Bast Parchment", + }, + }, + ["Ovinnik Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Ovinnik Hide", + "Distilled Water", + }, + }, + ["Ovinnik Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Ovinnik Hide", + "Distilled Water", + }, + }, + ["Ox Tongue"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Ash Lumber", + "Gold Ingot", + "Aquamarine", + "Gold Thread", + }, + }, + ["Oxblood Orb"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Oxblood", + }, + }, + ["Oxidant Baselard"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Rhodium Ingot", + "Umbril Ooze", + "Acuex Poison", + "Mythril Baselard", + }, + }, + ["Oxidant Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Acid Bolt Heads", + "Urunday Lumber", + }, + }, + ["Oxidant Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Acid Bolt Heads", + "Acid Bolt Heads", + "Acid Bolt Heads", + "Bundling Twine", + "Urunday Lumber", + "Urunday Lumber", + "Urunday Lumber", + }, + }, + ["Oxossi Facon"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Manta Leather", + "Cassia Lumber", + "Simian Horn", + }, + }, + ["Padded Armor"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Iron Sheet", + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Padded Box"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bast Parchment", + "Bast Parchment", + "Inferior Cocoon", + }, + }, + ["Padded Box 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 5", + }, + }, + ["Padded Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Lizard Skin", + "Lizard Skin", + }, + }, + ["Painite"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Fenrite", + }, + }, + ["Painite Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Painite", + "Gold Ring", + }, + }, + ["Painite Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Painite", + "Gold Ring +1", + }, + }, + ["Pak Corselet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Behem. Leather", + "Behem. Leather", + "Mercury", + "Siren's Macrame", + "Fiendish Skin", + "Scintillant Ingot", + "Tanzanite Jewel", + }, + }, + ["Paktong Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Firesand", + "Paktong Ingot", + }, + }, + ["Paktong Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ore", + "Copper Ore", + "Zinc Ore", + "Kopparnickel Ore", + }, + }, + ["Palladian Brass Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "P. Brass Ingot", + "P. Brass Ingot", + }, + }, + ["Palladian Brass Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "P. Brass Ore", + "P. Brass Ore", + "P. Brass Ore", + "P. Brass Ore", + }, + }, + ["Palladian Brass Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "P. Brass Ingot", + }, + }, + ["Palmer's Bangles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rogue's Silver", + "Silver Bangles", + }, + }, + ["Pamama Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Brass Tank", + "Pamama au Lait", + "Pamama au Lait", + "Pamama au Lait", + "Pamama au Lait", + }, + }, + ["Pamama Tart"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Pamamas", + "Bbl. Chocolate", + "Bbl. Chocolate", + "Distilled Water", + "Bird Egg", + }, + }, + ["Pamama au Lait"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Honey", + "Selbina Milk", + "Pamamas", + "Pamamas", + }, + }, + ["Pamun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Damascus Ingot", + "Ormolu Ingot", + "Habu Skin", + "Bztavian Wing", + }, + }, + ["Panacea"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Phil. Stone", + "Sulfur", + }, + }, + ["Panther Mask"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Ram Leather", + "Wyvern Skin", + "H.Q. Coeurl Hide", + "H.Q. Coeurl Hide", + }, + }, + ["Pantin Fists"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hades' Claw", + "Dark Matter", + "S. Faulpie Leather", + "Moldy Weapon", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Sardonyx Crystal", + }, + }, + ["Papillion"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Insect Wing", + "Insect Wing", + "Artificial Lens", + "Prism Powder", + }, + }, + ["Paralysis Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Apkal. Fletching", + "Par. Arrowheads", + }, + }, + ["Paralysis Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Animal Glue", + "Imperial Cermet", + "Paralyze Potion", + }, + }, + ["Paralysis Dust"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Puffball", + "Puffball", + }, + }, + ["Paralysis Dust 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Three-eyed Fish", + }, + }, + ["Paralyze Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Paralysis Dust", + }, + }, + ["Paralyze Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Mercury", + "Mercury", + "Paralysis Dust", + "Paralysis Dust", + "Paralysis Dust", + "Triturator", + }, + }, + ["Parchment"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Karakul Leather", + "Rolanberry", + }, + }, + ["Parchment 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheep Leather", + "Rolanberry", + }, + }, + ["Parclose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Teak Lumber", + "Teak Lumber", + }, + }, + ["Partisan"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Ash Lumber", + "Silver Thread", + }, + }, + ["Partition"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + }, + }, + ["Passaddhi Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Blk. Tiger Fang", + "Hefty Oak Lbr.", + }, + }, + ["Pastoral Staff"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Quarterstaff", + }, + }, + ["Patas"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Iron Sheet", + "Carbon Fiber", + }, + }, + ["Patlican Salata"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Eggplant", + "Eggplant", + "Yogurt", + }, + }, + ["Pattern Reader"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Wind Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Pea Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blue Peas", + "Blue Peas", + "Blue Peas", + "Dried Marjoram", + "Wild Onion", + "Distilled Water", + }, + }, + ["Peace Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Silk Cloth", + "Amity Cape", + }, + }, + ["Pealing Anelace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Luminous Core", + "Anelace", + }, + }, + ["Pealing Nagan"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Luminous Core", + "Nagan", + }, + }, + ["Peapuk Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Peapuk Wing", + "Peapuk Wing", + }, + }, + ["Peapuk Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Peapuk Wing", + "Peapuk Wing", + "Peapuk Wing", + "Peapuk Wing", + "Peapuk Wing", + "Peapuk Wing", + }, + }, + ["Pear Crepe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Cinnamon", + "Derfland Pear", + "Faerie Apple", + "Honey", + "Bird Egg", + "Uleguerand Milk", + }, + }, + ["Pear Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Brass Tank", + "Pear au Lait", + "Pear au Lait", + "Pear au Lait", + "Pear au Lait", + }, + }, + ["Pear au Lait"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Derfland Pear", + "Derfland Pear", + "Honey", + "Selbina Milk", + }, + }, + ["Pearl"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Shall Shell", + }, + }, + ["Pearl 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Istiridye", + }, + }, + ["Pearl Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pearl", + "Mythril Earring", + }, + }, + ["Pearl Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pearl", + "Mythril Earring +1", + }, + }, + ["Pearl Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pearl", + "Mythril Ring", + }, + }, + ["Pearl Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pearl", + "Mythril Ring +1", + }, + }, + ["Pebble Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Flint Stone", + "Flint Stone", + "Flint Stone", + "Distilled Water", + }, + }, + ["Pebble Soup 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 5", + }, + }, + ["Peeled Crayfish"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Crayfish", + }, + }, + ["Peeled Lobster"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Lobster", + }, + }, + ["Peeled Lobster 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Istakoz", + }, + }, + ["Peiste Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Chain", + "Peiste Leather", + }, + }, + ["Peiste Dart"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Animal Glue", + "Gnat Wing", + "Gnat Wing", + "Peiste Stinger", + }, + }, + ["Peiste Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Peiste Skin", + "Distilled Water", + }, + }, + ["Peiste Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Peiste Skin", + "Distilled Water", + }, + }, + ["Peiste Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tanning Vat", + "Peiste Skin", + "Peiste Skin", + "Peiste Skin", + "Distilled Water", + }, + }, + ["Peiste Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Peiste Skin", + "Peiste Skin", + }, + }, + ["Peiste Mantle 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 95", + }, + }, + ["Pellet Belt"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sheep Leather", + "Igneous Rock", + "Igneous Rock", + "Leather Pouch", + }, + }, + ["Pendragon's Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "S. Bgd. Leather", + "Koenigs Belt", + }, + }, + ["Pennon Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gnat Wing", + "Gnat Wing", + "Electrum Ingot", + }, + }, + ["Peperoncino"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Olive Oil", + "Rock Salt", + "Spaghetti", + "Misx. Parsley", + }, + }, + ["Pepper Biscuit"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Black Pepper", + "Crawler Egg", + "Honey", + "Acorn", + "Acorn", + "Acorn", + }, + }, + ["Pepperoni"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Black Pepper", + "Sage", + "Oak Log", + "Rock Salt", + "G. Sheep Meat", + "Buffalo Meat", + }, + }, + ["Pepperoni Pizza"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pizza Dough", + "Pomodoro Sauce", + "Misx. Parsley", + "Pepperoni", + "Agaricus", + "Chalaimbille", + }, + }, + ["Pepperoni Slice"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pizza Dough", + "Pomodoro Sauce", + "Misx. Parsley", + "Pepperoni", + "Agaricus", + "Chalaimbille", + "Pizza Cutter", + }, + }, + ["Peridot Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Peridot", + "Mythril Earring", + }, + }, + ["Peridot Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold. Kit 45", + }, + }, + ["Peridot Earring 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Peridot", + "Mythril Earring +1", + }, + }, + ["Peridot Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Peridot", + "Mythril Ring", + }, + }, + ["Peridot Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Peridot", + "Mythril Ring +1", + }, + }, + ["Persikos Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Brass Tank", + "Persikos au Lait", + "Persikos au Lait", + "Persikos au Lait", + "Persikos au Lait", + }, + }, + ["Persikos au Lait"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Persikos", + "Persikos", + "Honey", + "Selbina Milk", + }, + }, + ["Personal Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Rosewood Lbr.", + "Gold Ingot", + }, + }, + ["Pescatora"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Spaghetti", + "Sandfish", + "Grimmonite", + "Gold Lobster", + "Shall Shell", + "Pomodoro Sauce", + }, + }, + ["Pescatora 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Spaghetti", + "Sandfish", + "Pomodoro Sauce", + "Istakoz", + "Ahtapot", + "Istiridye", + }, + }, + ["Pet Food Alpha"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Horo Flour", + "Hare Meat", + "Distilled Water", + "Bird Egg", + }, + }, + ["Pet Food Beta"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Horo Flour", + "G. Sheep Meat", + "Distilled Water", + "Bird Egg", + }, + }, + ["Pet Food Beta 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Horo Flour", + "Distilled Water", + "Apkallu Egg", + "Karakul Meat", + }, + }, + ["Pet Food Delta"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rye Flour", + "Land Crab Meat", + "Distilled Water", + "Bird Egg", + }, + }, + ["Pet Food Epsilon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rye Flour", + "Lizard Egg", + "Distilled Water", + "Ziz Meat", + }, + }, + ["Pet Food Epsilon 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rye Flour", + "Lizard Egg", + "Cockatrice Meat", + "Distilled Water", + }, + }, + ["Pet Food Eta"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Distilled Water", + "Buffalo Meat", + "Apkallu Egg", + }, + }, + ["Pet Food Gamma"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Horo Flour", + "Dhalmel Meat", + "Distilled Water", + "Bird Egg", + }, + }, + ["Pet Food Theta"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Distilled Water", + "Puk Egg", + "Ruszor Meat", + }, + }, + ["Pet Food Zeta"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Lizard Egg", + "Coeurl Meat", + "Distilled Water", + }, + }, + ["Pet Poultice"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Linen Cloth", + "Flaxseed Oil", + "Lycopodium Flower", + "Holy Water", + }, + }, + ["Pet Roborant"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Boyahda Moss", + "Hecteyes Eye", + "Beast Blood", + "Scream Fungus", + "Ca Cuong", + }, + }, + ["Ph. Gold Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ph. Gold Ingot", + }, + }, + ["Ph. Gold Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ph. Gold Ingot", + "Ph. Gold Ingot", + "Ph. Gold Ingot", + "Ph. Gold Ingot", + "Ph. Gold Ingot", + "Ph. Gold Ingot", + "Workshop Anvil", + }, + }, + ["Phantom Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Earring", + "Phtm. Tathlum", + }, + }, + ["Phos Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Scarlet Kadife", + "Sealord Leather", + "Sonic Belt", + }, + }, + ["Photoanima"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fire Anima", + "Ice Anima", + "Wind Anima", + "Earth Anima", + "Lightning Anima", + "Water Anima", + "Light Anima", + "Dark Anima", + }, + }, + ["Phrygian Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ph. Gold Ingot", + "Ph. Gold Ingot", + }, + }, + ["Phrygian Gold Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Phrygian Ore", + "Phrygian Ore", + "Phrygian Ore", + "Phrygian Ore", + }, + }, + ["Phrygian Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ph. Gold Ingot", + "Ph. Gold Ingot", + }, + }, + ["Phrygian Ring 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 94", + }, + }, + ["Piccolo"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Holly Lumber", + "Parchment", + }, + }, + ["Piccolo 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 20", + }, + }, + ["Pickaxe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Maple Lumber", + }, + }, + ["Pickled Herring"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Rock Salt", + "Nosteau Herring", + }, + }, + ["Pickled Rarab Tail"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Water Barrel", + "Smooth Stone", + "Kazham Peppers", + "Mhaura Garlic", + "Rock Salt", + "Sea Foliage", + "Kitron", + "Rarab Tail", + }, + }, + ["Pie Dough"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Rock Salt", + }, + }, + ["Piercing Dagger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Water Cell", + "Lam. Wind Cell", + "Brass Dagger", + }, + }, + ["Pigaches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Silk Cloth", + "Raptor Skin", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Pigeon Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Pigeon's Blood", + "Platinum Earring", + }, + }, + ["Pineapple Juice"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kazham Pineapl.", + "Kazham Pineapl.", + }, + }, + ["Pineapple Juice 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cook. Kit 30", + }, + }, + ["Pinga Crown"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Rockfin Tooth", + "Defiant Scarf", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Pinga Mittens"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Rockfin Tooth", + "Defiant Scarf", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Pinga Pants"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Rockfin Tooth", + "Defiant Scarf", + "Azure Cermet", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Pinga Pumps"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Rockfin Tooth", + "Defiant Scarf", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Pinga Tunic"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Rockfin Tooth", + "Defiant Scarf", + "Defiant Scarf", + "Azure Cermet", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Pinwheel"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Animal Glue", + "Bast Parchment", + "Bast Parchment", + }, + }, + ["Pirate's Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Darksteel Ingot", + "Turtle Shell", + }, + }, + ["Pizza Cutter"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Holly Lumber", + }, + }, + ["Pizza Dough"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Selbina Butter", + "Olive Oil", + "Rock Salt", + "Semolina", + }, + }, + ["Plain Cap"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rusty Cap", + }, + }, + ["Plain Pick"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rusty Pick", + }, + }, + ["Plain Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Rusty Greatsword", + }, + }, + ["Planus Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Silk Cloth", + "Silk Cloth", + "Siren's Macrame", + "Lancewood Lbr.", + "Lancewood Lbr.", + "Lancewood Lbr.", + "Bloodthread", + }, + }, + ["Plasma Oil"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Flan Meat", + "Flan Meat", + }, + }, + ["Plastron"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Chain", + "Ocl. Ingot", + "Tiger Leather", + "Tiger Leather", + "Kunwu Iron", + "Kunwu Sheet", + }, + }, + ["Plate Leggings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Iron Sheet", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Platinum Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Yagudo Fltchg.", + "Plt. Arrowheads", + }, + }, + ["Platinum Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Platinum Ingot", + }, + }, + ["Platinum Bangles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + }, + }, + ["Platinum Bangles 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 85", + }, + }, + ["Platinum Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Firesand", + }, + }, + ["Platinum Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + }, + }, + ["Platinum Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Mandrel", + }, + }, + ["Platinum Cutlass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Platinum Ingot", + "Mercury", + "Cutlass", + }, + }, + ["Platinum Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + }, + }, + ["Platinum Gear"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Sheet", + }, + }, + ["Platinum Grip"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Mandrel", + }, + }, + ["Platinum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Plt. Beastcoin", + "Plt. Beastcoin", + "Plt. Beastcoin", + "Plt. Beastcoin", + }, + }, + ["Platinum Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ore", + "Platinum Ore", + "Platinum Ore", + "Platinum Ore", + }, + }, + ["Platinum Ingot 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ore", + "Platinum Nugget", + "Platinum Nugget", + "Platinum Nugget", + "Platinum Nugget", + "Platinum Nugget", + "Platinum Nugget", + }, + }, + ["Platinum Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Platinum Ingot", + "Mercury", + "Darksteel Mace", + }, + }, + ["Platinum Nugget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Leaf", + "Panacea", + }, + }, + ["Platinum Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + }, + }, + ["Platinum Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Gold Ingot", + "Platinum Ingot", + }, + }, + ["Platinum Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + }, + }, + ["Platinum Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Workshop Anvil", + }, + }, + ["Platinum Silk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Silk Thread", + }, + }, + ["Platinum Silk 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Platinum Ingot", + "Platinum Ingot", + "Silk Thread", + "Silk Thread", + "Silk Thread", + "Spindle", + }, + }, + ["Poet's Circlet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Mythril Ingot", + }, + }, + ["Pogaca"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Rock Salt", + "Stone Cheese", + "Distilled Water", + "Apkallu Egg", + "Yogurt", + }, + }, + ["Poison Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Chocobo Fltchg.", + "Poison Arrowhd.", + }, + }, + ["Poison Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Animal Glue", + "Poison Potion", + }, + }, + ["Poison Baghnakhs"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Baghnakhs", + }, + }, + ["Poison Baghnakhs 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 35", + }, + }, + ["Poison Baselard"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Baselard", + }, + }, + ["Poison Baselard 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 25", + }, + }, + ["Poison Cesti"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Lizard Cesti", + }, + }, + ["Poison Claws"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Claws", + }, + }, + ["Poison Dagger"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Dagger", + }, + }, + ["Poison Dust"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Deathball", + "Deathball", + }, + }, + ["Poison Dust 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Giant Stinger", + "Giant Stinger", + }, + }, + ["Poison Dust 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Yellow Globe", + "Yellow Globe", + }, + }, + ["Poison Katars"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Katars", + }, + }, + ["Poison Knife"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Knife", + }, + }, + ["Poison Kukri"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Poison Potion", + "Kukri", + }, + }, + ["Poison Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Poison Dust", + }, + }, + ["Poison Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Mercury", + "Mercury", + "Poison Dust", + "Poison Dust", + "Poison Dust", + "Triturator", + }, + }, + ["Poisona Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Neutralizing Slv.", + "Silver Ring", + }, + }, + ["Poisonous Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Venom Dust", + "Umbril Ooze", + "Distilled Water", + "Gnatbane", + }, + }, + ["Polyflan"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Flan Meat", + "Chimera Blood", + }, + }, + ["Polyflan Paper"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Polyflan", + }, + }, + ["Pomodoro Sauce"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Bay Leaves", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Holy Basil", + "Wild Onion", + "Mithran Tomato", + "Misx. Parsley", + }, + }, + ["Ponderous Gully"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Spirit Core", + "Gully", + }, + }, + ["Ponderous Lance"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sprt. Orichalcum", + "Orichalcum Lance", + }, + }, + ["Popo. con Queso"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Popoto", + "Rock Salt", + "Danceshroom", + "Selbina Milk", + "Wild Onion", + "Chalaimbille", + }, + }, + ["Popstar"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Firesand", + "Bast Parchment", + "Twinkle Powder", + "Twinkle Powder", + "Prism Powder", + }, + }, + ["Porcelain Flowerpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cermet Chunk", + }, + }, + ["Pork Cutlet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Olive Oil", + "Rock Salt", + "White Bread", + "Bird Egg", + "Porxie Pork", + }, + }, + ["Pork Cutlet Rice Bowl"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Soy Stock", + "2Leaf Mandra Bud", + "Wild Onion", + "Bird Egg", + "Pork Cutlet", + }, + }, + ["Porxie Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Porxie Wing", + "Porxie Wing", + }, + }, + ["Porxie Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Porxie Wing", + "Porxie Wing", + "Porxie Wing", + "Porxie Wing", + "Porxie Wing", + "Porxie Wing", + }, + }, + ["Poseidon's Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Aqueous Ocl.", + "Orichalcum Ring", + }, + }, + ["Pot-au-feu"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Giant Femur", + "Hare Meat", + "Frost Turnip", + "San d'Or. Carrot", + }, + }, + ["Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Lizard Tail", + "Distilled Water", + }, + }, + ["Potion Drop"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sage", + "Lizard Tail", + "Distilled Water", + }, + }, + ["Potion Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Brass Tank", + "Potion", + "Potion", + "Potion", + "Potion", + }, + }, + ["Poultry Pitaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Olive Oil", + "Rock Salt", + "Imperial Flour", + "Cockatrice Meat", + "Distilled Water", + "Apkallu Egg", + "Graubg. Lettuce", + }, + }, + ["Powder Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tgh. Dhal. Lth.", + "Cuir Highboots", + }, + }, + ["Power Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elm Lumber", + "Elm Lumber", + "Wool Cloth", + "Scorpion Claw", + "Coeurl Whisker", + }, + }, + ["Premium Bag"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Platinum Ingot", + "Rainbow Thread", + "Gold Thread", + "Rainbow Cloth", + "Bugard Leather", + "M. Sheep Lth.", + "M. Sheep Wool", + }, + }, + ["Primate Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Gold Ingot", + "Yellow Rock", + "Yellow Rock", + "Mercury", + "Cassia Lumber", + "Cassia Lumber", + "Vrml. Lacquer", + }, + }, + ["Prism Powder"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Ahriman Lens", + "Glass Fiber", + "Glass Fiber", + }, + }, + ["Prism Powder 2"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Glass Fiber", + "Glass Fiber", + "Artificial Lens", + }, + }, + ["Prism Powder 3"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Glass Fiber", + "Glass Fiber", + "Glass Fiber", + "Glass Fiber", + "Artificial Lens", + "Artificial Lens", + "Triturator", + }, + }, + ["Pristine Sap"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Divine Sap", + "Holy Water", + "Holy Water", + }, + }, + ["Pro-Ether"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Dried Marjoram", + "Ahriman Wing", + "Ahriman Wing", + "Treant Bulb", + "Wyvern Wing", + "Distilled Water", + }, + }, + ["Prominence Axe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Brimsand", + "Inferno Axe", + }, + }, + ["Prominence Sword"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Brimsand", + "Inferno Sword", + }, + }, + ["Protect Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "S. Smil. Leather", + "Smilodon Ring", + }, + }, + ["Puce Chest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Thief's Tools", + "Green Text. Dye", + "Yellow Txt. Dye", + "Gua. Lumber", + }, + }, + ["Puk Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Puk Wing", + "Puk Wing", + }, + }, + ["Puk Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Puk Wing", + "Puk Wing", + "Puk Wing", + "Puk Wing", + "Puk Wing", + "Puk Wing", + }, + }, + ["Pukatrice Egg"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "White Bread", + "Cockatrice Meat", + "Bird Egg", + "Puk Egg", + }, + }, + ["Puls"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rye Flour", + "Horo Flour", + "Honey", + "Distilled Water", + }, + }, + ["Pumpkin Cake"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Maple Sugar", + "Ogre Pumpkin", + "Olive Oil", + "Selbina Milk", + "Bird Egg", + "Apkallu Egg", + }, + }, + ["Pumpkin Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Pie Dough", + "Maple Sugar", + "Cinnamon", + "Ogre Pumpkin", + "Selbina Milk", + "Distilled Water", + "Bird Egg", + }, + }, + ["Pumpkin Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ogre Pumpkin", + "Sage", + "Rock Salt", + "Selbina Milk", + "Distilled Water", + }, + }, + ["Pungent Powder"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Ahriman Lens", + "Silk Cloth", + "Saruta Cotton", + "Glass Fiber", + "Glass Fiber", + "Gelatin", + "Cornstarch", + "Pagodite", + }, + }, + ["Pungent Powder II"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Ahriman Lens", + "Silk Cloth", + "Saruta Cotton", + "Glass Fiber", + "Glass Fiber", + "Revival Root", + "Cornstarch", + "Pagodite", + }, + }, + ["Pungent Powder III"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Ahriman Lens", + "Silk Cloth", + "Saruta Cotton", + "Glass Fiber", + "Glass Fiber", + "Cornstarch", + "Pagodite", + }, + }, + ["Pup. Collar"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Claw", + "Dark Matter", + "Cyan Coral", + "Sardonyx Crystal", + "Moldy Collar", + }, + }, + ["Purple Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fluorite", + "Gold Earring", + }, + }, + ["Purple Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fluorite", + "Gold Earring +1", + }, + }, + ["Pya'ekue Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Bztavian Wing", + "Phos Belt", + }, + }, + ["Qi Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Demon Horn", + "Blue Jasper", + }, + }, + ["Qiqirn Hood"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Lapis Lazuli", + "Lapis Lazuli", + "Wool Cloth", + "Wool Cloth", + "Coeurl Whisker", + "Qiqirn Cape", + }, + }, + ["Qiqirn Sash"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Scarlet Linen", + "Red Grs. Thread", + "Karakul Cloth", + }, + }, + ["Quadav Barbut"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Black Pearl", + "Black Pearl", + "Wool Thread", + "Tiger Leather", + "Lizard Molt", + "Bugard Tusk", + "Red Grass Cloth", + "Quadav Parts", + }, + }, + ["Quake Grenade"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Yuhtunga Sulfur", + "Firesand", + "Firesand", + }, + }, + ["Quake Grenade 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Firesand", + "Firesand", + "Sulfur", + }, + }, + ["Quake Grenade 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Firesand", + "Firesand", + "Sulfur", + "Cluster Ash", + }, + }, + ["Quarterstaff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Walnut Lumber", + "Walnut Lumber", + }, + }, + ["R. Pickled R. Tail"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Apple Vinegar", + "Black Pepper", + "Maple Sugar", + "Rock Salt", + "Ro'Maeve Water", + "Rolanberry", + "Rarab Tail", + "Rarab Tail", + }, + }, + ["Ra'Kaznar Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Ra'Kaznar Ingot", + }, + }, + ["Ra'Kaznar Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ra'Kaznar Ingot", + }, + }, + ["Ra'Kaznar Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ore", + "Darksteel Ore", + "Darksteel Ore", + "Ra'Kaznar Ore", + }, + }, + ["Raaz Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Raaz Tusk", + }, + }, + ["Raaz Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Shagreen File", + "Raaz Tusk", + "Raaz Tusk", + "Raaz Tusk", + }, + }, + ["Raaz Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Distilled Water", + "Raaz Hide", + }, + }, + ["Raaz Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Distilled Water", + "Raaz Hide", + }, + }, + ["Raaz Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tanning Vat", + "Distilled Water", + "Raaz Hide", + "Raaz Hide", + "Raaz Hide", + }, + }, + ["Rabbit Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Rabbit Hide", + "Rabbit Hide", + "Rabbit Hide", + "Rabbit Hide", + "Rabbit Hide", + }, + }, + ["Rabbit Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Pie Dough", + "Black Pepper", + "Rock Salt", + "Wild Onion", + "San d'Or. Carrot", + "Lynx Meat", + "Agaricus", + }, + }, + ["Radical Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leafkin Frond", + "Chapuli Wing", + "Chapuli Wing", + "Raptor Mantle", + }, + }, + ["Raetic Algol"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Thought Crystal", + "Azure Cermet", + "Rune Algol", + }, + }, + ["Raetic Arrow"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Thought Crystal", + "Cypress Lumber", + "Niobium Ore", + "Rune Arrow", + "Rune Arrow", + "Rune Arrow", + }, + }, + ["Raetic Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hope Crystal", + "Niobium Ingot", + "Rune Axe", + }, + }, + ["Raetic Baghnakhs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fulfillment Crystal", + "Ruthenium Ingot", + "Rune Baghnakhs", + }, + }, + ["Raetic Bangles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fulfillment Crystal", + "Cyan Coral", + "Cyan Coral", + "Cyan Orb", + "Cyan Orb", + "Cyan Orb", + "Rune Bangles", + }, + }, + ["Raetic Blade"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Thought Crystal", + "Ruthenium Ingot", + "Rune Blade", + }, + }, + ["Raetic Bow"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Thought Crystal", + "Cypress Lumber", + "Cypress Lumber", + "Cypress Lumber", + "Rune Bow", + }, + }, + ["Raetic Chopper"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fulfillment Crystal", + "Niobium Ingot", + "Rune Chopper", + }, + }, + ["Raetic Halberd"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hope Crystal", + "Cypress Lumber", + "Cypress Lumber", + "Cypress Lumber", + "Rune Halberd", + }, + }, + ["Raetic Kris"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hope Crystal", + "Niobium Ingot", + "Rune Kris", + }, + }, + ["Raetic Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Thought Crystal", + "Niobium Ingot", + "Rune Rod", + }, + }, + ["Raetic Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hope Crystal", + "Cyan Coral", + "Cyan Coral", + "Cyan Orb", + "Cyan Orb", + "Cyan Orb", + "Rune Scythe", + }, + }, + ["Raetic Staff"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fulfillment Crystal", + "Cypress Lumber", + "Cypress Lumber", + "Cypress Lumber", + "Rune Staff", + }, + }, + ["Rainbow Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Rainbow Cloth", + "Rainbow Cloth", + }, + }, + ["Rainbow Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Rainbow Thread", + }, + }, + ["Rainbow Headband"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Cloth", + "Carbon Fiber", + }, + }, + ["Rainbow Headband 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 85", + }, + }, + ["Rainbow Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Rainbow Thread", + "Rainbow Thread", + "Silver Thread", + "Gold Thread", + }, + }, + ["Rainbow Obi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 90", + }, + }, + ["Rainbow Powder"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Glass Fiber", + "Glass Fiber", + "Wamoura Scale", + }, + }, + ["Rainbow Powder 2"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Glass Fiber", + "Glass Fiber", + "Glass Fiber", + "Glass Fiber", + "Triturator", + "Wamoura Scale", + "Wamoura Scale", + }, + }, + ["Rainbow Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Spider Web", + "Spider Web", + }, + }, + ["Rainbow Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Spider Web", + "Spider Web", + "Spider Web", + "Spider Web", + "Spider Web", + "Spider Web", + "Spindle", + }, + }, + ["Rainbow Velvet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Rainbow Thread", + "Rainbow Thread", + }, + }, + ["Raisin Bread"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Rock Salt", + "San d'Or. Grape", + "Distilled Water", + }, + }, + ["Ram Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Ram Skin", + "Distilled Water", + }, + }, + ["Ram Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Ram Skin", + "Ram Skin", + "Ram Skin", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Ram Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Leath. Kit 35", + }, + }, + ["Ram Leather 4"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Ram Skin", + "Distilled Water", + }, + }, + ["Ram Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Ram Skin", + }, + }, + ["Ram-Dao"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Mahogany Lbr.", + "Raptor Skin", + }, + }, + ["Ramen Noodles"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Rock Salt", + "Baking Soda", + "Distilled Water", + }, + }, + ["Rancid Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Frigorifish", + "Frigorifish", + "Frigorifish", + "Frigorifish", + }, + }, + ["Ranging Knife"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Stately Crab Sh.", + }, + }, + ["Ranka"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Night Queen", + "Night Queen", + }, + }, + ["Rapid Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Ebony Lumber", + "Silver Thread", + "Silk Cloth", + }, + }, + ["Rapier"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Gold Ingot", + "Fluorite", + "Mercury", + }, + }, + ["Raptor Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 55", + }, + }, + ["Raptor Gloves 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Raptor Skin", + "Cuir Gloves", + }, + }, + ["Raptor Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Sheep Leather", + "Raptor Skin", + "Raptor Skin", + }, + }, + ["Raptor Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Raptor Skin", + "Raptor Skin", + }, + }, + ["Raptor Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Raptor Skin", + "Cuir Highboots", + }, + }, + ["Raptor Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Raptor Skin", + "Raptor Skin", + }, + }, + ["Raptor Strap"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Raptor Skin", + "Raptor Skin", + }, + }, + ["Raptor Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Raptor Skin", + "Raptor Skin", + "Cuir Trousers", + }, + }, + ["Rarab Meatball"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Mhaura Garlic", + "Black Pepper", + "Rock Salt", + "Hare Meat", + "Stone Cheese", + "Distilled Water", + "Bird Egg", + }, + }, + ["Rasetsu Hakama"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Silk Thread", + "Velvet Cloth", + "Velvet Cloth", + "Sheep Leather", + "Tiger Leather", + "Raxa", + }, + }, + ["Rasetsu Jinpachi"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Tiger Leather", + "Raxa", + }, + }, + ["Rasetsu Samue"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Steel Sheet", + "Rainbow Thread", + "Velvet Cloth", + "Tiger Leather", + "Tiger Leather", + "Raxa", + "Raxa", + }, + }, + ["Rasetsu Sune-Ate"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Silk Thread", + "Tiger Leather", + "Tiger Leather", + "Raxa", + }, + }, + ["Rasetsu Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Iron Chain", + "Linen Thread", + "Tiger Leather", + "Raxa", + }, + }, + ["Ratatouille"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Bay Leaves", + "Olive Oil", + "Wild Onion", + "Eggplant", + "Mithran Tomato", + "Zucchini", + "Paprika", + }, + }, + ["Ratatouille 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 65", + }, + }, + ["Ratri Breastplate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Cehuetzi Claw", + "Macuil Plating", + "Macuil Plating", + "Azure Cermet", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Ratri Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Cehuetzi Claw", + "Macuil Plating", + "Azure Cermet", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Ratri Gadlings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Sheet", + "Cehuetzi Claw", + "Macuil Plating", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Ratri Sallet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Chain", + "Cehuetzi Claw", + "Macuil Plating", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Ratri Sollerets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Cehuetzi Claw", + "Macuil Plating", + "Azure Cermet", + "Azure Cermet", + }, + }, + ["Ravenous Breastplate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "Gold Thread", + "Sealord Leather", + "Rhodium Ingot", + "Macuil Plating", + "Macuil Plating", + }, + }, + ["Razor Brain Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Hare Meat", + "G. Sheep Meat", + "Ziz Meat", + }, + }, + ["Razorfury"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Damascus Ingot", + "Damascus Ingot", + "Ormolu Ingot", + "Urunday Lumber", + "Rockfin Tooth", + }, + }, + ["Reaver Grip"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Malebolge Mand.", + }, + }, + ["Recital Bench"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Hickory Lumber", + "Wolf Felt", + }, + }, + ["Red Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Chocobo Fthr.", + }, + }, + ["Red Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + }, + }, + ["Red Curry"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Curry Powder", + "Coriander", + "Dragon Meat", + "San d'Or. Carrot", + "Mithran Tomato", + "Distilled Water", + }, + }, + ["Red Curry Bun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Olive Oil", + "Red Curry", + "Bird Egg", + }, + }, + ["Red Grass Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Red Grs. Thread", + "Red Grs. Thread", + "Red Grs. Thread", + }, + }, + ["Red Grass Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Red Moko Grass", + "Red Moko Grass", + }, + }, + ["Red Grass Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Red Moko Grass", + "Red Moko Grass", + "Red Moko Grass", + "Red Moko Grass", + "Red Moko Grass", + "Red Moko Grass", + "Spindle", + }, + }, + ["Red Grass Thread 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Cloth. Kit 15", + }, + }, + ["Red Hobby Bo"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Hickory Lumber", + "Dogwd. Lumber", + "Onyx", + "Onyx", + "Red Chocobo Dye", + }, + }, + ["Red Mahogany Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mahogany Bed", + "Wool Thread", + "Red Textile Dye", + }, + }, + ["Red Round Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Linen Cloth", + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Platinum Silk", + "Teak Lumber", + "Red Textile Dye", + }, + }, + ["Red Storm Lantern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Brass Ingot", + "Silver Ingot", + "Silk Cloth", + "Glass Sheet", + "Sailcloth", + "Red Textile Dye", + }, + }, + ["Red Textile Dye"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Nopales", + }, + }, + ["Red Viola"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Red Rock", + "Granite", + "Red Gravel", + "Wildgrass Seeds", + "Humus", + }, + }, + ["Reef Aquarium"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Oak Lumber", + "Coral Fragment", + "Sieglinde Putty", + "Glass Sheet", + "Saltwater Set", + "Coral Butterfly", + "Coral Butterfly", + "Coral Butterfly", + }, + }, + ["Regen Collar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Water Cell", + "Lam. Earth Cell", + "Feather Collar", + }, + }, + ["Regen Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Vivio Platinum", + "Lord's Cuirass", + }, + }, + ["Regiment Kheten"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Kheten", + }, + }, + ["Regulator"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Tank", + "Spect. Goldenrod", + "Chimera Blood", + "Imperial Cermet", + "Umbril Ooze", + }, + }, + ["Relic Steel"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Relic Iron", + "Relic Iron", + }, + }, + ["Reliquary"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Dogwd. Lumber", + "Imp. Silk Cloth", + "A.U. Brass Ingot", + "A.U Brass Sheet", + "A.U Brass Sheet", + }, + }, + ["Remedy"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Chamomile", + "Sage", + "Mistletoe", + "Boyahda Moss", + "Wijnruit", + "Honey", + "Distilled Water", + }, + }, + ["Remedy Ointment"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Qutrub Bandage", + "Distilled Water", + "White Honey", + }, + }, + ["Repeater"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Glass Fiber", + "Sieglinde Putty", + "Glass Sheet", + "Homncl. Nerves", + "High Ebonite", + }, + }, + ["Repeating Crossbow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mahogany Lbr.", + "Rosewood Lbr.", + "Scorpion Claw", + "Coeurl Whisker", + "Carbon Fiber", + }, + }, + ["Replicator"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Sieglinde Putty", + "Polyflan Paper", + "Polyflan Paper", + "Wind Fan", + }, + }, + ["Reppu"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tin Ingot", + "Steel Sheet", + "Kodachi", + }, + }, + ["Republican Legionnaire's Bedding"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Steel Ingot", + "Iron Sheet", + "Iron Sheet", + "Chestnut Lumber", + "Linen Cloth", + "Linen Cloth", + "Saruta Cotton", + }, + }, + ["Reraise Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Vivified Mythril", + "Mythril Earring", + }, + }, + ["Reraise Gorget"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Vivified Coral", + "Coral Gorget", + }, + }, + ["Reraise Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Vivified Coral", + "Coral Hairpin", + }, + }, + ["Resister"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blsd. Mtl. Sheet", + "Goblin Grease", + "Ebonite", + "Water Tank", + "Hydro Pump", + }, + }, + ["Resister II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blsd. Mtl. Sheet", + "Goblin Grease", + "Ebonite", + "Water Tank", + "Kilo Pump", + }, + }, + ["Resolution Ring"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Fiend Blood", + "Dragon Blood", + "Avatar Blood", + "Lizard Blood", + "Bird Blood", + "Chimera Blood", + "Demon Blood", + "Platinum Ring", + }, + }, + ["Revealer's Crown"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Lizard Molt", + "Baldurno's Horn", + "Abyssdiver Feather", + }, + }, + ["Revealer's Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Ancestral Cloth", + "Ancestral Cloth", + "Pitriv's Thread", + "Warblade's Hide", + }, + }, + ["Revealer's Pants"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Ancestral Cloth", + "Ancestral Cloth", + "Pitriv's Thread", + "Warblade's Hide", + }, + }, + ["Revealer's Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ancestral Cloth", + "Ancestral Cloth", + "Pitriv's Thread", + "Pitriv's Thread", + "Warblade's Hide", + }, + }, + ["Revealer's Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Linen Cloth", + "Ancestral Cloth", + "Ancestral Cloth", + "Ancestral Cloth", + "Pitriv's Thread", + "Warblade's Hide", + }, + }, + ["Revenging Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Arioch Fang", + }, + }, + ["Reverberation Sphere"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Delkfutt Key", + }, + }, + ["Reverberation Sphere 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Fetich Torso", + }, + }, + ["Reverberation Sphere 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Desert Venom", + }, + }, + ["Reverberation Sphere 4"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Water Crest Card", + }, + }, + ["Reverberation Sphere 5"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Indigo Memosphere", + }, + }, + ["Rhodium Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rhodium Ore", + "Rhodium Ore", + "Rhodium Ore", + "Rhodium Ore", + }, + }, + ["Rhodium Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rhodium Ingot", + "Rhodium Ingot", + }, + }, + ["Rhodium Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rhodium Ingot", + }, + }, + ["Rhodium Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Workshop Anvil", + "Rhodium Ingot", + "Rhodium Ingot", + "Rhodium Ingot", + "Rhodium Ingot", + "Rhodium Ingot", + "Rhodium Ingot", + }, + }, + ["Rhodonite"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Scarlet Stone", + }, + }, + ["Rice Ball"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Pamtam Kelp", + "Rock Salt", + "Distilled Water", + }, + }, + ["Rice Dumpling"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Bamboo Stick", + "Rock Salt", + "Sticky Rice", + "Dhalmel Meat", + "Coral Fungus", + "Distilled Water", + }, + }, + ["Righteous Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Animal Glue", + "Avatar Blood", + "Hallowed Water", + "Hallowed Water", + "Ra'Kaznar Ingot", + }, + }, + ["Rindomaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Darksteel Ingot", + "Tama-Hagane", + "Ash Lumber", + "Cotton Thread", + "Raptor Skin", + "Dweomer Steel", + }, + }, + ["Riot Grenade"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Yuhtunga Sulfur", + "Paralysis Dust", + "Firesand", + "Firesand", + }, + }, + ["Riot Grenade 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Paralysis Dust", + "Firesand", + "Firesand", + "Sulfur", + }, + }, + ["Riot Grenade 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Sheet", + "Paralysis Dust", + "Firesand", + "Firesand", + "Sulfur", + "Cluster Ash", + }, + }, + ["Rising Sun"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Gold Ingot", + "Mercury", + }, + }, + ["Ritter Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Adaman Sheet", + "Adaman Sheet", + "Ash Lumber", + "Sheep Leather", + }, + }, + ["River Aquarium"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Petrified Log", + "Oak Lumber", + "Sieglinde Putty", + "Glass Sheet", + "Freshwater Set", + "Kayabaligi", + "Kayabaligi", + "Kayabaligi", + }, + }, + ["Riverfin Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ginger", + "Chicken Bone", + "Rock Salt", + "Rockfin Fin", + "Distilled Water", + "Cibol", + "Isleracea", + }, + }, + ["Roast Carp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Forest Carp", + }, + }, + ["Roast Carp 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Moat Carp", + }, + }, + ["Roast Coffee Beans"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Coffee Beans", + }, + }, + ["Roast Mushroom"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Danceshroom", + "Danceshroom", + }, + }, + ["Roast Mushroom 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Woozyshroom", + "Woozyshroom", + }, + }, + ["Roast Mushroom 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Sleepshroom", + "Sleepshroom", + }, + }, + ["Roast Mutton"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Dried Marjoram", + "G. Sheep Meat", + }, + }, + ["Roast Pipira"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Pipira", + }, + }, + ["Roast Trout"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Shining Trout", + }, + }, + ["Roast Trout 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Alabaligi", + }, + }, + ["Roasted Almonds"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Almond", + }, + }, + ["Roasted Corn"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Millioncorn", + }, + }, + ["Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Rococo Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + }, + }, + ["Rod"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Iron Ingot", + "Iron Ingot", + }, + }, + ["Rogue's Silver Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ore", + "Silver Ore", + "Silver Ore", + "Silver Ore", + "Ice Anima", + "Lightning Anima", + "Dark Anima", + }, + }, + ["Rolan. Daifuku"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Sticky Rice", + "Cornstarch", + "Rolanberry", + "Rolanberry", + "Distilled Water", + "Azuki Bean", + }, + }, + ["Rolanberry Pie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Pie Dough", + "Maple Sugar", + "Gelatin", + "Rolanberry", + "Selbina Milk", + "Bird Egg", + }, + }, + ["Rook Banner"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Gold Ingot", + "Gold Thread", + "Gold Thread", + "Silk Cloth", + "Rainbow Cloth", + "Pigeon's Blood", + "Siren's Macrame", + }, + }, + ["Roppo Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Mercury", + "Titanium Sheet", + }, + }, + ["Rose Harp"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Rosewood Lbr.", + "Coeurl Whisker", + }, + }, + ["Rose Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Black C. Feather", + }, + }, + ["Rosenbogen"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Mercury", + "Dryad Root", + "Fiend Blood", + "Red Rose", + "Leshonki Bulb", + "Rapid Bow", + }, + }, + ["Rosewood Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rosewood Log", + }, + }, + ["Rosewood Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rosewood Log", + "Rosewood Log", + "Rosewood Log", + "Bundling Twine", + }, + }, + ["Rosewood Lumber 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 45", + }, + }, + ["Roshi Jinpachi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Arhat's Jinpachi", + "Arhat's Jinpachi", + }, + }, + ["Rosschinder"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Ash Lumber", + "Thokcha Ingot", + "Larimar", + "Wyrdstrand", + "Paralyze Potion", + }, + }, + ["Round Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Oak Lumber", + "Mahogany Lbr.", + }, + }, + ["Royal Bed"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Ebony Lumber", + "Ancient Lumber", + "Gold Ingot", + "Ruby", + "Gold Thread", + "Silk Cloth", + "Damascene Cloth", + }, + }, + ["Royal Bookshelf"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Ebony Lumber", + "Ebony Lumber", + "Lqr. Tree Lbr.", + "Lqr. Tree Lbr.", + }, + }, + ["Royal Knight Army Lance +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "R.K. Army Lance", + }, + }, + ["Royal Knight Army Shield +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "R.K. Army Shield", + }, + }, + ["Royal Knight's Belt +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Ryl.Kgt. Belt", + }, + }, + ["Royal Knight's Cloak +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Silk Cloth", + "Ryl.Kgt. Cloak", + }, + }, + ["Royal Knight's Mufflers +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Chain", + "Ryl.Kgt. Mufflers", + }, + }, + ["Royal Knight's Sollerets +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Chain", + "Ryl.Kgt. Sollerets", + }, + }, + ["Royal Omelette"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "King Truffle", + "Wild Onion", + "Cockatrice Meat", + "Bird Egg", + }, + }, + ["Royal Squire's Breeches +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Chain", + "Ryl.Sqr. Breeches", + }, + }, + ["Royal Squire's Bunk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Chestnut Lumber", + "Walnut Lumber", + "Ash Lumber", + "Ash Lumber", + "Wool Cloth", + "Wool Cloth", + "Sheep Wool", + }, + }, + ["Royal Squire's Chainmail +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Chain", + "Ryl.Sqr. Chainmail", + }, + }, + ["Royal Squire's Robe +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Wool Cloth", + "Ryl.Sqr. Robe", + }, + }, + ["Royal Squire's Shield +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Ryl.Sqr. Shield", + }, + }, + ["Royal Swordsman's Blade +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Ryl.Swd. Blade", + }, + }, + ["Ruby Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ruby", + "Platinum Earring", + }, + }, + ["Ruby Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ruby", + "Ptm. Earring +1", + }, + }, + ["Ruby Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ruby", + "Platinum Ring", + }, + }, + ["Ruby Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ruby", + "Platinum Ring +1", + }, + }, + ["Rugged Bugard Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Bugard Skin", + "Fire Anima", + "Fire Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Rugged Bugard Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Bugard Skin", + "Fire Anima", + "Fire Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Runner's Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "S. Bgd. Leather", + "Barbarian's Belt", + }, + }, + ["Ruszor Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Ruszor Fang", + }, + }, + ["Ruszor Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Shagreen File", + "Ruszor Fang", + "Ruszor Fang", + "Ruszor Fang", + }, + }, + ["Ruszor Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Ruszor Hide", + "Distilled Water", + }, + }, + ["Ruszor Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Ruszor Hide", + "Distilled Water", + }, + }, + ["Ruszor Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tanning Vat", + "Ruszor Hide", + "Ruszor Hide", + "Ruszor Hide", + "Distilled Water", + }, + }, + ["Ruthenium Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ruthenium Ore", + "Ruthenium Ore", + "Ruthenium Ore", + "Ruthenium Ore", + }, + }, + ["S. Salis. Steak"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Sage", + "Rock Salt", + "White Bread", + "Wild Onion", + "Bird Egg", + "Buffalo Meat", + "Cerberus Meat", + }, + }, + ["Saber"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tiger Leather", + "Cermet Chunk", + "Cermet Chunk", + "Cermet Chunk", + }, + }, + ["Saber 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Alch. Kit 70", + }, + }, + ["Sabiki Rig"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Copper Ingot", + "Cotton Thread", + "Cotton Thread", + "Cotton Thread", + }, + }, + ["Sacred Degen"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hallowed Water", + "Holy Degen", + }, + }, + ["Sacred Lance"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hallowed Water", + "Holy Lance", + }, + }, + ["Sacred Mace"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hallowed Water", + "Holy Mace", + }, + }, + ["Sacred Maul"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hallowed Water", + "Holy Maul", + }, + }, + ["Sacred Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hallowed Water", + "Holy Sword", + }, + }, + ["Sacred Wand"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Hallowed Water", + "Holy Wand", + }, + }, + ["Saffron"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Saffron Blossom", + "Saffron Blossom", + "Saffron Blossom", + }, + }, + ["Sagacious Brocade Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dull Gold Thread", + "Brocade Obi", + }, + }, + ["Sagacious Gold Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dull Gold Thread", + "Gold Obi", + }, + }, + ["Sai"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Silver Thread", + "Habu Skin", + }, + }, + ["Saida Ring"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Holy Water", + "Holy Water", + "Hallowed Water", + "Orichalcum Ring", + }, + }, + ["Sailcloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Grass Thread", + "Rainbow Thread", + }, + }, + ["Sainti"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Rosewood Lbr.", + "Gold Ingot", + "Gold Ingot", + "Mercury", + }, + }, + ["Saintly Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Fish Scales", + "Ascetic's Ring", + }, + }, + ["Sairui-Ran"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Bomb Ash", + "Bast Parchment", + "Bird Egg", + }, + }, + ["Sairui-Ran 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Bast Parchment", + "Djinn Ash", + "Bird Egg", + }, + }, + ["Sakurafubuki"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Tama-Hagane", + "Silk Thread", + "Raptor Skin", + "Cermet Chunk", + }, + }, + ["Saline Broth"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Mercury", + "Beastman Blood", + "Phil. Stone", + "Buried Vestige", + }, + }, + ["Sallet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Sheet", + "Iron Sheet", + "Sheep Leather", + }, + }, + ["Sallet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 55", + }, + }, + ["Salmon Croute"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Pie Dough", + "Sage", + "Rock Salt", + "Crawler Egg", + "Cheval Salmon", + "Grape Juice", + }, + }, + ["Salmon Eggs"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Cheval Salmon", + }, + }, + ["Salmon Meuniere"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Black Pepper", + "Olive Oil", + "Rock Salt", + "Cheval Salmon", + }, + }, + ["Salmon Rice Ball"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Pamtam Kelp", + "Rock Salt", + "Smoked Salmon", + "Distilled Water", + }, + }, + ["Salmon Roe"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Rock Salt", + "Salmon Eggs", + }, + }, + ["Salmon Sub"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Crying Mustard", + "Apple Vinegar", + "Black Bread", + "La Theine Cbg.", + "Smoked Salmon", + "Mithran Tomato", + }, + }, + ["Salmon Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Cheval Salmon", + "Distilled Water", + "Ground Wasabi", + }, + }, + ["Salsa"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Rock Salt", + "Wild Onion", + "Mithran Tomato", + "Gysahl Greens", + }, + }, + ["Salt Ramen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Bastore Sardine", + "Batagreens", + "Black Prawn", + "Ramen Noodles", + "Salt Ramen Soup", + "Bamboo Shoots", + }, + }, + ["Salt Ramen Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Lufet Salt", + "Cheval Salmon", + "Bluetail", + "Bastore Bream", + "Distilled Water", + "Vongola Clam", + }, + }, + ["Salted Dragonfly Trout"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Dragonfly Trout", + }, + }, + ["Salted Hare"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Hare Meat", + }, + }, + ["Saltena"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Maple Sugar", + "Olive Oil", + "Imperial Flour", + "Wild Onion", + "Cockatrice Meat", + "Bird Egg", + "Paprika", + }, + }, + ["Saltwater Aquarium"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Oak Lumber", + "Coral Fragment", + "Sieglinde Putty", + "Glass Sheet", + "Saltwater Set", + "Moorish Idol", + "Moorish Idol", + "Moorish Idol", + }, + }, + ["Saltwater Set"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "White Sand", + "Sea Foliage", + "Salinator", + "Holy Water", + }, + }, + ["Salubrious Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Akaso", + "Buffalo Meat", + "Apkallufa", + }, + }, + ["Salutary Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Wool Cloth", + "Wool Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Mandra Scale", + }, + }, + ["Samsonian Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "R. Bgd. Leather", + "Barbarian's Belt", + }, + }, + ["Samurai's Nodowa"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Yggdreant Root", + "Dark Matter", + "Azure Leaf", + "Amber Crystal", + "Moldy Nodowa", + }, + }, + ["San d'Orian Bandana"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ryl.Ftm. Bandana", + }, + }, + ["San d'Orian Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ryl.Ftm. Boots", + }, + }, + ["San d'Orian Bow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Yew Lumber", + "Ryl.Arc. Longbow", + }, + }, + ["San d'Orian Cesti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ryl.Arc. Cesti", + }, + }, + ["San d'Orian Clogs"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Holly Lumber", + "Ryl.Ftm. Clogs", + }, + }, + ["San d'Orian Dagger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Ryl.Sqr. Dagger", + }, + }, + ["San d'Orian Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ryl.Ftm. Gloves", + }, + }, + ["San d'Orian Halberd"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ryl.Sqr. Halberd", + }, + }, + ["San d'Orian Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Ryl. Squire's Helm", + }, + }, + ["San d'Orian Horn"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Giant Femur", + "Ryl.Spr. Horn", + }, + }, + ["San d'Orian Mace"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Ryl.Sqr. Mace", + }, + }, + ["San d'Orian Mufflers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Chain", + "Ryl.Sqr. Mufflers", + }, + }, + ["San d'Orian Sill"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Sieglinde Putty", + "Glass Sheet", + }, + }, + ["San d'Orian Sollerets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Chain", + "Ryl.Sqr. Sollerets", + }, + }, + ["San d'Orian Spear"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ryl.Spr. Spear", + }, + }, + ["San d'Orian Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Ryl.Arc. Sword", + }, + }, + ["San d'Orian Tea"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Win. Tea Leaves", + "Sage", + "Selbina Milk", + "Distilled Water", + }, + }, + ["San d'Orian Tea 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 70", + }, + }, + ["San d'Orian Tea Set"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Angelstone", + "Kaolin", + "Kaolin", + }, + }, + ["San d'Orian Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ryl.Ftm. Trousers", + }, + }, + ["San d'Orian Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Grass Cloth", + "Ryl.Ftm. Tunic", + }, + }, + ["San d'Orian Vest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ryl.Ftm. Vest", + }, + }, + ["Sanctified Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Petrified Log", + "Ice Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Sancus Sachet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Siren's Macrame", + "Sif's Macrame", + "Sif's Macrame", + "Vulcanite Ore", + "Arasy Sachet", + }, + }, + ["Sandals"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Sheep Leather", + }, + }, + ["Sanjaku-Tenugui"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Saotome-no-tachi"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Plating", + "Dark Matter", + "Ruthenium Ore", + "Moldy G. Katana", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Amber Crystal", + }, + }, + ["Sapara"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Ingot", + "Silver Ingot", + }, + }, + ["Sapphire Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sapphire", + "Platinum Earring", + }, + }, + ["Sapphire Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sapphire", + "Ptm. Earring +1", + }, + }, + ["Sapphire Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sapphire", + "Platinum Ring", + }, + }, + ["Sapphire Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sapphire", + "Platinum Ring +1", + }, + }, + ["Sarcenet Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Sarcenet Cloth", + "Sarcenet Cloth", + }, + }, + ["Sardine Ball"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Horo Flour", + "Bastore Sardine", + "Distilled Water", + }, + }, + ["Sardine Ball 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Horo Flour", + "Distilled Water", + "Hamsi", + }, + }, + ["Sardine Ball 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Horo Flour", + "Distilled Water", + "Senroh Sardine", + }, + }, + ["Sardonyx"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Red Rock", + }, + }, + ["Sardonyx 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Flame Geode", + }, + }, + ["Sardonyx Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sardonyx", + "Silver Earring", + }, + }, + ["Sardonyx Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sardonyx", + "Silver Earring +1", + }, + }, + ["Sardonyx Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sardonyx", + "Silver Ring", + }, + }, + ["Sardonyx Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sardonyx", + "Silver Ring +1", + }, + }, + ["Sasah Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Phoenix Feather", + "Urunday Lumber", + }, + }, + ["Sasah Wand 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 94", + }, + }, + ["Sasanuki"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Ancient Lumber", + "Thokcha Ingot", + "Thokcha Ingot", + "Gold Ingot", + "Rainbow Thread", + "Scintillant Ingot", + "Smildn. Leather", + }, + }, + ["Sasuke Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Mercury", + "Bismuth Sheet", + }, + }, + ["Sausage"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Black Pepper", + "Sage", + "Maple Log", + "Rock Salt", + "G. Sheep Meat", + }, + }, + ["Sausage Roll"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Rock Salt", + "Honey", + "Distilled Water", + "Sausage", + }, + }, + ["Savage Mole Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Red Gravel", + "Snapping Mole", + "Helmet Mole", + "Loam", + "Little Worm", + "Little Worm", + }, + }, + ["Scale Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Bronze Scales", + "Cotton Thread", + "Leather Trousers", + }, + }, + ["Scale Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Bronze Scales", + "Cotton Thread", + "Leather Gloves", + }, + }, + ["Scale Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Bronze Scales", + "Cotton Thread", + "Leather Highboots", + }, + }, + ["Scale Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Bronze Scales", + "Bronze Scales", + "Bronze Scales", + "Cotton Thread", + "Sheep Leather", + "Leather Vest", + }, + }, + ["Scanner"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Ice Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Scapegoat"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Phoenix Feather", + "Marid Tusk", + }, + }, + ["Scarlet Linen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Thread", + "Bloodthread", + }, + }, + ["Scarlet Ribbon"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Velvet Cloth", + }, + }, + ["Scepter"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Gold Ingot", + "Mercury", + }, + }, + ["Schlaeger"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Darksteel Ingot", + "Silver Ingot", + }, + }, + ["Schwert"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Mythril Ingot", + "Moonstone", + "Cermet Chunk", + }, + }, + ["Scimitar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Steel Ingot", + }, + }, + ["Scimitar Cactus"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Iron Sheet", + "Red Gravel", + "Cactus Arm", + "Humus", + }, + }, + ["Scintillant Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Orichalcum Ore", + "Luminium Ore", + "Luminium Ore", + "Luminium Ore", + }, + }, + ["Scission Sphere"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Scorpion Stinger", + }, + }, + ["Scission Sphere 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Magicked Steel", + }, + }, + ["Scission Sphere 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Fetich Head", + }, + }, + ["Scission Sphere 4"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elshimo Marble", + }, + }, + ["Scission Sphere 5"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Earth Crest Card", + }, + }, + ["Scope"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Glass Fiber", + "Artificial Lens", + "Artificial Lens", + "Myth.Gear Mach.", + }, + }, + ["Scope II"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Glass Fiber", + "Artificial Lens", + "Artificial Lens", + "Golden Gear", + "A.U Brass Sheet", + }, + }, + ["Scope III"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Glass Fiber", + "Artificial Lens", + "Artificial Lens", + "A.U Brass Sheet", + "Platinum Gear", + }, + }, + ["Scope IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Glass Fiber", + "Artificial Lens", + "Artificial Lens", + "A.U Brass Sheet", + "Ocl. Gearbox", + }, + }, + ["Scorpion Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Insect Fltchg.", + "Scp. Arrowhd.", + }, + }, + ["Scorpion Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Scorpion Claw", + }, + }, + ["Scorpion Arrowheads 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Bone Chip", + "Bone Chip", + "Scorpion Claw", + "Scorpion Claw", + "Scorpion Claw", + "Shagreen File", + }, + }, + ["Scorpion Breastplate"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Ram Leather", + "Ram Leather", + "H.Q. Scp. Shell", + "H.Q. Scp. Shell", + "H.Q. Scp. Shell", + "H.Q. Scp. Shell", + }, + }, + ["Scorpion Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "H.Q. Scp. Shell", + "H.Q. Scp. Shell", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Scorpion Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Scorpion Shell", + "Scorpion Shell", + "Venomous Claw", + }, + }, + ["Scorpion Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Sheep Leather", + "Ram Leather", + "H.Q. Scp. Shell", + "H.Q. Scp. Shell", + }, + }, + ["Scorpion Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Ram Leather", + "Pugil Scales", + "Scorpion Shell", + }, + }, + ["Scorpion Mask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Scorpion Shell", + }, + }, + ["Scorpion Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Pugil Scales", + "Scorpion Shell", + }, + }, + ["Scorpion Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Scorpion Shell", + }, + }, + ["Scorpion Ring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 60", + }, + }, + ["Scorpion Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Cloth", + "Ram Leather", + "Scorpion Shell", + }, + }, + ["Scout's Bolt"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Dark Matter", + "Moldy Bolt", + "Relic Adaman", + "Malachite Crystal", + }, + }, + ["Scout's Crossbow"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Macuil Plating", + "Dark Matter", + "Cyan Coral", + "Moldy Crossbow", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Malachite Crystal", + }, + }, + ["Scout's Gorget"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Pelt", + "Dark Matter", + "S. Faulpie Leather", + "Malachite Crystal", + "Moldy Gorget", + }, + }, + ["Scutum"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Oak Lumber", + }, + }, + ["Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Holly Lumber", + "Grass Cloth", + }, + }, + ["Sea Bass Croute"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Pie Dough", + "Sage", + "Rock Salt", + "Lizard Egg", + "Zafmlug Bass", + "King Truffle", + "Grape Juice", + }, + }, + ["Sea Dragon Liver"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Soryu's Liver", + "Sekiryu's Liver", + "Hakuryu's Liver", + "Kokuryu's Liver", + }, + }, + ["Seadog Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Coral Fragment", + "Coral Fragment", + }, + }, + ["Seafood Gratin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Rock Salt", + "Danceshroom", + "Selbina Milk", + "Gigant Squid", + "Bastore Sweeper", + "Chalaimbille", + }, + }, + ["Seafood Paella"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Tarutaru Rice", + "Saffron", + "Wild Onion", + "Gigant Squid", + "Distilled Water", + "Black Prawn", + "Mussel", + }, + }, + ["Seafood Pitaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Rock Salt", + "Imperial Flour", + "Wild Onion", + "Distilled Water", + "Graubg. Lettuce", + "Butterpear", + "Peeled Lobster", + }, + }, + ["Seafood Stew"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Black Pepper", + "Rock Salt", + "Nebimonite", + "Gold Lobster", + "Shall Shell", + "Distilled Water", + "Gysahl Greens", + }, + }, + ["Seafood Stew 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Black Pepper", + "Rock Salt", + "Distilled Water", + "Gysahl Greens", + "Istakoz", + "Ahtapot", + "Istiridye", + }, + }, + ["Seafood Stewpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Fish Stock", + "Danceshroom", + "Gold Lobster", + "Bastore Bream", + "Distilled Water", + "Cotton Tofu", + "Cibol", + "Napa", + }, + }, + ["Sealord Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Sealord Skin", + "Distilled Water", + }, + }, + ["Sealord Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Sealord Skin", + "Distilled Water", + }, + }, + ["Secretaire"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + "Mahogany Lbr.", + }, + }, + ["Seer's Crown"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Lizard Molt", + "Bone Chip", + "Coeurl Whisker", + }, + }, + ["Seer's Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Cotton Cloth", + "Cotton Cloth", + "Saruta Cotton", + "Sheep Leather", + }, + }, + ["Seer's Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Thread", + "Cotton Cloth", + "Cotton Cloth", + "Sheep Leather", + }, + }, + ["Seer's Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Cotton Cloth", + "Cotton Cloth", + "Linen Cloth", + "Sheep Leather", + }, + }, + ["Seer's Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + "Linen Cloth", + "Linen Cloth", + "Sheep Leather", + }, + }, + ["Seito"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Muting Potion", + "Mokuto", + }, + }, + ["Sekishitsu"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lqr. Tree Sap", + "Lqr. Tree Sap", + "Lqr. Tree Sap", + "Lqr. Tree Sap", + "Vrml. Lacquer", + "Honey", + }, + }, + ["Selbina Butter"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Rock Salt", + "Selbina Milk", + }, + }, + ["Self Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Lumber", + "Grass Thread", + "Cotton Cloth", + "Giant Femur", + }, + }, + ["Semainier"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Ebony Lumber", + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Senbaak Nagan"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Damascus Ingot", + "Damascus Ingot", + "Damascus Ingot", + "Damascus Ingot", + "Scarletite Ingot", + "Wyvern Skin", + "Urunday Lumber", + "Gabbrath Horn", + }, + }, + ["Senroh Skewer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bluetail", + "Shall Shell", + "Shall Shell", + "Contortopus", + "Senroh Sardine", + }, + }, + ["Senroh Skewer 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bluetail", + "Shall Shell", + "Shall Shell", + "Contortacle", + "Contortacle", + "Contortacle", + "Senroh Sardine", + }, + }, + ["Serpette"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Grass Cloth", + "Giant Femur", + "Giant Femur", + "Bukktooth", + }, + }, + ["Seshaw Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Sif's Macrame", + "Ancestral Cloth", + "Cehuetzi Pelt", + }, + }, + ["Severus Claws"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Likho Talon", + }, + }, + ["Sha'ir Crackows"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Gold Thread", + "Velvet Cloth", + "Tiger Leather", + "Tiger Leather", + "Buffalo Leather", + }, + }, + ["Sha'ir Gages"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Garnet", + "Gold Thread", + "Velvet Cloth", + "Tiger Leather", + "H.Q. Bugard Skin", + }, + }, + ["Sha'ir Manteel"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Ruby", + "Sapphire", + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Cashmere Cloth", + }, + }, + ["Sha'ir Seraweels"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Tiger Leather", + "Taffeta Cloth", + }, + }, + ["Sha'ir Turban"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Pigeon's Blood", + "Hippogryph Fthr.", + }, + }, + ["Shabti Armet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Gold Ingot", + "Sheep Leather", + "Mercury", + "Bismuth Sheet", + "Bismuth Sheet", + }, + }, + ["Shabti Cuirass"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Ram Leather", + "Ram Leather", + "Mercury", + "Bismuth Sheet", + "Bismuth Sheet", + "Bismuth Sheet", + "Bismuth Sheet", + }, + }, + ["Shabti Cuisses"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Ram Leather", + "Bismuth Sheet", + "Bismuth Sheet", + }, + }, + ["Shabti Gauntlets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "Bismuth Sheet", + "Bismuth Sheet", + "Leather Gloves", + "Leather Gloves", + }, + }, + ["Shabti Sabatons"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Ram Leather", + "Ram Leather", + "Mercury", + "Bismuth Sheet", + "Bismuth Sheet", + "Bismuth Sheet", + }, + }, + ["Shade Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Luminicloth", + "Velvet Cloth", + "Tiger Leather", + "Uragnite Shell", + "Uragnite Shell", + "Eft Skin", + "Eft Skin", + "Photoanima", + }, + }, + ["Shade Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Luminicloth", + "Lizard Skin", + "Tiger Leather", + "Tiger Leather", + "Uragnite Shell", + "Eft Skin", + "Photoanima", + }, + }, + ["Shade Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Luminicloth", + "Sheep Leather", + "Tiger Leather", + "Uragnite Shell", + "Eft Skin", + "Photoanima", + }, + }, + ["Shade Tiara"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Uragnite Shell", + "Eft Skin", + "Photoanima", + }, + }, + ["Shade Tights"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Luminicloth", + "Velvet Cloth", + "Tiger Leather", + "Uragnite Shell", + "Eft Skin", + "Photoanima", + }, + }, + ["Shadow Apple"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Coffee Powder", + "Faerie Apple", + }, + }, + ["Shadow Bow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Assassin's Bow", + }, + }, + ["Shadow Roll"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Thread", + "Wool Cloth", + "Sheep Leather", + }, + }, + ["Shadow Roll 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 40", + }, + }, + ["Shadow Throne"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Demon Skull", + "Giant Femur", + "Giant Femur", + "Demon Horn", + "Demon Horn", + "Fiend Blood", + "Necropsyche", + "Demon Blood", + }, + }, + ["Shadowy Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dragon Meat", + "Nopales", + "Agaricus", + }, + }, + ["Shallops Tropicale"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Bay Leaves", + "Rock Salt", + "Kazham Pineapl.", + "Shall Shell", + "Shall Shell", + "Distilled Water", + }, + }, + ["Shallops Tropicale 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 80", + }, + }, + ["Shark Fin Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ginger", + "Popoto", + "Chicken Bone", + "Rock Salt", + "Sleepshroom", + "Silver Shark", + "Distilled Water", + "Bird Egg", + }, + }, + ["Sharur"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ormolu Ingot", + "Mercury", + "Urunday Lumber", + "Bztavian Stinger", + }, + }, + ["Sheep Chammy"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Win. Tea Leaves", + "Clot Plasma", + "Distilled Water", + }, + }, + ["Sheep Chammy 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Willow Log", + "Clot Plasma", + "Distilled Water", + }, + }, + ["Sheep Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Willow Log", + "Distilled Water", + }, + }, + ["Sheep Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Win. Tea Leaves", + "Distilled Water", + }, + }, + ["Sheep Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Sheepskin", + "Sheepskin", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Sheep Wool"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheepskin", + "Sheepskin", + }, + }, + ["Shell Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Seashell", + "Seashell", + }, + }, + ["Shell Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Turtle Shell", + }, + }, + ["Shell Lamp"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Uragnite Shell", + "F. Glass Sheet", + "Kaolin", + "Kaolin", + "Bomb Arm", + }, + }, + ["Shell Powder"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Seashell", + "Seashell", + "Seashell", + }, + }, + ["Shell Powder 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Vongola Clam", + "Vongola Clam", + }, + }, + ["Shell Powder 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 5", + }, + }, + ["Shell Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Fish Scales", + "Seashell", + }, + }, + ["Shield Plaque"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Mythril Sheet", + "Rosewood Lbr.", + "Gold Ingot", + "Gold Sheet", + "Turquoise", + "Rhodonite", + "Scarlet Linen", + }, + }, + ["Shigeto Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Gold Sheet", + "Wisteria Lumber", + "Wisteria Lumber", + "Urushi", + "Shortbow", + }, + }, + ["Shihei"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Black Ink", + "Bast Parchment", + "Bast Parchment", + }, + }, + ["Shimmering Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Ruddy Seema", + "Ruddy Seema", + "Ruddy Seema", + "Ruddy Seema", + }, + }, + ["Shining Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Ingot", + "Scintillant Ingot", + }, + }, + ["Shinobi Gi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Iron Chain", + "Linen Thread", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Shinobi Hachigane"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Iron Chain", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Shinobi Hakama"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Silk Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Shinobi Kyahan"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Linen Thread", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Shinobi Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Iron Chain", + "Linen Thread", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Shinobi-Gatana"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Tama-Hagane", + "Elm Lumber", + "Cotton Thread", + "Lizard Skin", + }, + }, + ["Shinobi-Tabi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Cotton Cloth", + "Saruta Cotton", + }, + }, + ["Shiny Gold Thread"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Silk Thread", + "Light Anima", + "Light Anima", + "Light Anima", + }, + }, + ["Shirogatana"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Tama-Hagane", + "Ancient Lumber", + "Silver Ingot", + "Scintillant Ingot", + "Wamoura Silk", + }, + }, + ["Shiromochi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sticky Rice", + "Cornstarch", + "Distilled Water", + }, + }, + ["Shock Absorber"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Darksteel Sheet", + "Bomb Ash", + "Carbon Fiber", + "Imperial Cermet", + }, + }, + ["Shock Absorber II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Sheet", + "Carbon Fiber", + "Cluster Ash", + "Dark Adaman", + "Imperial Cermet", + }, + }, + ["Shock Absorber III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Carbon Fiber", + "Drk. Adm. Sheet", + "Imperial Cermet", + "Djinn Ash", + "Titanium Sheet", + }, + }, + ["Shock Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Luminous Shell", + "Carapace Subligar", + }, + }, + ["Shoes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Dhalmel Leather", + "Dhalmel Leather", + }, + }, + ["Shofar"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Behemoth Horn", + "Beetle Jaw", + }, + }, + ["Shortbow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Lumber", + "Grass Thread", + "Grass Cloth", + }, + }, + ["Shotel"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Silver Ingot", + "Bugard Tusk", + "Tiger Eye", + }, + }, + ["Shower Stand"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Gold Ingot", + "Sieglinde Putty", + }, + }, + ["Shrimp Cracker"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rock Salt", + "Gold Lobster", + "Distilled Water", + }, + }, + ["Shrimp Cracker 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rock Salt", + "Distilled Water", + "Istakoz", + }, + }, + ["Shrimp Lantern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tin Ingot", + "Beeswax", + "Moblumin Sheet", + "Moblin Putty", + }, + }, + ["Shrimp Lure"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Glass Fiber", + "Crayfish", + }, + }, + ["Shrimp Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Ground Wasabi", + "Bastore Sweeper", + }, + }, + ["Shuriken"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Cotton Thread", + }, + }, + ["Sickle"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Ash Lumber", + "Grass Cloth", + }, + }, + ["Sieglinde Putty"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Flaxseed Oil", + "Flaxseed Oil", + "Shell Powder", + "Shell Powder", + "Zinc Oxide", + }, + }, + ["Sieglinde Putty 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Alch. Kit 30", + }, + }, + ["Sif's Macrame"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Gold Thread", + "Gold Thread", + "Siren's Hair", + "Sif's Lock", + }, + }, + ["Silence Baghnakhs"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Silencing Potion", + "Brass Baghnakhs", + }, + }, + ["Silence Dagger"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Silencing Potion", + "Brass Dagger", + }, + }, + ["Silencing Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kazham Peppers", + "2Leaf Mandra Bud", + "Scream Fungus", + }, + }, + ["Silencing Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Lycopodium Flower", + "Scream Fungus", + }, + }, + ["Silencing Potion 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Distilled Water", + "Sobbing Fungus", + "Sobbing Fungus", + }, + }, + ["Silencing Potion 4"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Mercury", + "Cobalt Jellyfish", + }, + }, + ["Silencing Potion 5"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Mercury", + "Denizanasi", + }, + }, + ["Silent Oil"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Slime Oil", + "Beeswax", + "Beeswax", + }, + }, + ["Silent Oil 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Olive Oil", + "Beeswax", + "Beeswax", + }, + }, + ["Silk Cloak"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Silk Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Thread", + "Silk Thread", + }, + }, + ["Silk Coat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Silk Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Aquamarine", + "Aquamarine", + "Gold Thread", + "Velvet Cloth", + "Silk Cloth", + }, + }, + ["Silk Cuffs 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lapis Lazuli", + "Lapis Lazuli", + "Gold Thread", + "Velvet Cloth", + "Silk Cloth", + }, + }, + ["Silk Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Silver Thread", + "Velvet Cloth", + }, + }, + ["Silk Headband"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Cloth", + "Carbon Fiber", + }, + }, + ["Silk Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Silk Cloth", + "Silk Cloth", + "Saruta Cotton", + }, + }, + ["Silk Pumps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Silk Cloth", + "Silk Cloth", + "Sheep Leather", + }, + }, + ["Silk Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Silk Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Silk Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Thread", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["Silk Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Crawler Cocoon", + "Crawler Cocoon", + }, + }, + ["Silk Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Crawler Cocoon", + "Crawler Cocoon", + "Crawler Cocoon", + "Crawler Cocoon", + "Crawler Cocoon", + "Crawler Cocoon", + "Spindle", + }, + }, + ["Silken Coat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Imp. Silk Cloth", + "Imp. Silk Cloth", + }, + }, + ["Silken Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lapis Lazuli", + "Lapis Lazuli", + "Gold Thread", + "Velvet Cloth", + "Imp. Silk Cloth", + }, + }, + ["Silken Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Silver Thread", + "Velvet Cloth", + "Imp. Silk Cloth", + "Imp. Silk Cloth", + }, + }, + ["Silken Pigaches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Raptor Skin", + "Tiger Leather", + "Tiger Leather", + "Imp. Silk Cloth", + }, + }, + ["Silken Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Sheet", + "Gold Thread", + "Velvet Cloth", + "Imp. Silk Cloth", + "Imp. Silk Cloth", + }, + }, + ["Silky Suede"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Garnet", + "Buffalo Leather", + }, + }, + ["Silver Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Slv. Arrowheads", + "Yagudo Fltchg.", + }, + }, + ["Silver Arrow 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Silver Ingot", + "Yagudo Feather", + "Yagudo Feather", + }, + }, + ["Silver Arrow 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 30", + }, + }, + ["Silver Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Silver Ingot", + }, + }, + ["Silver Bangles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + }, + }, + ["Silver Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Lizard Belt", + }, + }, + ["Silver Belt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold. Kit 25", + }, + }, + ["Silver Brocade"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Silk Thread", + "Rainbow Thread", + "Rainbow Thread", + "Silver Thread", + "Silver Thread", + }, + }, + ["Silver Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Firesand", + }, + }, + ["Silver Cassandra"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Ocl. Ingot", + "Ocl. Ingot", + "Mercury", + "Smildn. Leather", + "Darksteel Hexagun", + }, + }, + ["Silver Chain"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Ingot", + }, + }, + ["Silver Chain 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Mandrel", + }, + }, + ["Silver Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Ingot", + }, + }, + ["Silver Greaves"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Mercury", + "Greaves", + }, + }, + ["Silver Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Ingot", + }, + }, + ["Silver Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Chain Hose", + }, + }, + ["Silver Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Beastcoin", + "Silver Beastcoin", + "Silver Beastcoin", + "Silver Beastcoin", + }, + }, + ["Silver Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ore", + "Silver Ore", + "Silver Ore", + "Silver Ore", + }, + }, + ["Silver Ingot 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold. Kit 20", + }, + }, + ["Silver Ingot 4"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ore", + "Silver Nugget", + "Silver Nugget", + "Silver Nugget", + "Silver Nugget", + "Silver Nugget", + "Silver Nugget", + }, + }, + ["Silver Mail"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Chain", + "Silver Chain", + "Chainmail", + }, + }, + ["Silver Mask"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Mercury", + "Iron Mask", + }, + }, + ["Silver Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Chain", + "Chain Mittens", + }, + }, + ["Silver Nugget"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Leaf", + "Panacea", + }, + }, + ["Silver Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Silver Thread", + "Silver Thread", + }, + }, + ["Silver Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Ingot", + }, + }, + ["Silver Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + }, + }, + ["Silver Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Workshop Anvil", + }, + }, + ["Silver Thread"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silk Thread", + }, + }, + ["Silver Thread 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Silver Ingot", + "Silver Ingot", + "Silk Thread", + "Silk Thread", + "Silk Thread", + "Spindle", + }, + }, + ["Simit"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Rock Salt", + "Simsim", + "Imperial Flour", + "Selbina Milk", + "Buburimu Grape", + "Distilled Water", + "White Honey", + }, + }, + ["Simple Bed"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Lauan Lumber", + "Holly Lumber", + "Holly Lumber", + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + }, + }, + ["Single Hook Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. S.H. Rod", + }, + }, + ["Single Hook Fishing Rod 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Carbon Fiber", + "Glass Fiber", + "Glass Fiber", + }, + }, + ["Sipahi Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Mythril Sheet", + "Karakul Leather", + "Marid Leather", + "Marid Leather", + "Wamoura Cloth", + }, + }, + ["Sipahi Dastanas"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Karakul Leather", + "Marid Leather", + "Marid Hair", + "Karakul Cloth", + }, + }, + ["Sipahi Jawshan"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Steel Sheet", + "Gold Chain", + "Silk Cloth", + "Karakul Leather", + "Marid Leather", + "Marid Leather", + "Wamoura Cloth", + }, + }, + ["Sipahi Turban"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Chain", + "Marid Hair", + "Wamoura Cloth", + "Wamoura Cloth", + }, + }, + ["Sipahi Zerehs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Chain", + "Marid Leather", + "Marid Hair", + "Karakul Cloth", + "Karakul Cloth", + "Wamoura Cloth", + }, + }, + ["Siren's Macrame"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Rainbow Thread", + "Gold Thread", + "Gold Thread", + "Siren's Hair", + "Siren's Hair", + }, + }, + ["Sis Kebabi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Black Pepper", + "Rock Salt", + "Wild Onion", + "Mithran Tomato", + "Karakul Meat", + }, + }, + ["Sitabaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + "Cotton Cloth", + }, + }, + ["Skeleton Key"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Tooth", + "Bat Fang", + "Bat Fang", + "Chicken Bone", + "Carbon Fiber", + "Glass Fiber", + "Animal Glue", + "Hecteyes Eye", + }, + }, + ["Skeleton Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Wool Cloth", + "Wool Cloth", + "Osseous Serum", + }, + }, + ["Skrymir Cord"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Gold Thread", + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + "Khoma Thread", + "Wyrm Ash", + }, + }, + ["Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Sleep Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Bird Fletchings", + "Sleep Arrowhd.", + }, + }, + ["Sleep Arrow 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 50", + }, + }, + ["Sleep Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Ram Horn", + "Animal Glue", + "Sleeping Potion", + }, + }, + ["Sleep Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Slp. Bolt Heads", + }, + }, + ["Sleep Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Ash Lumber", + "Slp. Bolt Heads", + "Slp. Bolt Heads", + "Slp. Bolt Heads", + "Bundling Twine", + }, + }, + ["Sleep Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Animal Glue", + "Sleeping Potion", + }, + }, + ["Sleeping Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Chamomile", + "Poison Flour", + "Sleepshroom", + }, + }, + ["Sleeping Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Chamomile", + "Chamomile", + "Poison Flour", + "Poison Flour", + "Triturator", + "Sleepshroom", + "Sleepshroom", + }, + }, + ["Slice of Bluetail"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bluetail", + }, + }, + ["Slice of Bluetail 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cook. Kit 15", + }, + }, + ["Slice of Carp"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Moat Carp", + }, + }, + ["Slice of Carp 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Forest Carp", + }, + }, + ["Sliced Cod"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tiger Cod", + }, + }, + ["Sliced Sardine"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bastore Sardine", + }, + }, + ["Sliced Sardine 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Hamsi", + }, + }, + ["Sliced Sardine 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Senroh Sardine", + }, + }, + ["Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Grass Cloth", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Smash Cesti"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Earth Cell", + "Lam. Wind Cell", + "Lizard Cesti", + }, + }, + ["Smilodon Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Smilodon Hide", + "Distilled Water", + }, + }, + ["Smilodon Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Smilodon Hide", + "Distilled Water", + }, + }, + ["Smilodon Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tanning Vat", + "Smilodon Hide", + "Smilodon Hide", + "Smilodon Hide", + "Distilled Water", + }, + }, + ["Smilodon Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Smilodon Hide", + }, + }, + ["Smilodon Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Smildn. Leather", + }, + }, + ["Smithing Set 25"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Lizard Skin", + }, + }, + ["Smithing Set 45"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Steel Ingot", + "Mythril Ingot", + "Mythril Ingot", + }, + }, + ["Smithing Set 65"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mahogany Lbr.", + "Cockatrice Skin", + }, + }, + ["Smithing Set 70"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Lizard Skin", + }, + }, + ["Smithing Set 76"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Tin Ingot", + "Muketsu", + }, + }, + ["Smithing Set 80"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Raptor Skin", + "Broadsword", + }, + }, + ["Smithing Set 84"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Steel Sheet", + "Darksteel Mufflers", + }, + }, + ["Smithing Set 91"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Mahogany Lbr.", + }, + }, + ["Smithing Set 94"] = { + ["crystal"] = "Pyre Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Gold Ingot", + "Cockatrice Skin", + "Mercury", + }, + }, + ["Smiting Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tenebrium", + "Mythril Scythe", + }, + }, + ["Smoked Salmon"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Walnut Log", + "Rock Salt", + "Cheval Salmon", + }, + }, + ["Smooth Beetle Jaw"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Beetle Jaw", + "Wind Anima", + "Wind Anima", + "Light Anima", + }, + }, + ["Smooth Sheep Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Willow Log", + "Wind Anima", + "Wind Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Smooth Sheep Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Win. Tea Leaves", + "Wind Anima", + "Wind Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Smooth Velvet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Wool Thread", + "Wool Thread", + "Wind Anima", + "Wind Anima", + "Light Anima", + }, + }, + ["Smooth Velvet 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Cotton Thread", + "Cotton Thread", + "Wind Anima", + "Wind Anima", + "Light Anima", + }, + }, + ["Snakeeye"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Hydra Fang", + "Hydra Fang", + "Wamoura Silk", + }, + }, + ["Sniper's Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Archer's Ring", + }, + }, + ["Snoll Gelato"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Olive Oil", + "Selbina Milk", + "Bird Egg", + "Snoll Arm", + }, + }, + ["Snoll Gelato 2"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Olive Oil", + "Vanilla", + "Selbina Milk", + "Bird Egg", + "Snoll Arm", + }, + }, + ["Snow Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ice Bead", + "Orichalcum Ring", + }, + }, + ["Snowsteel"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Snowsteel Ore", + "Snowsteel Ore", + "Snowsteel Ore", + "Snowsteel Ore", + }, + }, + ["Snowsteel Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Snowsteel", + }, + }, + ["Snowsteel Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Workshop Anvil", + "Snowsteel", + "Snowsteel", + "Snowsteel", + "Snowsteel", + "Snowsteel", + "Snowsteel", + }, + }, + ["Soba Noodles"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Buckwheat Flour", + }, + }, + ["Socks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + "Dhalmel Leather", + }, + }, + ["Soft Bugard Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Bugard Skin", + "Lightning Anima", + "Lightning Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Soft Bugard Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Bugard Skin", + "Lightning Anima", + "Lightning Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Soil Gi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Soil Hachimaki"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Soil Kyahan"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Cotton Thread", + "Linen Cloth", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Soil Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Earth Bead", + "Orichalcum Ring", + }, + }, + ["Soil Sitabaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Linen Cloth", + "Linen Cloth", + "Wool Cloth", + }, + }, + ["Soil Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Grass Thread", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Sole Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Ground Wasabi", + "Dil", + }, + }, + ["Sole Sushi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Black Sole", + "Distilled Water", + "Ground Wasabi", + }, + }, + ["Solea"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Sollerets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Mythril Sheet", + "Greaves", + }, + }, + ["Sombra Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Cloth", + "Damascene Cloth", + "Raaz Leather", + "Intuila's Hide", + "Intuila's Hide", + "Arthro's Shell", + "Arthro's Shell", + }, + }, + ["Sombra Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Damascene Cloth", + "Behemoth Hide", + "Raaz Leather", + "Raaz Leather", + "Intuila's Hide", + "Arthro's Shell", + }, + }, + ["Sombra Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Damascene Cloth", + "Buffalo Leather", + "Raaz Leather", + "Intuila's Hide", + "Arthro's Shell", + }, + }, + ["Sombra Tiara"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Intuila's Hide", + "Arthro's Shell", + }, + }, + ["Sombra Tights"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Cloth", + "Damascene Cloth", + "Raaz Leather", + "Intuila's Hide", + "Arthro's Shell", + }, + }, + ["Sonic Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ram Leather", + "Speed Belt", + }, + }, + ["Sopa Pez Blanco"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Black Pepper", + "Rock Salt", + "Selbina Milk", + "Wild Onion", + "San d'Or. Carrot", + "Distilled Water", + "Dil", + }, + }, + ["Sopa Pez Blanco 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Black Pepper", + "Rock Salt", + "Selbina Milk", + "Black Sole", + "Wild Onion", + "San d'Or. Carrot", + "Distilled Water", + }, + }, + ["Sorcerer's Staff"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Plovid Effluvium", + "Dark Matter", + "Khoma Thread", + "Moldy Staff", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Iolite Crystal", + }, + }, + ["Sorcerer's Stole"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Yggdreant Bole", + "Dark Matter", + "Cypress Log", + "Iolite Crystal", + "Moldy Stole", + }, + }, + ["Soshi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Black Ink", + "Bast Parchment", + "Bast Parchment", + }, + }, + ["Soy Milk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blue Peas", + "Blue Peas", + "Distilled Water", + }, + }, + ["Soy Ramen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pamtam Kelp", + "Tiger Cod", + "Bird Egg", + "Cibol", + "Porxie Pork", + "Ramen Noodles", + "Soy Ramen Soup", + "Bamboo Shoots", + }, + }, + ["Soy Ramen Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Chicken Bone", + "Chicken Bone", + "Wild Onion", + "Cockatrice Meat", + "Distilled Water", + "Cibol", + "Soy Sauce", + }, + }, + ["Spaghetti"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Rock Salt", + "Semolina", + }, + }, + ["Spark Baselard"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Mythril Baselard", + }, + }, + ["Spark Bilbo"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Bilbo", + }, + }, + ["Spark Dagger"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Dagger", + }, + }, + ["Spark Degen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Mythril Degen", + }, + }, + ["Spark Fork"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Battle Fork", + }, + }, + ["Spark Kris"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Darksteel Kris", + }, + }, + ["Spark Lance"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Lance", + }, + }, + ["Spark Rapier"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Rapier", + }, + }, + ["Spark Spear"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Copper Ingot", + "Brass Spear", + }, + }, + ["Sparkling Hand"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Silver Ingot", + "Parchment", + "Twinkle Powder", + "Prism Powder", + }, + }, + ["Sparkstrand Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "W. Spider's Web", + "W. Spider's Web", + }, + }, + ["Sparkstrand Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Spindle", + "W. Spider's Web", + "W. Spider's Web", + "W. Spider's Web", + "W. Spider's Web", + "W. Spider's Web", + "W. Spider's Web", + }, + }, + ["Spartan Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Bronze Ingot", + "Firesand", + "Twinkle Powder", + }, + }, + ["Spartan Hoplon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bld. Ram Lthr.", + "Hoplon", + }, + }, + ["Spatha"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Bronze Ingot", + "Lizard Skin", + }, + }, + ["Spatha 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 25", + }, + }, + ["Spear"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Ingot", + "Ash Lumber", + "Linen Thread", + }, + }, + ["Spectral Serum"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Luminicloth", + "Luminicloth", + "Mercury", + }, + }, + ["Speed Apple"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Faerie Apple", + "Honey", + }, + }, + ["Speedloader"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Slime Oil", + "Mythril Sheet", + "Glass Fiber", + "Mythril Coil", + "Myth.Gear Mach.", + }, + }, + ["Speedloader II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Slime Oil", + "Gold Sheet", + "Glass Fiber", + "Mythril Coil", + "Myth.Gear Mach.", + }, + }, + ["Spence"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Hickory Lumber", + "Hickory Lumber", + "Teak Lumber", + "Teak Lumber", + }, + }, + ["Sphene Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sphene", + "Mythril Earring", + }, + }, + ["Sphene Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sphene", + "Mythril Earring +1", + }, + }, + ["Sphene Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sphene", + "Mythril Ring", + }, + }, + ["Sphene Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sphene", + "Mythril Ring +1", + }, + }, + ["Spicy Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mand. Sprout", + "Mand. Sprout", + "G. Sheep Meat", + "Isleracea", + }, + }, + ["Spicy Cracker"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Tarutaru Rice", + "Rock Salt", + "Distilled Water", + }, + }, + ["Spiked Club"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Walnut Lumber", + "Walnut Lumber", + }, + }, + ["Spinel Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Spinel", + "Platinum Earring", + }, + }, + ["Spinel Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Spinel", + "Ptm. Earring +1", + }, + }, + ["Spinel Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Spinel", + "Platinum Ring", + }, + }, + ["Spinel Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Spinel", + "Platinum Ring +1", + }, + }, + ["Spirit Core"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Adaman Ore", + "Adaman Ore", + "Adaman Ore", + "Earth Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Spirit Maul"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Holy Maul", + }, + }, + ["Spirit Orichalcum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + "Orichalcum Ore", + "Earth Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Spirit Shell"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Turtle Shell", + "Earth Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Spirit Smilodon Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Earth Anima", + "Earth Anima", + "Dark Anima", + "Smilodon Hide", + "Distilled Water", + }, + }, + ["Spirit Smilodon Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Earth Anima", + "Earth Anima", + "Dark Anima", + "Smilodon Hide", + "Distilled Water", + }, + }, + ["Spirit Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Holy Sword", + }, + }, + ["Spolia Chapeau"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Beeswax", + "Mag. Ctn. Cloth", + "Sheep Chammy", + "Wyrdweave", + "Wyrdweave", + "Wyrdweave", + }, + }, + ["Spolia Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mag. Ctn. Cloth", + "Sheep Chammy", + "Wyrdweave", + "Wyrdweave", + "Wyrdweave", + }, + }, + ["Spolia Pigaches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Chammy", + "Catobl. Leather", + "Wyrdstrand", + "Wyrdweave", + "Wyrdweave", + }, + }, + ["Spolia Saio"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Chain", + "Beeswax", + "Buffalo Leather", + "Mag. Ctn. Cloth", + "Sheep Chammy", + "Wyrdstrand", + "Wyrdweave", + "Wyrdweave", + }, + }, + ["Spolia Trews"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mag. Ctn. Cloth", + "Mag. Ctn. Cloth", + "Sheep Chammy", + "Wyrdstrand", + "Wyrdweave", + }, + }, + ["Spore Bomb"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Firesand", + "Bast Parchment", + "Danceshroom", + }, + }, + ["Sprightly Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Danceshroom", + "Wild Onion", + "Reishi Mushroom", + "Distilled Water", + "Agaricus", + }, + }, + ["Square Jalousie"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Sieglinde Putty", + "Glass Sheet", + }, + }, + ["Squid Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Gigant Squid", + "Distilled Water", + "Ground Wasabi", + }, + }, + ["Stabilizer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Sieglinde Putty", + "Ebonite", + "Black Ghost", + "Water Tank", + }, + }, + ["Stabilizer II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Sieglinde Putty", + "High Ebonite", + "Black Ghost", + "Water Tank", + }, + }, + ["Stabilizer III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Sieglinde Putty", + "High Ebonite", + "Black Ghost", + "Water Tank", + }, + }, + ["Stabilizer IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Sieglinde Putty", + "High Ebonite", + "Black Ghost", + "Water Tank", + }, + }, + ["Stabilizer V"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Sieglinde Putty", + "High Ebonite", + "Black Ghost", + "Water Tank", + }, + }, + ["Stamina Apple"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Faerie Apple", + "Yogurt", + }, + }, + ["Star Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Star Sapphire", + "Ocl. Earring", + }, + }, + ["Star Globe"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Garnet", + "Gold Thread", + "Animal Glue", + "Bast Parchment", + "Bast Parchment", + "Wisteria Lumber", + "Lqr. Tree Lbr.", + }, + }, + ["Star Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Star Sapphire", + "Orichalcum Ring", + }, + }, + ["Staunch Tathlum"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Plovid Flesh", + "Macuil Horn", + "Defiant Scarf", + "Hades' Claw", + }, + }, + ["Staurobow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mahogany Lbr.", + "Ebony Lumber", + "Rattan Lumber", + "Carbon Fiber", + "Flauros Whisker", + "Unicorn Horn", + }, + }, + ["Stealth Screen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Water Anima", + "Glass Sheet", + "Homncl. Nerves", + "Plasma Oil", + }, + }, + ["Stealth Screen II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hecteyes Eye", + "Water Anima", + "Homncl. Nerves", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Steamed Catfish"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Dried Marjoram", + "Maple Sugar", + "Grape Juice", + "Giant Catfish", + "Distilled Water", + "Gysahl Greens", + }, + }, + ["Steel Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Firesand", + }, + }, + ["Steel Cuisses"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Scales", + "Steel Scales", + "Cotton Thread", + "Leather Trousers", + }, + }, + ["Steel Finger Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Scales", + "Steel Scales", + "Cotton Thread", + "Leather Gloves", + }, + }, + ["Steel Greaves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Scales", + "Steel Scales", + "Cotton Thread", + "Leather Highboots", + }, + }, + ["Steel Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Bomb Ash", + "Iron Sand", + "Iron Sand", + "Iron Sand", + "Iron Sand", + }, + }, + ["Steel Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bomb Ash", + "Iron Sand", + "Iron Sand", + "Iron Sand", + "Iron Sand", + "Cluster Ash", + }, + }, + ["Steel Ingot 3"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Steel Nugget", + "Steel Nugget", + "Steel Nugget", + "Steel Nugget", + "Steel Nugget", + "Steel Nugget", + }, + }, + ["Steel Ingot 4"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sand", + "Iron Sand", + "Iron Sand", + "Iron Sand", + "Djinn Ash", + }, + }, + ["Steel Kilij"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Aluminum Ingot", + "Aluminum Ingot", + "Rosewood Lbr.", + "Amethyst", + "Ametrine", + "Karakul Leather", + }, + }, + ["Steel Scale Mail"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Scales", + "Steel Scales", + "Steel Scales", + "Steel Scales", + "Cotton Thread", + "Sheep Leather", + "Leather Vest", + }, + }, + ["Steel Scales"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Sheet", + }, + }, + ["Steel Scales 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Smith. Kit 40", + }, + }, + ["Steel Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + }, + }, + ["Steel Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Workshop Anvil", + }, + }, + ["Steel Visor"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Sheet", + "Iron Scales", + "Sheep Leather", + }, + }, + ["Steel Walnut Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Log", + "Earth Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Steel-splitter"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Stl. Wal. Lumber", + "Iron-splitter", + }, + }, + ["Stepping Stool"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + "Ebony Lumber", + "Ebony Lumber", + }, + }, + ["Sticky Webbing"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gnat Wing", + "Twitherym Wing", + "Mantid Carapace", + "Chapuli Wing", + }, + }, + ["Stikini Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Koh-I-Noor", + "Dark Matter", + "Dark Matter", + "Tartarian Chain", + "Tartarian Chain", + }, + }, + ["Stirge Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ram Leather", + "Mercury", + "Toad Oil", + "Volant Serum", + }, + }, + ["Stone Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Stone Arrowhd.", + "Chocobo Fltchg.", + }, + }, + ["Stone Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Flint Stone", + "Flint Stone", + }, + }, + ["Stone Bangles"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Spirit Shell", + "Turtle Bangles", + }, + }, + ["Stone Cheese"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Rock Salt", + "Selbina Milk", + }, + }, + ["Stoneskin Torque"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Indurated Gold", + "Torque", + }, + }, + ["Strength Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Boyahda Moss", + "Red Rose", + "Dried Mugwort", + "Honey", + "Distilled Water", + }, + }, + ["Strobe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Silver Sheet", + "Glass Sheet", + "Orobon Lure", + "Polyflan", + "Plasma Oil", + }, + }, + ["Strobe II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Orobon Lure", + "Polyflan", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Studded Bandana"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Leather Bandana", + }, + }, + ["Studded Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Dhalmel Leather", + "Leather Highboots", + }, + }, + ["Studded Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Dhalmel Leather", + "Leather Gloves", + }, + }, + ["Studded Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Dhalmel Leather", + "Leather Trousers", + }, + }, + ["Studded Trousers 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Leath. Kit 30", + }, + }, + ["Studded Vest"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Dhalmel Leather", + "Ram Leather", + "Leather Vest", + }, + }, + ["Stuffed Pitaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Rock Salt", + "Imperial Flour", + "G. Sheep Meat", + "Mithran Tomato", + "Distilled Water", + "Graubg. Lettuce", + "Paprika", + }, + }, + ["Stun Claws"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Paralyze Potion", + "Cermet Claws", + }, + }, + ["Stun Jamadhars"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Paralyze Potion", + "Jamadhars", + }, + }, + ["Stun Knife"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Paralyze Potion", + "Cermet Knife", + }, + }, + ["Stun Knife 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 80", + }, + }, + ["Stun Kukri"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Paralyze Potion", + "Cermet Kukri", + }, + }, + ["Sturdy Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Water Cell", + "Slacks", + }, + }, + ["Sturdy Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Earth Cell", + "Leather Trousers", + }, + }, + ["Styrne Byrnie"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Dhalmel Leather", + "Tiger Leather", + "Behem. Leather", + "Herensugue Skin", + "Silver Mail", + }, + }, + ["Sublime Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Bibiki Urchin", + "Cheval Salmon", + "Black Sole", + "Gugru Tuna", + "Bird Egg", + "Ground Wasabi", + }, + }, + ["Sublime Sushi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Bibiki Urchin", + "Cheval Salmon", + "Black Sole", + "Gugru Tuna", + "Bird Egg", + "Wasabi", + }, + }, + ["Sugar Rusk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Maple Sugar", + "Iron Bread", + "Bird Egg", + }, + }, + ["Sugary Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Rolanberry", + "Honey", + "Walnut", + "Ulbuconut", + }, + }, + ["Sukezane"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Cotton Thread", + "Manta Leather", + "Kunwu Iron", + "Yggdreant Bole", + }, + }, + ["Sultan's Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "R. Bgd. Leather", + "Koenigs Belt", + }, + }, + ["Summoner's Collar"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Cehuetzi Claw", + "Dark Matter", + "Cyan Coral", + "Rutile Crystal", + "Moldy Collar", + }, + }, + ["Summoner's Staff"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Plovid Effluvium", + "Dark Matter", + "Khoma Thread", + "Moldy Staff", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Rutile Crystal", + }, + }, + ["Sun Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sunstone", + "Gold Earring", + }, + }, + ["Sun Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sunstone", + "Gold Earring +1", + }, + }, + ["Sun Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sunstone", + "Gold Ring", + }, + }, + ["Sun Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sunstone", + "Gold Ring +1", + }, + }, + ["Sun Water"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Beastman Blood", + "Phil. Stone", + "Cactuar Root", + }, + }, + ["Sune-Ate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Silk Thread", + "Silk Cloth", + "Sheep Leather", + }, + }, + ["Sunstone"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ifritite", + }, + }, + ["Super Ether"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Dried Marjoram", + "Dried Marjoram", + "Ahriman Wing", + "Treant Bulb", + "Distilled Water", + }, + }, + ["Sutlac"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Rock Salt", + "Imperial Rice", + "Cornstarch", + "Selbina Milk", + "Apkallu Egg", + }, + }, + ["Sweet Lizard"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lizard Tail", + "Honey", + }, + }, + ["Sweet Rice Cake"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Cinnamon", + "Sticky Rice", + "Gardenia Seed", + "Fresh Mugwort", + "Distilled Water", + }, + }, + ["Sweordfaetels"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "P. Brass Chain", + "Sealord Leather", + "Cehuetzi Pelt", + }, + }, + ["Swirling Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "San d'Or. Carrot", + "San d'Or. Carrot", + "San d'Or. Carrot", + "Verboshroom", + }, + }, + ["Swith Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sparkstrand", + "Wyrdweave", + "Wyrdweave", + }, + }, + ["Swordbelt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Chain", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Tabar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Mythril Ingot", + "Chestnut Lumber", + }, + }, + ["Tabarzin"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Mahogany Lbr.", + "Gold Ingot", + "Mercury", + }, + }, + ["Tabin Beret"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Imp. Silk Cloth", + "Green Beret", + }, + }, + ["Tabin Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Marid Leather", + "Battle Boots", + }, + }, + ["Tabin Bracers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Imp. Silk Cloth", + "Battle Bracers", + }, + }, + ["Tabin Bracers 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 75", + }, + }, + ["Tabin Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Marid Leather", + "Battle Hose", + }, + }, + ["Tabin Jupon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Imp. Silk Cloth", + "Battle Jupon", + }, + }, + ["Tachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Iron Ingot", + "Iron Ingot", + "Tama-Hagane", + "Ash Lumber", + "Cotton Thread", + "Lizard Skin", + }, + }, + ["Tactician Magician's Coat +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Tct.Mgc. Coat", + }, + }, + ["Tactician Magician's Cuffs +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Tct.Mgc. Cuffs", + }, + }, + ["Tactician Magician's Espadon +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Tct.Mag. Espadon", + }, + }, + ["Tactician Magician's Hat +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Tct.Mgc. Hat", + }, + }, + ["Tactician Magician's Hooks +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Demon Horn", + "Tct.Mag. Hooks", + }, + }, + ["Tactician Magician's Pigaches +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Tct.Mgc. Pigaches", + }, + }, + ["Tactician Magician's Slops +1"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Tct.Mgc. Slops", + }, + }, + ["Tactician Magician's Wand +1"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Tct.Mag. Wand", + }, + }, + ["Taffeta Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Taffeta Cloth", + "Taffeta Cloth", + }, + }, + ["Taikyoku Kenpogi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lam. Earth Cell", + "Lam. Wind Cell", + "Kenpogi", + }, + }, + ["Talisman Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Al. Cotton Cloth", + "Cotton Cape", + }, + }, + ["Talisman Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Al. Cotton Cloth", + "Heko Obi", + }, + }, + ["Tanegashima"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Steel Ingot", + "Steel Ingot", + "Oak Lumber", + }, + }, + ["Tarasque Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Thread", + "Saruta Cotton", + "Tarasque Skin", + "Tarasque Skin", + }, + }, + ["Targe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Sheet", + "Iron Sheet", + "Holly Lumber", + }, + }, + ["Targe 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 35", + }, + }, + ["Tariqah"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Marid Leather", + "Marid Hair", + "Tariqah -1", + }, + }, + ["Tarutaru Desk"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Lauan Lumber", + "Lauan Lumber", + "Lauan Lumber", + "Lauan Lumber", + "Linen Cloth", + "Linen Cloth", + }, + }, + ["Tarutaru Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Taru. Rod", + }, + }, + ["Tarutaru Fishing Rod 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Silk Thread", + }, + }, + ["Tarutaru Fishing Rod 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wood. Kit 65", + }, + }, + ["Tarutaru Folding Screen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Parchment", + "Parchment", + "Parchment", + }, + }, + ["Tarutaru Sash"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Rainbow Thread", + "Silver Thread", + "Gold Thread", + "Manticore Hair", + "Manticore Hair", + }, + }, + ["Tarutaru Sash 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 95", + }, + }, + ["Tarutaru Stool"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Elm Lumber", + }, + }, + ["Tarutaru Stool 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wood. Kit 25", + }, + }, + ["Tathlum"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + }, + }, + ["Tathlum 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Smith. Kit 30", + }, + }, + ["Tati Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Silver Chain", + "Gabbrath Horn", + "Gabbrath Horn", + }, + }, + ["Tavern Bench"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Mahogany Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + }, + }, + ["Tavnazian Salad"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Apple Vinegar", + "Flint Caviar", + "Grimmonite", + "Frost Turnip", + "San d'Or. Carrot", + "Bastore Bream", + "Noble Lady", + "Beaugreens", + }, + }, + ["Tavnazian Taco"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tavnazian Salad", + "Tortilla", + "Tortilla", + "Salsa", + }, + }, + ["Teak Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Teak Log", + }, + }, + ["Teak Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bundling Twine", + "Teak Log", + "Teak Log", + "Teak Log", + }, + }, + ["Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Grass Thread", + "Grass Cloth", + "Grass Cloth", + }, + }, + ["Temple Knight Army Shield +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Mercury", + "T.K. Army Shield", + }, + }, + ["Temple Knight Army Sword +1"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "T.K. Army Sword", + }, + }, + ["Tempus Fugit"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Plovid Flesh", + "Defiant Scarf", + "Pya'ekue Belt", + }, + }, + ["Tension Spring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Darksteel Ingot", + "Mythril Coil", + "Mythril Coil", + "Myth.Gear Mach.", + }, + }, + ["Tension Spring II"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Darksteel Ingot", + "Mythril Coil", + "Mythril Coil", + "Golden Gear", + }, + }, + ["Tension Spring III"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Darksteel Ingot", + "Mythril Coil", + "Mythril Coil", + "Platinum Gear", + }, + }, + ["Tension Spring IV"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Darksteel Ingot", + "Mythril Coil", + "Mythril Coil", + "Ocl. Gearbox", + }, + }, + ["Tension Spring V"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Darksteel Ingot", + "Golden Coil", + "Golden Coil", + "Ocl. Gearbox", + }, + }, + ["Tentacle Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ginger", + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Kalamar", + }, + }, + ["Tentacle Sushi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ginger", + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Cone Calamary", + }, + }, + ["Terebrokath"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Damascus Ingot", + "Damascus Ingot", + "Gold Ingot", + "Mercury", + "Yggdreant Bole", + }, + }, + ["Testudo Mantle"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Manticore Hair", + "Herensugue Skin", + }, + }, + ["Tewhatewha"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Steel Ingot", + "Steel Ingot", + "Holly Lumber", + "Aramid Fiber", + }, + }, + ["Thalassocrat"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Scintillant Ingot", + "Wamoura Silk", + "Jacaranda Lbr.", + }, + }, + ["The Big One"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Ebony Lumber", + "Gold Sheet", + "Saruta Cotton", + "Beeswax", + "Animal Glue", + "Beetle Blood", + "Titanic Sawfish", + }, + }, + ["Thick Breeches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Chain", + "Dst. Breeches", + }, + }, + ["Thick Mufflers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Darksteel Mufflers", + }, + }, + ["Thick Mufflers 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Smith. Kit 84", + }, + }, + ["Thick Sollerets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Steel Sheet", + "Dst. Sollerets", + }, + }, + ["Thief's Tools"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Yew Lumber", + }, + }, + ["Thokcha Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Thokcha Ore", + "Thokcha Ore", + "Thokcha Ore", + "Thokcha Ore", + }, + }, + ["Throwing Tomahawk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Chestnut Lumber", + "Chestnut Lumber", + }, + }, + ["Thug's Jambiya"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Mythril Ingot", + "Turquoise", + "Wivre Horn", + }, + }, + ["Thunder Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Lightning Cluster", + }, + }, + ["Thunder Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Luminous Shell", + "Carapace Mittens", + }, + }, + ["Thunder Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lightning Bead", + "Orichalcum Ring", + }, + }, + ["Thunder Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Lightning Bead", + }, + }, + ["Thurible"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scintillant Ingot", + "Tr. Brz. Ingot", + "A.U Brass Sheet", + "A.U Brass Sheet", + "A.U Brass Sheet", + }, + }, + ["Thurisaz Blade"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lizard Skin", + "Rhodium Ingot", + "Rhodium Ingot", + "Rhodium Ingot", + "Rhodium Ingot", + "Urunday Lumber", + "Twitherym Scale", + }, + }, + ["Tiger Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Cuir Gloves", + }, + }, + ["Tiger Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Sheep Leather", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Tiger Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["Tiger Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Tiger Hide", + "Distilled Water", + }, + }, + ["Tiger Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Tiger Hide", + "Distilled Water", + }, + }, + ["Tiger Leather 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Win. Tea Leaves", + "Win. Tea Leaves", + "Tiger Hide", + "Tiger Hide", + "Tiger Hide", + "Tanning Vat", + "Distilled Water", + }, + }, + ["Tiger Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Tiger Leather", + "Cuir Highboots", + }, + }, + ["Tiger Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Tiger Hide", + }, + }, + ["Tiger Mantle 2"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Leath. Kit 75", + }, + }, + ["Tiger Mask"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Ram Leather", + "Tiger Hide", + "Tiger Hide", + "Wyvern Skin", + }, + }, + ["Tiger Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Leather", + "Tiger Leather", + "Cuir Trousers", + }, + }, + ["Tigereye Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tiger Eye", + "Silver Ring", + }, + }, + ["Tigereye Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold. Kit 35", + }, + }, + ["Tigerfangs"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Blk. Tiger Fang", + "Blk. Tiger Fang", + "Scorpion Shell", + "Carbon Fiber", + }, + }, + ["Tin Bullet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tin Ingot", + "Firesand", + }, + }, + ["Tin Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tin Ore", + "Tin Ore", + "Tin Ore", + "Tin Ore", + }, + }, + ["Tin Ingot 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Smith. Kit 15", + }, + }, + ["Titanictus Shell"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Titanictus", + }, + }, + ["Titanictus Shell 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Armored Pisces", + }, + }, + ["Titanium Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Titanium Ingot", + }, + }, + ["Titanium Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Titanium Ore", + "Titanium Ore", + "Titanium Ore", + "Titanium Ore", + }, + }, + ["Titanium Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Titanium Ingot", + }, + }, + ["Titanium Sheet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Workshop Anvil", + "Titanium Ingot", + "Titanium Ingot", + "Titanium Ingot", + "Titanium Ingot", + "Titanium Ingot", + "Titanium Ingot", + }, + }, + ["Tojaku"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sprt. Orichalcum", + "Hirenjaku", + }, + }, + ["Tomahawk"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Ash Lumber", + }, + }, + ["Tomato Juice"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Rock Salt", + "Mithran Tomato", + "Mithran Tomato", + "Mithran Tomato", + }, + }, + ["Tomato Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "2Leaf Mandra Bud", + "Wild Onion", + "Tomato Juice", + "Distilled Water", + }, + }, + ["Tomato Soup 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Dried Marjoram", + "Bay Leaves", + "Wild Onion", + "Tomato Juice", + "Distilled Water", + }, + }, + ["Tomonari"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Ancient Lumber", + "Manta Leather", + "Scintillant Ingot", + "Wamoura Silk", + "Midrium Ingot", + "Midrium Ingot", + "Mantid Carapace", + }, + }, + ["Tonno Rosso"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Olive Oil", + "Rock Salt", + "Holy Basil", + "Spaghetti", + "Wild Onion", + "Pomodoro Sauce", + "Lakerda", + }, + }, + ["Tonno Rosso 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mhaura Garlic", + "Olive Oil", + "Rock Salt", + "Holy Basil", + "Spaghetti", + "Wild Onion", + "Gugru Tuna", + "Pomodoro Sauce", + }, + }, + ["Tonosama Rice Ball"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Pamtam Kelp", + "Rock Salt", + "Flint Caviar", + "Distilled Water", + }, + }, + ["Topaz Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Topaz", + "Platinum Earring", + }, + }, + ["Topaz Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Topaz", + "Ptm. Earring +1", + }, + }, + ["Topaz Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Topaz", + "Platinum Ring", + }, + }, + ["Topaz Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Topaz", + "Platinum Ring +1", + }, + }, + ["Toporok"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Adaman Ingot", + "Ebony Lumber", + "Gold Ingot", + "Painite", + "Painite", + "Mercury", + }, + }, + ["Torque"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + "Gold Ingot", + }, + }, + ["Tortilla"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Millioncorn", + "Olive Oil", + "Rock Salt", + }, + }, + ["Tortoise Earring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Gold Chain", + "Turtle Shell", + }, + }, + ["Tortoise Earring 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone. Kit 55", + }, + }, + ["Totem Pole"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Rosewood Lbr.", + "Rosewood Lbr.", + "Rosewood Lbr.", + "White Rock", + "Manticore Hair", + "Manticore Hair", + "Wivre Horn", + }, + }, + ["Tough Belt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "T. Bgd. Leather", + "Barbarian's Belt", + }, + }, + ["Tough Bugard Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Bugard Skin", + "Earth Anima", + "Earth Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Tough Bugard Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Bugard Skin", + "Earth Anima", + "Earth Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Tough Dhalmel Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Dhalmel Hide", + "Wind Anima", + "Wind Anima", + "Dark Anima", + "Distilled Water", + }, + }, + ["Tough Dhalmel Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Dhalmel Hide", + "Wind Anima", + "Wind Anima", + "Dark Anima", + "Distilled Water", + }, + }, + ["Tourmaline"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Green Rock", + }, + }, + ["Tourmaline 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Breeze Geode", + }, + }, + ["Tourmaline Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tourmaline", + "Silver Earring", + }, + }, + ["Tourmaline Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tourmaline", + "Silver Earring +1", + }, + }, + ["Tourmaline Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tourmaline", + "Silver Ring", + }, + }, + ["Tourmaline Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tourmaline", + "Silver Ring +1", + }, + }, + ["Tower Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Ingot", + "Brass Sheet", + "Oak Lumber", + "Oak Lumber", + "Mahogany Lbr.", + "Ebony Lumber", + }, + }, + ["Tracker's Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mahogany Htwd.", + "Crossbow", + }, + }, + ["Trader's Chapeau"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Sheep Leather", + "Beeswax", + "Red Grs. Thread", + "Red Grass Cloth", + "Red Grass Cloth", + }, + }, + ["Trader's Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Sheep Leather", + "Sheep Leather", + "Red Grs. Thread", + "Red Grass Cloth", + }, + }, + ["Trader's Pigaches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dhalmel Leather", + "Sheep Leather", + "Red Grs. Thread", + "Red Grass Cloth", + "Red Grass Cloth", + }, + }, + ["Trader's Saio"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Chain", + "Cotton Cloth", + "Sheep Leather", + "Ram Leather", + "Beeswax", + "Red Grs. Thread", + "Red Grass Cloth", + "Red Grass Cloth", + }, + }, + ["Trader's Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Cotton Cloth", + "Sheep Leather", + "Red Grs. Thread", + "Red Grass Cloth", + }, + }, + ["Tranquilizer II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Sieglinde Putty", + "Homncl. Nerves", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Tranquilizer III"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Sieglinde Putty", + "Homncl. Nerves", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Tranquilizer IV"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Sieglinde Putty", + "Homncl. Nerves", + "Plasma Oil", + "F. Glass Sheet", + }, + }, + ["Transfixion Sphere"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lucky Egg", + }, + }, + ["Transfixion Sphere 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Carbuncle's Ruby", + }, + }, + ["Transfixion Sphere 3"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "White Memosphere", + }, + }, + ["Transfixion Sphere 4"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bruised Starfruit", + }, + }, + ["Transfixion Sphere 5"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Light Crest Card", + }, + }, + ["Translucent Rock"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Marble Nugget", + }, + }, + ["Transom"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Mahogany Lbr.", + "Sieglinde Putty", + "Glass Sheet", + "Silica", + "Pebble", + }, + }, + ["Traversiere"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Parchment", + }, + }, + ["Tree Sap"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Maple Sugar", + "Chestnut Log", + }, + }, + ["Triangular Jalousie"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Sieglinde Putty", + "Glass Sheet", + }, + }, + ["Troll Bronze Sheet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tr. Brz. Ingot", + }, + }, + ["Troll Coif"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Karakul Leather", + "Manticore Hair", + "Marid Leather", + "Marid Hair", + "Mohbwa Cloth", + }, + }, + ["Tropical Crepe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Maple Sugar", + "Kitron", + "Persikos", + "Bird Egg", + "Uleguerand Milk", + "Felicifruit", + }, + }, + ["Tropical Punches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Fruit Punches", + }, + }, + ["Trout Ball"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rye Flour", + "Shining Trout", + "Distilled Water", + }, + }, + ["Trout Ball 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rye Flour", + "Distilled Water", + "Alabaligi", + }, + }, + ["Truesights"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Sheet", + "Wind Bead", + "Homncl. Nerves", + "Plasma Oil", + "High Ebonite", + }, + }, + ["Trumpet Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Trumpet Shell", + "Trumpet Shell", + }, + }, + ["Tsahyan Mask"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Ebony Lumber", + "Ebony Lumber", + "G. Bird Plume", + "G. Bird Plume", + "G. Bird Plume", + "Manticore Hair", + "Avatar Blood", + }, + }, + ["Tsukumo"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Garglle. Shank", + "Ruszor Leather", + "Dweomer Steel", + }, + }, + ["Tsukumo 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Garglle. Shank", + "Ruszor Leather", + "Dweomer Steel", + }, + }, + ["Tsurara"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Rock Salt", + "Distilled Water", + "Distilled Water", + }, + }, + ["Tsurugitachi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lam. Fire Cell", + "Lam. Wind Cell", + "Hosodachi", + }, + }, + ["Tuck"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Silver Ingot", + }, + }, + ["Tulfaire Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Tulfaire Feather", + "Tulfaire Feather", + }, + }, + ["Tulfaire Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Zephyr Thread", + "Tulfaire Feather", + "Tulfaire Feather", + "Tulfaire Feather", + "Tulfaire Feather", + "Tulfaire Feather", + "Tulfaire Feather", + }, + }, + ["Tulwar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Mythril Ingot", + "Silver Ingot", + }, + }, + ["Tuna Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Gugru Tuna", + "Distilled Water", + "Ground Wasabi", + }, + }, + ["Tuna Sushi 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Rice Vinegar", + "Distilled Water", + "Ground Wasabi", + "Lakerda", + }, + }, + ["Tunic"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Turbo Charger II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Glass Fiber", + "Glass Sheet", + "Haste", + "Mega Fan", + "Vanir Battery", + }, + }, + ["Turms Cap"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tiger Leather", + "Cermet Chunk", + "Bztavian Wing", + "Macuil Horn", + "Ruthenium Ore", + "Ruthenium Ore", + "Ruthenium Ore", + }, + }, + ["Turms Harness"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tiger Leather", + "Cermet Chunk", + "Bztavian Wing", + "Macuil Horn", + "Macuil Horn", + "Ruthenium Ore", + "Ruthenium Ingot", + }, + }, + ["Turms Leggings"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tiger Leather", + "Bztavian Wing", + "Macuil Horn", + "Ruthenium Ore", + "Ruthenium Ore", + "Ruthenium Ore", + }, + }, + ["Turms Mittens"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tiger Leather", + "Tiger Leather", + "Bztavian Wing", + "Macuil Horn", + "Ruthenium Ore", + "Ruthenium Ore", + "Ruthenium Ore", + }, + }, + ["Turms Subligar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tiger Leather", + "Cermet Chunk", + "Bztavian Wing", + "Macuil Horn", + "Ruthenium Ore", + "Ruthenium Ingot", + }, + }, + ["Turpid Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Gelatin", + "Yawning Catfish", + "Warthog Meat", + }, + }, + ["Turquoise Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Turquoise", + "Mythril Earring", + }, + }, + ["Turquoise Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Turquoise", + "Mythril Earring +1", + }, + }, + ["Turquoise Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Turquoise", + "Mythril Ring", + }, + }, + ["Turquoise Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Turquoise", + "Mythril Ring +1", + }, + }, + ["Turtle Bangles"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Turtle Shell", + "Turtle Shell", + "Giant Femur", + }, + }, + ["Turtle Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Turtle Shell", + "Beetle Shell", + }, + }, + ["Turtle Shield 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone. Kit 35", + }, + }, + ["Turtle Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ginger", + "Chicken Bone", + "Rock Salt", + "Danceshroom", + "San d'Or. Carrot", + "Red Terrapin", + "Acorn", + "Distilled Water", + }, + }, + ["Twicer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Light Steel", + "Voulge", + }, + }, + ["Twill Damask"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Sparkstrand", + "Sparkstrand", + }, + }, + ["Twinkle Shower"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Firesand", + "Bast Parchment", + "Twinkle Powder", + }, + }, + ["Twinthread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Twincoon", + "Twincoon", + }, + }, + ["Twinthread Obi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Twinthread", + "Twinthread", + "Twinthread", + }, + }, + ["Twitherym Scale"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Twitherym Wing", + "Twitherym Wing", + }, + }, + ["Two-Handed Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Steel Ingot", + "Ash Lumber", + "Lizard Skin", + }, + }, + ["Tyro Katars"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Steel Ingot", + "Ram Leather", + "Grimy Brz. Sheet", + }, + }, + ["Tzustes Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Midrium Ingot", + "Urunday Lumber", + }, + }, + ["Uchigatana"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Iron Ingot", + "Tama-Hagane", + "Elm Lumber", + "Silk Thread", + "Lizard Skin", + }, + }, + ["Uchitake"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bamboo Stick", + "Grass Cloth", + "Toad Oil", + }, + }, + ["Ugol Brayettes"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Durium Chain", + "P. Brass Chain", + "Linen Cloth", + "Light Ram Lth.", + "Light Ram Lth.", + }, + }, + ["Ugol Haubert"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "P. Brass Sheet", + "Durium Ingot", + "Durium Sheet", + "P. Brass Chain", + "P. Brass Chain", + "P. Brass Chain", + "Velvet Cloth", + "Silk Cloth", + }, + }, + ["Ugol Moufles"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "P. Brass Sheet", + "Durium Sheet", + "Chain Mittens", + }, + }, + ["Ugol Salade"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "P. Brass Sheet", + "Durium Ingot", + "P. Brass Chain", + "Vi. Sh. Leather", + "Scintillant Ingot", + "Scintillant Ingot", + }, + }, + ["Ugol Sollerets"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "P. Brass Sheet", + "Durium Sheet", + "Greaves", + }, + }, + ["Ulbuconut Milk"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Elshimo Coconut", + }, + }, + ["Ulbuconut Milk 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ulbuconut", + }, + }, + ["Unicorn Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Gold Thread", + "Tiger Leather", + "Behem. Leather", + "Unicorn Horn", + }, + }, + ["Unicorn Harness"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Tiger Leather", + "Behem. Leather", + "Unicorn Horn", + "Unicorn Horn", + }, + }, + ["Unicorn Leggings"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Behem. Leather", + "Behem. Leather", + "Wyvern Scales", + "Unicorn Horn", + }, + }, + ["Unicorn Mittens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Behem. Leather", + "Wyvern Scales", + "Unicorn Horn", + }, + }, + ["Unicorn Subligar"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Behem. Leather", + "Taffeta Cloth", + "Unicorn Horn", + }, + }, + ["Urchin Sushi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Pamtam Kelp", + "Rice Vinegar", + "Bibiki Urchin", + "Distilled Water", + }, + }, + ["Urja Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Buffalo Leather", + "Squamous Hide", + "Squamous Hide", + }, + }, + ["Urja Helm"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dark Bronze", + "Marid Leather", + "Squamous Hide", + "Squamous Hide", + }, + }, + ["Urja Jerkin"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Buffalo Leather", + "Dark Bronze", + "Squamous Hide", + "Squamous Hide", + "Ogre Jerkin", + }, + }, + ["Urja Ledelsens"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Buffalo Leather", + "Drk. Brz. Sheet", + "Squamous Hide", + "Squamous Hide", + }, + }, + ["Urja Trousers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Buffalo Leather", + "Buffalo Leather", + "Squamous Hide", + "Squamous Hide", + }, + }, + ["Urunday Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Urunday Log", + }, + }, + ["Urunday Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bundling Twine", + "Urunday Log", + "Urunday Log", + "Urunday Log", + }, + }, + ["Urushi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ore", + "Lqr. Tree Sap", + "Lqr. Tree Sap", + "Lqr. Tree Sap", + "Lqr. Tree Sap", + "Honey", + }, + }, + ["Uruz Blade"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Lizard Skin", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + "Midrium Ingot", + "Urunday Lumber", + "Twitherym Scale", + }, + }, + ["Vagabond's Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bronze Scales", + "Grass Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Vagabond's Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Cloth", + "Sheep Leather", + "Sheep Leather", + }, + }, + ["Vagabond's Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Cotton Cloth", + "Cotton Cloth", + }, + }, + ["Vagabond's Tunica"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Grass Cloth", + "Grass Cloth", + "Grass Cloth", + "Cotton Cloth", + "Sheep Leather", + }, + }, + ["Valance"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Sieglinde Putty", + "Glass Sheet", + }, + }, + ["Valor Sword"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Plovid Flesh", + "Dark Matter", + "Khoma Thread", + "Moldy Sword", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Diamond Crystal", + }, + }, + ["Vampire Juice"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Faerie Apple", + "Rolanberry", + "Mithran Tomato", + "Red Terrapin", + }, + }, + ["Vampire Juice 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Faerie Apple", + "Rolanberry", + "Mithran Tomato", + "Kaplumbaga", + }, + }, + ["Vampire Juice 3"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cook. Kit 90", + }, + }, + ["Varar Ring"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Scarletite Ingot", + "Beryllium Ingot", + "Tartarian Chain", + }, + }, + ["Vegetable Gruel"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Chamomile", + "Frost Turnip", + "Rarab Tail", + "Distilled Water", + "Beaugreens", + }, + }, + ["Vegetable Gruel 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tarutaru Rice", + "Chamomile", + "Batagreens", + "Frost Turnip", + "Rarab Tail", + "Distilled Water", + }, + }, + ["Vegetable Paste"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "La Theine Millet", + "Lizard Egg", + "Distilled Water", + "Gysahl Greens", + "Gysahl Greens", + }, + }, + ["Vegetable Soup"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bay Leaves", + "Rock Salt", + "La Theine Cbg.", + "Frost Turnip", + "Wild Onion", + "Eggplant", + "San d'Or. Carrot", + "Distilled Water", + }, + }, + ["Vegetable Soup 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 25", + }, + }, + ["Vejovis Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Kapor Lumber", + "Black C. Feather", + }, + }, + ["Vela Justaucorps"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Beetle Shell", + "Bastet Fang", + "Bastet Fang", + "Wool Robe", + }, + }, + ["Veldt Axe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Penumbral Brass", + "Brass Axe", + }, + }, + ["Vellum"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheep Leather", + "Gold Dust", + "Rolanberry", + }, + }, + ["Velocity Bow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Flauros Whisker", + "Heavy Crossbow", + }, + }, + ["Velvet Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Wool Thread", + "Wool Thread", + }, + }, + ["Velvet Cloth 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silk Thread", + "Cotton Thread", + "Cotton Thread", + }, + }, + ["Velvet Cloth 3"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 50", + }, + }, + ["Velvet Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Peridot", + "Peridot", + "Silver Thread", + "Wool Cloth", + "Velvet Cloth", + }, + }, + ["Velvet Cuffs 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tourmaline", + "Tourmaline", + "Silver Thread", + "Wool Cloth", + "Velvet Cloth", + }, + }, + ["Velvet Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Silk Thread", + "Wool Cloth", + "Velvet Cloth", + "Velvet Cloth", + }, + }, + ["Velvet Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Silver Thread", + "Wool Cloth", + "Wool Cloth", + "Velvet Cloth", + "Velvet Cloth", + }, + }, + ["Velvet Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Silver Thread", + "Wool Cloth", + "Velvet Cloth", + "Velvet Cloth", + }, + }, + ["Vendor's Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Scarlet Linen", + "Bloodthread", + "Imp. Silk Cloth", + "Imp. Silk Cloth", + }, + }, + ["Venom Baselard"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Dst. Baselard", + }, + }, + ["Venom Bolt"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Vnm. Bolt Heads", + }, + }, + ["Venom Bolt 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Ash Lumber", + "Ash Lumber", + "Vnm. Bolt Heads", + "Vnm. Bolt Heads", + "Vnm. Bolt Heads", + "Bundling Twine", + }, + }, + ["Venom Bolt Heads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Animal Glue", + "Venom Potion", + }, + }, + ["Venom Claws"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Darksteel Claws", + }, + }, + ["Venom Dust"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Scorpion Claw", + "Scorpion Claw", + }, + }, + ["Venom Dust 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Istavrit", + }, + }, + ["Venom Dust 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Ogre Eel", + "Ogre Eel", + }, + }, + ["Venom Dust 4"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Monke-Onke", + }, + }, + ["Venom Katars"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Darksteel Katars", + }, + }, + ["Venom Knife"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Darksteel Knife", + }, + }, + ["Venom Kris"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Darksteel Kris", + }, + }, + ["Venom Kukri"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Venom Potion", + "Darksteel Kukri", + }, + }, + ["Venom Kukri 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 75", + }, + }, + ["Venom Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Venom Dust", + }, + }, + ["Venom Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Mercury", + "Mercury", + "Venom Dust", + "Venom Dust", + "Venom Dust", + "Triturator", + }, + }, + ["Verdun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Adaman Ingot", + "Adaman Ingot", + "Gold Ingot", + "Platinum Ingot", + "Spinel", + "Mercury", + }, + }, + ["Vermihumus"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Humus", + "Humus", + }, + }, + ["Vermihumus 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Derfland Humus", + }, + }, + ["Vermihumus 3"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Rich Humus", + "Rich Humus", + }, + }, + ["Vermilion Lacquer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mercury", + "Sulfur", + }, + }, + ["Vermillion Cloak"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Damascene Cloth", + "Damascene Cloth", + "Damascene Cloth", + }, + }, + ["Vermin Slayer"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Lizard Blood", + "Ameretat Vine", + "Darksteel Kilij", + }, + }, + ["Vexed Bliaut"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Bliaut -1", + }, + }, + ["Vexed Bliaut 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bztavian Wing", + "Intuila's Hide", + "Eschite Ore", + "Hexed Bliaut", + }, + }, + ["Vexed Bonnet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Bonnet -1", + }, + }, + ["Vexed Bonnet 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Waktza Crest", + "Hepatizon Ingot", + "Eschite Ore", + "Hexed Bonnet", + }, + }, + ["Vexed Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Boots -1", + }, + }, + ["Vexed Boots 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sif's Macrame", + "Cehuetzi Pelt", + "Eschite Ore", + "Hexed Boots", + }, + }, + ["Vexed Coif"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Coif -1", + }, + }, + ["Vexed Coif 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sif's Macrame", + "Defiant Sweat", + "Eschite Ore", + "Hexed Coif", + }, + }, + ["Vexed Coronet"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Coronet -1", + }, + }, + ["Vexed Coronet 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hepatizon Ingot", + "Immani. Hide", + "Eschite Ore", + "Hexed Coronet", + }, + }, + ["Vexed Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Cuffs -1", + }, + }, + ["Vexed Cuffs 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bztavian Wing", + "Hepatizon Ingot", + "Eschite Ore", + "Hexed Cuffs", + }, + }, + ["Vexed Domaru"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Domaru -1", + }, + }, + ["Vexed Domaru 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beryllium Ingot", + "Muut's Vestment", + "Eschite Ore", + "Hexed Domaru", + }, + }, + ["Vexed Doublet"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Doublet -1", + }, + }, + ["Vexed Doublet 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sif's Macrame", + "Defiant Sweat", + "Eschite Ore", + "Hexed Doublet", + }, + }, + ["Vexed Gages"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Gages -1", + }, + }, + ["Vexed Gages 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sif's Macrame", + "Defiant Sweat", + "Eschite Ore", + "Hexed Gages", + }, + }, + ["Vexed Gamashes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Gamash. -1", + }, + }, + ["Vexed Gamashes 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Macuil Horn", + "Samantha's Vine", + "Eschite Ore", + "Hexed Gamashes", + }, + }, + ["Vexed Gambieras"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Gamb. -1", + }, + }, + ["Vexed Gambieras 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Hepatizon Ingot", + "Immani. Hide", + "Eschite Ore", + "Hexed Gambieras", + }, + }, + ["Vexed Gauntlets"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Gantl. -1", + }, + }, + ["Vexed Gauntlets 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Hepatizon Ingot", + "Immani. Hide", + "Eschite Ore", + "Hexed Gauntlets", + }, + }, + ["Vexed Hakama"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Hakama -1", + }, + }, + ["Vexed Hakama 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cehuetzi Pelt", + "Muut's Vestment", + "Eschite Ore", + "Hexed Hakama", + }, + }, + ["Vexed Haubert"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Haubert -1", + }, + }, + ["Vexed Haubert 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Hepatizon Ingot", + "Immani. Hide", + "Eschite Ore", + "Hexed Haubert", + }, + }, + ["Vexed Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Hose -1", + }, + }, + ["Vexed Hose 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Hepatizon Ingot", + "Plovid Flesh", + "Eschite Ore", + "Hexed Hose", + }, + }, + ["Vexed Jacket"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Jacket -1", + }, + }, + ["Vexed Jacket 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Warblade's Hide", + "Macuil Horn", + "Eschite Ore", + "Hexed Jacket", + }, + }, + ["Vexed Kecks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Kecks -1", + }, + }, + ["Vexed Kecks 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Waktza Crest", + "Warblade's Hide", + "Eschite Ore", + "Hexed Kecks", + }, + }, + ["Vexed Mitra"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Mitra -1", + }, + }, + ["Vexed Mitra 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bztavian Wing", + "Intuila's Hide", + "Eschite Ore", + "Hexed Mitra", + }, + }, + ["Vexed Nails"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Nails -1", + }, + }, + ["Vexed Nails 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sif's Macrame", + "Defiant Sweat", + "Eschite Ore", + "Hexed Nails", + }, + }, + ["Vexed Slops"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Slops -1", + }, + }, + ["Vexed Slops 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sif's Macrame", + "Defiant Sweat", + "Eschite Ore", + "Hexed Slops", + }, + }, + ["Vexed Somen"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Somen -1", + }, + }, + ["Vexed Somen 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beryllium Ingot", + "Muut's Vestment", + "Eschite Ore", + "Hexed Somen", + }, + }, + ["Vexed Sune-Ate"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Sune-Ate -1", + }, + }, + ["Vexed Sune-Ate 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Beryllium Ingot", + "Muut's Vestment", + "Eschite Ore", + "Hexed Sune-Ate", + }, + }, + ["Vexed Tekko"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Tekko -1", + }, + }, + ["Vexed Tekko 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cehuetzi Pelt", + "Muut's Vestment", + "Eschite Ore", + "Hexed Tekko", + }, + }, + ["Vexed Tights"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Tights -1", + }, + }, + ["Vexed Tights 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bztavian Wing", + "Jill's Spittle", + "Eschite Ore", + "Hexed Tights", + }, + }, + ["Vexed Wristbands"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Eschite Ore", + "Hexed Wrist. -1", + }, + }, + ["Vexed Wristbands 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Warblade's Hide", + "Macuil Horn", + "Eschite Ore", + "Hexed Wristbands", + }, + }, + ["Vexer Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Coral Fragment", + "Coral Fragment", + "Twitherym Scale", + "Matamata Shell", + }, + }, + ["Viper Dust"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Khimaira Tail", + }, + }, + ["Viper Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Viper Dust", + }, + }, + ["Viper Potion 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Mercury", + "Mercury", + "Triturator", + "Viper Dust", + "Viper Dust", + "Viper Dust", + }, + }, + ["Vision Amethyst Stone"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Amethyst", + "Earth Anima", + "Lightning Anima", + "Dark Anima", + }, + }, + ["Vision Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Vision Amethyst", + "Amethyst Ring", + }, + }, + ["Vitality Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Chamomile", + "Lizard Tail", + "Dried Mugwort", + "Honey", + "Distilled Water", + }, + }, + ["Vitriol"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Dhalmel Saliva", + }, + }, + ["Vitriol 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Treant Bulb", + "Treant Bulb", + }, + }, + ["Vitriol 3"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Treant Bulb", + "Treant Bulb", + "Treant Bulb", + "Treant Bulb", + "Treant Bulb", + "Treant Bulb", + "Triturator", + }, + }, + ["Vivacity Coat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + "Rgd. Gld. Thread", + }, + }, + ["Vivi-Valve II"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Sheet", + "Glass Fiber", + "Light Bead", + "Vanir Battery", + }, + }, + ["Vivified Coral"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Coral Fragment", + "Lightning Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Vivified Mythril"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ore", + "Mythril Ore", + "Mythril Ore", + "Mythril Ore", + "Lightning Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Vivio Crab Shell"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Crab Shell", + "Wind Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Vivio Femur"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Giant Femur", + "Wind Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Vivio Platinum Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Platinum Ore", + "Platinum Ore", + "Platinum Ore", + "Platinum Ore", + "Wind Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Vivio Scorpion Claw"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Scorpion Claw", + "Wind Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Vivio Sheep Leather"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Willow Log", + "Wind Anima", + "Water Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Vivio Sheep Leather 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheepskin", + "Win. Tea Leaves", + "Wind Anima", + "Water Anima", + "Light Anima", + "Distilled Water", + }, + }, + ["Vivio Wyvern Scale"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wyvern Scales", + "Wind Anima", + "Water Anima", + "Light Anima", + }, + }, + ["Voay Staff"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gua. Lumber", + "Snowsteel Ore", + "Voay Staff -1", + }, + }, + ["Voay Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gua. Lumber", + "Titanium Ore", + "Voay Sword -1", + }, + }, + ["Volant Serum"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Bat Fang", + "Bat Fang", + "Mercury", + }, + }, + ["Volt Gun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Gold Sheet", + "Hiraishin", + "Ebonite", + "Myth.Gear Mach.", + "Battery", + }, + }, + ["Vongole Rosso"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Kazham Peppers", + "Mhaura Garlic", + "Black Pepper", + "Olive Oil", + "Spaghetti", + "Wild Onion", + "Vongola Clam", + "Pomodoro Sauce", + }, + }, + ["Voulge"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Steel Ingot", + "Mythril Ingot", + "Holly Lumber", + }, + }, + ["Vulcan Blade"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Slime Oil", + "Brimsand", + "Flame Blade", + }, + }, + ["Vulcan Claymore"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Brimsand", + "Flame Claymore", + }, + }, + ["Vulcan Degen"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Brimsand", + "Flame Degen", + }, + }, + ["Vulcan Sword"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Slime Oil", + "Brimsand", + "Fire Sword", + }, + }, + ["Wailing Bone Chip"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bone Chip", + "Ice Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Wailing Ram Horn"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ram Horn", + "Ice Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Wailing Shell"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Seashell", + "Ice Anima", + "Earth Anima", + "Dark Anima", + }, + }, + ["Waistbelt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Grass Thread", + "Ram Leather", + "Ram Leather", + }, + }, + ["Wakizashi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Tama-Hagane", + "Elm Lumber", + "Silk Thread", + "Lizard Skin", + }, + }, + ["Walahra Burner"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Ocl. Sheet", + "Ancient Lumber", + "Gold Ingot", + "Gold Sheet", + "Gold Sheet", + }, + }, + ["Walnut Cookie"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Maple Sugar", + "Imperial Flour", + "Distilled Water", + "Apkallu Egg", + "Walnut", + }, + }, + ["Walnut Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Log", + }, + }, + ["Walnut Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Walnut Log", + "Walnut Log", + "Walnut Log", + "Bundling Twine", + }, + }, + ["Wamoura Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wamoura Silk", + "Wamoura Silk", + "Wamoura Silk", + }, + }, + ["Wamoura Silk"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Wam. Cocoon", + "Wam. Cocoon", + }, + }, + ["Wamoura Silk 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Spindle", + "Wam. Cocoon", + "Wam. Cocoon", + "Wam. Cocoon", + "Wam. Cocoon", + "Wam. Cocoon", + "Wam. Cocoon", + }, + }, + ["Wamoura Silk 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Wamoura Hair", + "Wamoura Hair", + }, + }, + ["War Aketon"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Ingot", + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["War Beret"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "G. Bird Plume", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["War Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Coeurl Leather", + "Gold Chain", + "Tiger Leather", + "Tiger Leather", + }, + }, + ["War Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Oak Lumber", + "Oak Lumber", + "Silk Cloth", + "Carbon Fiber", + "Glass Fiber", + }, + }, + ["War Brais"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Linen Cloth", + "Linen Cloth", + "Tiger Leather", + }, + }, + ["War Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Rainbow Thread", + "Velvet Cloth", + "Velvet Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["War Pick"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Ash Lumber", + }, + }, + ["War Shinobi Gi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Chain", + "Darksteel Chain", + "Rainbow Thread", + "Raxa", + "Raxa", + "Raxa", + }, + }, + ["Wardrobe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Walnut Lumber", + "Glass Sheet", + "A.U. Brass Ingot", + "A.U Brass Sheet", + "A.U Brass Sheet", + }, + }, + ["Warhammer"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Elm Lumber", + }, + }, + ["Warp Cudgel"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ether. Oak Lbr.", + "Oak Cudgel", + }, + }, + ["Warrior's Beads"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Waktza Crest", + "Dark Matter", + "Khoma Thread", + "Ruby Crystal", + "Moldy Necklace", + }, + }, + ["Warrior's Belt"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Iron Chain", + "Dhalmel Leather", + }, + }, + ["Warrior's Belt 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Leath. Kit 25", + }, + }, + ["Warrior's Chopper"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Plovid Flesh", + "Dark Matter", + "Khoma Thread", + "Moldy Great Axe", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Ruby Crystal", + }, + }, + ["Warthog Stewpot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Soy Stock", + "Danceshroom", + "Distilled Water", + "Bird Egg", + "Cotton Tofu", + "Napa", + "Shungiku", + "Warthog Meat", + }, + }, + ["Was"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Moonbow Cloth", + "Moonbow Urushi", + "Khoma Cloth", + "Astral Signa", + }, + }, + ["Water Anima"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Somber Memory", + "Somber Memory", + "Somber Memory", + "Somber Memory", + }, + }, + ["Water Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Puk Fletching", + "Water Arrowhds.", + }, + }, + ["Water Arrowheads"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Copper Ingot", + "Merrow Scale", + }, + }, + ["Water Barrel"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Sheet", + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + }, + }, + ["Water Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Water Ore", + }, + }, + ["Water Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Water Cluster", + }, + }, + ["Water Fewell"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Slime Oil", + "Blue Rock", + "Catalytic Oil", + }, + }, + ["Water Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Water Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Water Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Humid. Velvet", + "Black Mitts", + }, + }, + ["Water Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Water Bead", + }, + }, + ["Water Tank"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Sheep Leather", + "Brass Tank", + "Water Cluster", + }, + }, + ["Water Tank 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Karakul Leather", + "Brass Tank", + "Water Cluster", + }, + }, + ["Wax Sword"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Beeswax", + "Bronze Sword", + }, + }, + ["Wetlands Broth"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Petrified Log", + "Loam", + "Snap. Secretion", + "Distilled Water", + }, + }, + ["Whale Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Dolphin Staff", + }, + }, + ["White 3-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "3-Drawer Almirah", + "Gold Thread", + "White Text. Dye", + }, + }, + ["White 6-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "6-Drawer Almirah", + "Gold Thread", + "White Text. Dye", + }, + }, + ["White 9-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "9-Drawer Almirah", + "Gold Thread", + "White Text. Dye", + }, + }, + ["White Bread"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Selbina Butter", + "Rock Salt", + "Honey", + "Distilled Water", + }, + }, + ["White Cape"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["White Cape 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 64", + }, + }, + ["White Cloak"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + "Silk Cloth", + }, + }, + ["White Honey"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Peph. Hive Chip", + "Peph. Hive Chip", + "Peph. Hive Chip", + "Peph. Hive Chip", + }, + }, + ["White Mitts"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Silk Cloth", + "Saruta Cotton", + }, + }, + ["White Mouton"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Ram Skin", + "Shell Powder", + "Shell Powder", + "Distilled Water", + }, + }, + ["White Mouton 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Ram Skin", + "Shell Powder", + "Shell Powder", + "Distilled Water", + }, + }, + ["White Noble's Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Noble's Bed", + "Gold Thread", + "White Text. Dye", + }, + }, + ["White Puppet Turban"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Cotton Cloth", + "Silk Cloth", + }, + }, + ["White Round Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Linen Cloth", + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Platinum Silk", + "Teak Lumber", + "White Text. Dye", + }, + }, + ["White Slacks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Velvet Cloth", + "Silk Cloth", + }, + }, + ["White Storm Lantern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Brass Ingot", + "Silver Ingot", + "Silk Cloth", + "Glass Sheet", + "Sailcloth", + "White Text. Dye", + }, + }, + ["White Tarutaru Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Tarutaru Desk", + "White Text. Dye", + }, + }, + ["White Tarutaru Standing Screen"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Taru F. Screen", + "White Text. Dye", + }, + }, + ["White Textile Dye"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Baking Soda", + }, + }, + ["White Viola"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "White Rock", + "Granite", + "Red Gravel", + "Wildgrass Seeds", + "Humus", + }, + }, + ["White Viola 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Wood. Kit 60", + }, + }, + ["Whitefish Stew"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Black Pepper", + "Rock Salt", + "Selbina Milk", + "Wild Onion", + "San d'Or. Carrot", + "Bastore Bream", + "Distilled Water", + }, + }, + ["Whitefish Stew 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Black Pepper", + "Rock Salt", + "Selbina Milk", + "Wild Onion", + "San d'Or. Carrot", + "Distilled Water", + "Mercanbaligi", + }, + }, + ["Wicker Box"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Willow Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Rattan Lumber", + "Ram Leather", + }, + }, + ["Willow Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Willow Rod", + }, + }, + ["Willow Fishing Rod 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Lumber", + "Grass Thread", + }, + }, + ["Willow Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Log", + }, + }, + ["Willow Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Log", + "Willow Log", + "Willow Log", + "Bundling Twine", + }, + }, + ["Willow Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Willow Lumber", + "Insect Wing", + }, + }, + ["Wind Anima"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mercury", + "Rock Salt", + "Sulfur", + "Fleeting Memory", + "Fleeting Memory", + "Fleeting Memory", + "Fleeting Memory", + }, + }, + ["Wind Arrow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Puk Fletching", + "Wind Arrowhds.", + }, + }, + ["Wind Arrowheads"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Copper Ingot", + "Colibri Beak", + }, + }, + ["Wind Bead"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wind Ore", + }, + }, + ["Wind Card"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Mercury", + "Polyflan Paper", + "Wind Cluster", + }, + }, + ["Wind Fan"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Beetle Shell", + "Giant Femur", + "Beeswax", + "Bat Wing", + "Wind Cluster", + }, + }, + ["Wind Fewell"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Slime Oil", + "Green Rock", + "Catalytic Oil", + }, + }, + ["Wind Lamp"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Wind Ore", + "Scintillant Ingot", + "A.U. Brass Ingot", + }, + }, + ["Wind Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Wind Bead", + }, + }, + ["Windurst Salad"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Apple Vinegar", + "Rolanberry", + "La Theine Cbg.", + "San d'Or. Carrot", + "Mithran Tomato", + "Kazham Pineapl.", + "Yagudo Cherry", + "Pamamas", + }, + }, + ["Windurst Taco"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Hare Meat", + "Wild Onion", + "Tortilla", + "Tortilla", + "Stone Cheese", + "Windurst Salad", + "Salsa", + }, + }, + ["Windurstian Baghnakhs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Bone Chip", + "Fsd. Baghnakhs", + }, + }, + ["Windurstian Bow"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Willow Lumber", + "Freesword's Bow", + }, + }, + ["Windurstian Brais"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Mrc.Cpt. Hose", + }, + }, + ["Windurstian Club"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ash Lumber", + "Freesword's Club", + }, + }, + ["Windurstian Doublet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Mrc.Cpt. Doublet", + }, + }, + ["Windurstian Gaiters"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Mrc.Cpt. Gaiters", + }, + }, + ["Windurstian Gi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Mercenary's Gi", + }, + }, + ["Windurstian Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Mrc.Cpt. Gloves", + }, + }, + ["Windurstian Hachimaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Mrc. Hachimaki", + }, + }, + ["Windurstian Headgear"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Cotton Cloth", + "Mrc.Cpt. Headgear", + }, + }, + ["Windurstian Knife"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Mercenary's Knife", + }, + }, + ["Windurstian Kukri"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Mrc.Cpt. Kukri", + }, + }, + ["Windurstian Kyahan"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Mrc. Kyahan", + }, + }, + ["Windurstian Pole"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ash Lumber", + "Mercenary's Pole", + }, + }, + ["Windurstian Scythe"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Darksteel Ingot", + "Mrc.Cpt. Scythe", + }, + }, + ["Windurstian Sill"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Dogwd. Lumber", + "Sieglinde Putty", + "Glass Sheet", + }, + }, + ["Windurstian Sitabaki"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Mrc. Sitabaki", + }, + }, + ["Windurstian Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Linen Thread", + "Linen Cloth", + "Freesword's Slops", + }, + }, + ["Windurstian Staff"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Holly Lumber", + "Freesword's Staff", + }, + }, + ["Windurstian Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Mrc. Greatsword", + }, + }, + ["Windurstian Tea Set"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Bast Parchment", + "Jacaranda Lbr.", + }, + }, + ["Windurstian Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Grass Cloth", + "Mrc. Tekko", + }, + }, + ["Wing Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Ingot", + "Insect Wing", + "Insect Wing", + }, + }, + ["Wing Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Ardent Jadeite", + "Mythril Gorget", + }, + }, + ["Wing Sword"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Gold Ingot", + "Platinum Ingot", + "Ruby", + "Jagdplaute", + }, + }, + ["Winged Altar"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Platinum Ingot", + "Ocl. Ingot", + "Ruby", + "Gold Brocade", + "Teak Lumber", + "Jacaranda Lbr.", + "Jacaranda Lbr.", + }, + }, + ["Winged Balance"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ocl. Chain", + "Pearl", + "Nidhogg Scales", + "Southern Pearl", + "Angel Skin", + "Marid Tusk", + "Wivre Horn", + "Trumpet Shell", + }, + }, + ["Winged Boots"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lizard Skin", + "Leaping Boots", + }, + }, + ["Winged Plaque"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Sheet", + "Steel Sheet", + "Blsd. Mtl. Sheet", + "Blsd. Mtl. Sheet", + "Ocl. Sheet", + "Platinum Sheet", + "Sapphire", + "Scintillant Ingot", + }, + }, + ["Wingedge"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Silver Ingot", + "Cotton Thread", + }, + }, + ["Wise Braconi"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Silver Thread", + "Velvet Cloth", + "Velvet Cloth", + "Eft Skin", + "Eltoro Leather", + }, + }, + ["Wise Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Silk Cloth", + "Manticore Lth.", + "Eltoro Leather", + }, + }, + ["Wise Gloves"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Silver Thread", + "Velvet Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Eltoro Leather", + "Leather Gloves", + }, + }, + ["Wise Pigaches"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Gold Thread", + "Velvet Cloth", + "Sheep Leather", + "Tiger Leather", + "Eltoro Leather", + }, + }, + ["Wispy Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Loc. Elutriator", + "Shell Bug", + }, + }, + ["Witch Nougat"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Maple Sugar", + "Lizard Egg", + "Selbina Milk", + "Yagudo Cherry", + "White Honey", + "Roasted Almonds", + }, + }, + ["Wivre Gorget"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Karakul Leather", + "Wivre Horn", + }, + }, + ["Wivre Hairpin"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wivre Maul", + }, + }, + ["Wivre Mask"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Karakul Leather", + "Wivre Hide", + }, + }, + ["Wivre Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "A.U. Brass Ingot", + "Wivre Horn", + "Wivre Horn", + }, + }, + ["Wivre Shield"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Sheet", + "Ash Lumber", + "Wivre Hide", + "Wivre Hide", + }, + }, + ["Wolf Felt"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Sheep Wool", + "Sheep Wool", + "Sheep Wool", + "Manticore Hair", + "Wolf Fur", + "Wolf Fur", + "Wolf Fur", + "Distilled Water", + }, + }, + ["Wolf Fur"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Wolf Hide", + "Wolf Hide", + "Wolf Hide", + }, + }, + ["Wolf Gorget"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cotton Thread", + "Wolf Hide", + }, + }, + ["Wolf Mantle"] = { + ["crystal"] = "Ice Crystal", + ["ingredients"] = { + "Wool Thread", + "Wolf Hide", + }, + }, + ["Wooden Arrow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Arrowwood Lbr.", + "Flint Stone", + "Chocobo Fthr.", + "Chocobo Fthr.", + }, + }, + ["Woodworking Set 25"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Elm Lumber", + }, + }, + ["Woodworking Set 45"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Rosewood Log", + }, + }, + ["Woodworking Set 65"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Walnut Lumber", + "Silk Thread", + }, + }, + ["Woodworking Set 71"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Ebony Lumber", + "Ebony Lumber", + "Coeurl Whisker", + }, + }, + ["Woodworking Set 74"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Rosewood Lbr.", + "Silver Thread", + }, + }, + ["Woodworking Set 81"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Holly Lumber", + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + "Oak Lumber", + }, + }, + ["Woodworking Set 84"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Ancient Lumber", + "Round Shield", + }, + }, + ["Woodworking Set 90"] = { + ["crystal"] = "Geo Crystal", + ["ingredients"] = { + "Ancient Lumber", + "Ancient Lumber", + "Coeurl Whisker", + }, + }, + ["Woodworking Set 94"] = { + ["crystal"] = "Vortex Crystal", + ["ingredients"] = { + "Phoenix Feather", + "Urunday Lumber", + }, + }, + ["Wool Bracers"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Wool Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Chocobo Fthr.", + }, + }, + ["Wool Cap 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Cloth. Kit 45", + }, + }, + ["Wool Cloth"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Thread", + "Wool Thread", + }, + }, + ["Wool Cuffs"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Tourmaline", + "Tourmaline", + "Wool Thread", + "Linen Cloth", + "Wool Cloth", + }, + }, + ["Wool Doublet"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Wool Cloth", + "Wool Cloth", + "Saruta Cotton", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Wool Gambison"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Wool Cloth", + "Wool Cloth", + "Saruta Cotton", + "Saruta Cotton", + }, + }, + ["Wool Grease"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Lesser Chigoe", + "Lesser Chigoe", + "Shell Bug", + }, + }, + ["Wool Hat"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Linen Thread", + "Linen Cloth", + "Wool Cloth", + "Wool Cloth", + }, + }, + ["Wool Hose"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Ram Leather", + }, + }, + ["Wool Robe"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Scales", + "Linen Thread", + "Linen Cloth", + "Linen Cloth", + "Wool Cloth", + "Wool Cloth", + }, + }, + ["Wool Slops"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Brass Sheet", + "Wool Thread", + "Linen Cloth", + "Wool Cloth", + "Wool Cloth", + }, + }, + ["Wool Socks"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wool Thread", + "Wool Cloth", + "Wool Cloth", + "Wool Cloth", + "Ram Leather", + }, + }, + ["Wool Thread"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Sheep Wool", + "Sheep Wool", + }, + }, + ["Wool Thread 2"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Sheep Wool", + "Sheep Wool", + "Sheep Wool", + "Sheep Wool", + "Sheep Wool", + "Sheep Wool", + "Spindle", + }, + }, + ["Wool Thread 3"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Cloth. Kit 35", + }, + }, + ["Wootz Amood"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Steel Ingot", + "Steel Ingot", + "Im. Wootz Ingot", + "Im. Wootz Ingot", + "Scintillant Ingot", + "Scintillant Ingot", + "Jacaranda Lbr.", + }, + }, + ["Wootz Ingot"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Steel Ingot", + "Rosewood Lbr.", + "Wootz Ore", + }, + }, + ["Workbench"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Lauan Lumber", + "Lauan Lumber", + "Lauan Lumber", + }, + }, + ["Worm Lure"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Brass Ingot", + "Glass Fiber", + "Little Worm", + }, + }, + ["Worm Lure 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Glass Fiber", + "Animal Glue", + }, + }, + ["Worm Paste"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Cupid Worm", + "Cupid Worm", + "La Theine Millet", + "Lizard Egg", + "Distilled Water", + }, + }, + ["Wormy Broth"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Little Worm", + "Shell Bug", + }, + }, + ["Wrapped Bow"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Lumber", + "Wool Thread", + "Sheep Leather", + }, + }, + ["Wretched Coat"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Malboro Fiber", + "Eltoro Leather", + "Penelope's Cloth", + "Belladonna Sap", + "Plovid Flesh", + "Plovid Flesh", + }, + }, + ["Wulong Shoes"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Grass Thread", + "Cotton Cloth", + "Kung Fu Shoes", + }, + }, + ["Wyrdweave"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Wyrdstrand", + "Wyrdstrand", + "Wyrdstrand", + }, + }, + ["Wyrm Lance"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Defiant Scarf", + "Dark Matter", + "Cypress Log", + "Moldy Polearm", + "Ratnaraj", + "Relic Adaman", + "Relic Adaman", + "Andalusite Crystal", + }, + }, + ["Wyvern Helm"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheep Leather", + "Tiger Leather", + "Guivre's Skull", + "Beeswax", + }, + }, + ["Wyvern Helm 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Sheep Leather", + "Tiger Leather", + "Wyvern Skull", + "Beeswax", + }, + }, + ["Wyvern Spear"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Iron Ingot", + "Tama-Hagane", + "Mahogany Lbr.", + "Gold Thread", + "Wyvern Skin", + }, + }, + ["X-Potion"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Sage", + "Sage", + "Hecteyes Eye", + "Reishi Mushroom", + "Distilled Water", + }, + }, + ["Xiphos"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Bronze Ingot", + "Bronze Ingot", + "Giant Femur", + }, + }, + ["Yacuruna Ring"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yggdreant Root", + "Maliya. Coral", + "Maliya. Coral", + }, + }, + ["Yagudo Drink"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Yagudo Cherry", + "Buburimu Grape", + "Buburimu Grape", + "Buburimu Grape", + }, + }, + ["Yagudo Fletchings"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yagudo Feather", + "Yagudo Feather", + }, + }, + ["Yagudo Fletchings 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yagudo Feather", + "Yagudo Feather", + "Yagudo Feather", + "Yagudo Feather", + "Yagudo Feather", + "Yagudo Feather", + "Zephyr Thread", + }, + }, + ["Yagudo Headgear"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Black Pearl", + "Black Pearl", + "Wool Thread", + "Yagudo Feather", + "Yagudo Feather", + "Cockatrice Skin", + "Bugard Tusk", + "Yagudo Cutting", + }, + }, + ["Yasha Hakama"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Silk Thread", + "Velvet Cloth", + "Velvet Cloth", + "Sheep Leather", + "Tiger Leather", + "Kejusu Satin", + "Kejusu Satin", + }, + }, + ["Yasha Jinpachi"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Chain", + "Kejusu Satin", + "Kejusu Satin", + }, + }, + ["Yasha Samue"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Steel Sheet", + "Rainbow Thread", + "Velvet Cloth", + "Tiger Leather", + "Tiger Leather", + "Kejusu Satin", + "Kejusu Satin", + }, + }, + ["Yasha Sune-Ate"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Silk Thread", + "Tiger Leather", + "Tiger Leather", + "Kejusu Satin", + }, + }, + ["Yasha Tekko"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Darksteel Sheet", + "Darksteel Sheet", + "Darksteel Chain", + "Linen Thread", + "Tiger Leather", + "Kejusu Satin", + }, + }, + ["Yayla Corbasi"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Selbina Butter", + "Rock Salt", + "Apple Mint", + "Imperial Rice", + "Imperial Flour", + "Distilled Water", + "Apkallu Egg", + "Yogurt", + }, + }, + ["Yellow 3-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "3-Drawer Almirah", + "Gold Thread", + "Yellow Txt. Dye", + }, + }, + ["Yellow 6-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "6-Drawer Almirah", + "Gold Thread", + "Yellow Txt. Dye", + }, + }, + ["Yellow 9-Drawer Almirah"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "9-Drawer Almirah", + "Gold Thread", + "Yellow Txt. Dye", + }, + }, + ["Yellow Curry"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Popoto", + "Curry Powder", + "Turmeric", + "Coeurl Meat", + "Selbina Milk", + "Wild Onion", + "Distilled Water", + }, + }, + ["Yellow Curry 2"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Cook. Kit 85", + }, + }, + ["Yellow Curry Bun"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Olive Oil", + "Yellow Curry", + "Bird Egg", + }, + }, + ["Yellow Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chrysoberyl", + "Gold Earring", + }, + }, + ["Yellow Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chrysoberyl", + "Gold Earring +1", + }, + }, + ["Yellow Hobby Bo"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Chestnut Lumber", + "Hickory Lumber", + "Dogwd. Lumber", + "Onyx", + "Onyx", + "Ylw. Chocobo Dye", + }, + }, + ["Yellow Mahogany Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Mahogany Bed", + "Wool Thread", + "Yellow Txt. Dye", + }, + }, + ["Yellow Mouton"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Win. Tea Leaves", + "Ram Skin", + "Orpiment", + "Orpiment", + "Distilled Water", + }, + }, + ["Yellow Mouton 2"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Willow Log", + "Ram Skin", + "Orpiment", + "Orpiment", + "Distilled Water", + }, + }, + ["Yellow Noble's Bed"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Noble's Bed", + "Gold Thread", + "Yellow Txt. Dye", + }, + }, + ["Yellow Round Table"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Lauan Lumber", + "Linen Cloth", + "Linen Cloth", + "Velvet Cloth", + "Velvet Cloth", + "Platinum Silk", + "Teak Lumber", + "Yellow Txt. Dye", + }, + }, + ["Yellow Storm Lantern"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Olive Oil", + "Brass Ingot", + "Silver Ingot", + "Silk Cloth", + "Glass Sheet", + "Sailcloth", + "Yellow Txt. Dye", + }, + }, + ["Yellow Tarutaru Desk"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Tarutaru Desk", + "Yellow Txt. Dye", + }, + }, + ["Yellow Tarutaru Standing Screen"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Taru F. Screen", + "Yellow Txt. Dye", + }, + }, + ["Yellow Textile Dye"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Turmeric", + }, + }, + ["Yellow Viola"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Yellow Rock", + "Granite", + "Red Gravel", + "Wildgrass Seeds", + "Humus", + }, + }, + ["Yetshila"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Animal Glue", + "Waktza Rostrum", + "Waktza Crest", + }, + }, + ["Yew Fishing Rod"] = { + ["crystal"] = "Light Crystal", + ["ingredients"] = { + "Bkn. Yew Rod", + }, + }, + ["Yew Fishing Rod 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Lumber", + "Linen Thread", + }, + }, + ["Yew Lumber"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Log", + }, + }, + ["Yew Lumber 2"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Log", + "Yew Log", + "Yew Log", + "Bundling Twine", + }, + }, + ["Yew Wand"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Yew Lumber", + "Yagudo Feather", + }, + }, + ["Yhatdhara"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Divine Lumber", + "Thokcha Ingot", + "Thokcha Ingot", + "Thokcha Ingot", + "Linen Cloth", + }, + }, + ["Yogurt"] = { + ["crystal"] = "Dark Crystal", + ["ingredients"] = { + "Dogwood Log", + "Selbina Milk", + }, + }, + ["Yogurt Cake"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "San d'Or. Flour", + "Maple Sugar", + "Olive Oil", + "Kitron", + "Selbina Milk", + "Bird Egg", + "Apkallu Egg", + "Yogurt", + }, + }, + ["Yoshikiri"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Tama-Hagane", + "Ebony Lumber", + "Rainbow Thread", + "Wyvern Skin", + "Bismuth Ingot", + }, + }, + ["Yoto"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Animal Glue", + "Vitriol", + "Shinobi-Gatana", + }, + }, + ["Yoto 2"] = { + ["crystal"] = "Water Crystal", + ["ingredients"] = { + "Alch. Kit 55", + }, + }, + ["Zaghnal"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Iron Ingot", + "Iron Ingot", + "Holly Lumber", + "Grass Cloth", + }, + }, + ["Zamburak"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Steel Ingot", + "Oak Lumber", + "Coeurl Whisker", + }, + }, + ["Zamzummim Staff"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Ruby", + "Jacaranda Lbr.", + "Jacaranda Lbr.", + "Daimonic Mandible", + }, + }, + ["Zanbato"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Tama-Hagane", + "Ash Lumber", + "Cotton Thread", + "Raptor Skin", + }, + }, + ["Zaru Soba"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Pamtam Kelp", + "Fish Stock", + "Soba Noodles", + "Distilled Water", + "Ground Wasabi", + "Cibol", + "Puk Egg", + }, + }, + ["Zeal Cap"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Thunder Coral", + "Darksteel Cap", + }, + }, + ["Zestful Sap"] = { + ["crystal"] = "Lightng. Crystal", + ["ingredients"] = { + "Maple Sugar", + "Maple Sugar", + "Maple Sugar", + "Urunday Log", + }, + }, + ["Zinc Oxide"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Zinc Ore", + "Zinc Ore", + "Zinc Ore", + }, + }, + ["Zircon"] = { + ["crystal"] = "Wind Crystal", + ["ingredients"] = { + "Shivite", + }, + }, + ["Zircon Earring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Zircon", + "Gold Earring", + }, + }, + ["Zircon Earring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Zircon", + "Gold Earring +1", + }, + }, + ["Zircon Ring"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Zircon", + "Gold Ring", + }, + }, + ["Zircon Ring 2"] = { + ["crystal"] = "Earth Crystal", + ["ingredients"] = { + "Zircon", + "Gold Ring +1", + }, + }, + ["Zoni"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Rock Salt", + "Sticky Rice", + "Toko. Wildgrass", + "San d'Or. Carrot", + "Tiger Cod", + "Distilled Water", + "Lakerda", + "Ziz Meat", + }, + }, + ["Zunari Kabuto"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Copper Ingot", + "Iron Sheet", + "Iron Sheet", + "Silk Thread", + "Silk Cloth", + }, + }, + ["Zweihander"] = { + ["crystal"] = "Fire Crystal", + ["ingredients"] = { + "Mythril Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Darksteel Ingot", + "Chestnut Lumber", + "Ram Leather", + }, + }, +} diff --git a/addons/craft/slpp.py b/addons/craft/slpp.py new file mode 100644 index 0000000000..ea9c4279b9 --- /dev/null +++ b/addons/craft/slpp.py @@ -0,0 +1,279 @@ +"""Copyright (c) 2010, 2011, 2012 SirAnthony + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.""" + +import re +import sys + +ERRORS = { + 'unexp_end_string': u'Unexpected end of string while parsing Lua string.', + 'unexp_end_table': u'Unexpected end of table while parsing Lua string.', + 'mfnumber_minus': u'Malformed number (no digits after initial minus).', + 'mfnumber_dec_point': u'Malformed number (no digits after decimal point).', + 'mfnumber_sci': u'Malformed number (bad scientific format).', +} + + +class ParseError(Exception): + pass + + +class SLPP(object): + + def __init__(self): + self.text = '' + self.ch = '' + self.at = 0 + self.len = 0 + self.depth = 0 + self.space = re.compile('\s', re.M) + self.alnum = re.compile('\w', re.M) + self.newline = '\n' + self.tab = '\t' + + def decode(self, text): + try: + basestring + except NameError: + basestring = str + if not text or not isinstance(text, basestring): + return + #FIXME: only short comments removed + reg = re.compile('--.*$', re.M) + text = reg.sub('', text, 0) + self.text = text + self.at, self.ch, self.depth = 0, '', 0 + self.len = len(text) + self.next_chr() + result = self.value() + return result + + def encode(self, obj): + self.depth = 0 + return self.__encode(obj) + + def __encode(self, obj): + s = '' + tab = self.tab + newline = self.newline + tp = type(obj) + if isinstance(obj, str): + s += '"%s"' % obj.replace(r'"', r'\"') + if isinstance(obj, str): + s += '"%s"' % obj.encode('utf-8').replace(r'"', r'\"') + elif tp in [int, float, complex]: + s += str(obj) + elif tp is bool: + s += str(obj).lower() + elif obj is None: + s += 'nil' + elif tp in [list, tuple, dict]: + try: + basestring + except NameError: + basestring = str + self.depth += 1 + if len(obj) == 0 or ( tp is not dict and len(filter( + lambda x: type(x) in (int, float) \ + or (isinstance(x, basestring) and len(x) < 10), obj + )) == len(obj) ): + newline = tab = '' + dp = tab * self.depth + s += "%s{%s" % (tab * (self.depth - 2), newline) + if tp is dict: + contents = [] + for k, v in obj.iteritems(): + if type(k) is int: + contents.append(self.__encode(v)) + else: + contents.append(dp + '%s = %s' % (k, self.__encode(v))) + s += (',%s' % newline).join(contents) + else: + s += (',%s' % newline).join( + [dp + self.__encode(el) for el in obj]) + self.depth -= 1 + s += "%s%s}" % (newline, tab * self.depth) + return s + + def white(self): + while self.ch: + if self.space.match(self.ch): + self.next_chr() + else: + break + + def next_chr(self): + if self.at >= self.len: + self.ch = None + return None + self.ch = self.text[self.at] + self.at += 1 + return True + + def value(self): + self.white() + if not self.ch: + return + if self.ch == '{': + return self.object() + if self.ch == "[": + self.next_chr() + if self.ch in ['"', "'", '[']: + return self.string(self.ch) + if self.ch.isdigit() or self.ch == '-': + return self.number() + return self.word() + + def string(self, end=None): + s = '' + start = self.ch + if end == '[': + end = ']' + if start in ['"', "'", '[']: + while self.next_chr(): + if self.ch == end: + self.next_chr() + if start != "[" or self.ch == ']': + return s + if self.ch == '\\' and start == end: + self.next_chr() + if self.ch != end: + s += '\\' + s += self.ch + print(ERRORS['unexp_end_string']) + + def object(self): + o = {} + k = None + idx = 0 + numeric_keys = False + self.depth += 1 + self.next_chr() + self.white() + if self.ch and self.ch == '}': + self.depth -= 1 + self.next_chr() + return o #Exit here + else: + while self.ch: + self.white() + if self.ch == '{': + o[idx] = self.object() + idx += 1 + continue + elif self.ch == '}': + self.depth -= 1 + self.next_chr() + if k is not None: + o[idx] = k + if not numeric_keys and len([ key for key in o if isinstance(key, (str, float, bool, tuple))]) == 0: + ar = [] + for key in o: + ar.insert(key, o[key]) + o = ar + return o #or here + else: + if self.ch == ',': + self.next_chr() + continue + else: + k = self.value() + if self.ch == ']': + numeric_keys = True + self.next_chr() + self.white() + ch = self.ch + if ch in ('=', ','): + self.next_chr() + self.white() + if ch == '=': + o[k] = self.value() + else: + o[idx] = k + idx += 1 + k = None + print(ERRORS['unexp_end_table']) #Bad exit here + + words = {'true': True, 'false': False, 'nil': None} + def word(self): + s = '' + if self.ch != '\n': + s = self.ch + self.next_chr() + while self.ch is not None and self.alnum.match(self.ch) and s not in self.words: + s += self.ch + self.next_chr() + return self.words.get(s, s) + + def number(self): + def next_digit(err): + n = self.ch + self.next_chr() + if not self.ch or not self.ch.isdigit(): + raise ParseError(err) + return n + n = '' + try: + if self.ch == '-': + n += next_digit(ERRORS['mfnumber_minus']) + n += self.digit() + if n == '0' and self.ch in ['x', 'X']: + n += self.ch + self.next_chr() + n += self.hex() + else: + if self.ch and self.ch == '.': + n += next_digit(ERRORS['mfnumber_dec_point']) + n += self.digit() + if self.ch and self.ch in ['e', 'E']: + n += self.ch + self.next_chr() + if not self.ch or self.ch not in ('+', '-'): + raise ParseError(ERRORS['mfnumber_sci']) + n += next_digit(ERRORS['mfnumber_sci']) + n += self.digit() + except ParseError: + t, e = sys.exc_info()[:2] + print(e) + return 0 + try: + return int(n, 0) + except: + pass + return float(n) + + def digit(self): + n = '' + while self.ch and self.ch.isdigit(): + n += self.ch + self.next_chr() + return n + + def hex(self): + n = '' + while self.ch and \ + (self.ch in 'ABCDEFabcdef' or self.ch.isdigit()): + n += self.ch + self.next_chr() + return n + + +slpp = SLPP() + +__all__ = ['slpp'] diff --git a/addons/digger/messages.lua b/addons/digger/messages.lua index b190591272..e9599e2916 100644 --- a/addons/digger/messages.lua +++ b/addons/digger/messages.lua @@ -1,61 +1,61 @@ messages = {} -messages[2] = {bayld=7364, ease=7356, fail=7281, full=7279, notes=7363, points=7361, standing=7362, success=6384} -messages[4] = {bayld=7358, ease=7350, fail=7275, full=7273, notes=7357, points=7355, standing=7356, success=6384} -messages[5] = {bayld=7315, ease=7307, fail=7232, full=7230, notes=7314, points=7312, standing=7313, success=6397} -messages[7] = {bayld=7309, ease=7301, fail=7226, full=7224, notes=7308, points=7306, standing=7307, success=6384} -messages[24] = {bayld=7645, ease=7637, fail=7562, full=7560, notes=7644, points=7642, standing=7643, success=6384} -messages[25] = {bayld=7165, ease=7157, fail=7082, full=7080, notes=7164, points=7162, standing=7163, success=6384} -messages[51] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[52] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[61] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[79] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[81] = {bayld=7824, ease=7816, fail=7741, full=7739, notes=7823, points=7821, standing=7822, success=6384} -messages[82] = {bayld=7456, ease=7448, fail=7373, full=7371, notes=7455, points=7453, standing=7454, success=6384} -messages[83] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[84] = {bayld=7163, ease=7155, fail=7080, full=7078, notes=7162, points=7160, standing=7161, success=6384} -messages[88] = {bayld=7449, ease=7441, fail=7366, full=7364, notes=7448, points=7446, standing=7447, success=6384} -messages[89] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[90] = {bayld=7240, ease=7232, fail=7157, full=7155, notes=7239, points=7237, standing=7238, success=6384} -messages[91] = {bayld=7163, ease=7155, fail=7080, full=7078, notes=7162, points=7160, standing=7161, success=6384} -messages[95] = {bayld=7170, ease=7162, fail=7087, full=7085, notes=7169, points=7167, standing=7168, success=6384} -messages[96] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[97] = {bayld=7701, ease=7693, fail=7618, full=7616, notes=7700, points=7698, standing=7699, success=6384} -messages[98] = {bayld=7701, ease=7693, fail=7618, full=7616, notes=7700, points=7698, standing=7699, success=6384} -messages[100] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[101] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[102] = {bayld=7306, ease=7298, fail=7223, full=7221, notes=7305, points=7303, standing=7304, success=6384} -messages[103] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[104] = {bayld=7798, ease=7790, fail=7715, full=7713, notes=7797, points=7795, standing=7796, success=6406} -messages[105] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[106] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6565} -messages[107] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[108] = {bayld=7306, ease=7298, fail=7223, full=7221, notes=7305, points=7303, standing=7304, success=6384} -messages[109] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[110] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[111] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6565} -messages[112] = {bayld=7341, ease=7333, fail=7258, full=7256, notes=7340, points=7338, standing=7339, success=6397} -messages[113] = {bayld=7644, ease=7636, fail=7561, full=7559, notes=7643, points=7641, standing=7642, success=6384} -messages[114] = {bayld=7644, ease=7636, fail=7561, full=7559, notes=7643, points=7641, standing=7642, success=6384} -messages[115] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[116] = {bayld=7302, ease=7294, fail=7219, full=7217, notes=7301, points=7299, standing=7300, success=6384} -messages[117] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6565} -messages[118] = {bayld=7343, ease=7335, fail=7260, full=7258, notes=7342, points=7340, standing=7341, success=6419} -messages[119] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6406} -messages[120] = {bayld=7332, ease=7324, fail=7249, full=7247, notes=7331, points=7329, standing=7330, success=6406} -messages[121] = {bayld=7644, ease=7636, fail=7561, full=7559, notes=7643, points=7641, standing=7642, success=6384} -messages[122] = {bayld=7302, ease=7294, fail=7219, full=7217, notes=7301, points=7299, standing=7300, success=6384} -messages[123] = {bayld=7644, ease=7636, fail=7561, full=7559, notes=7643, points=7641, standing=7642, success=6384} -messages[124] = {bayld=7644, ease=7636, fail=7561, full=7559, notes=7643, points=7641, standing=7642, success=6384} -messages[125] = {bayld=7302, ease=7294, fail=7219, full=7217, notes=7301, points=7299, standing=7300, success=6384} -messages[126] = {bayld=7302, ease=7294, fail=7219, full=7217, notes=7301, points=7299, standing=7300, success=6384} -messages[127] = {bayld=7302, ease=7294, fail=7219, full=7217, notes=7301, points=7299, standing=7300, success=6384} -messages[128] = {bayld=7302, ease=7294, fail=7219, full=7217, notes=7301, points=7299, standing=7300, success=6384} -messages[136] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[137] = {bayld=7665, ease=7657, fail=7582, full=7580, notes=7664, points=7662, standing=7663, success=6384} -messages[260] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[261] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[262] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[263] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[265] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[266] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} -messages[267] = {bayld=7143, ease=7135, fail=7060, full=7058, notes=7142, points=7140, standing=7141, success=6384} +messages[2] = {bayld=7379, ease=7371, fail=7296, full=7294, notes=7378, points=7376, standing=7377, success=6390} +messages[4] = {bayld=7373, ease=7365, fail=7290, full=7288, notes=7372, points=7370, standing=7371, success=6390} +messages[5] = {bayld=7330, ease=7322, fail=7247, full=7245, notes=7329, points=7327, standing=7328, success=6403} +messages[7] = {bayld=7324, ease=7316, fail=7241, full=7239, notes=7323, points=7321, standing=7322, success=6390} +messages[24] = {bayld=7660, ease=7652, fail=7577, full=7575, notes=7659, points=7657, standing=7658, success=6390} +messages[25] = {bayld=7180, ease=7172, fail=7097, full=7095, notes=7179, points=7177, standing=7178, success=6390} +messages[51] = {bayld=7155, ease=7147, fail=7072, full=7070, notes=7154, points=7152, standing=7153, success=6390} +messages[52] = {bayld=7155, ease=7147, fail=7072, full=7070, notes=7154, points=7152, standing=7153, success=6390} +messages[61] = {bayld=7155, ease=7147, fail=7072, full=7070, notes=7154, points=7152, standing=7153, success=6390} +messages[79] = {bayld=7155, ease=7147, fail=7072, full=7070, notes=7154, points=7152, standing=7153, success=6390} +messages[81] = {bayld=7839, ease=7831, fail=7756, full=7754, notes=7838, points=7836, standing=7837, success=6390} +messages[82] = {bayld=7471, ease=7463, fail=7388, full=7386, notes=7470, points=7468, standing=7469, success=6390} +messages[83] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[84] = {bayld=7178, ease=7170, fail=7095, full=7093, notes=7177, points=7175, standing=7176, success=6390} +messages[88] = {bayld=7464, ease=7456, fail=7381, full=7379, notes=7463, points=7461, standing=7462, success=6390} +messages[89] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[90] = {bayld=7255, ease=7247, fail=7172, full=7170, notes=7254, points=7252, standing=7253, success=6390} +messages[91] = {bayld=7178, ease=7170, fail=7095, full=7093, notes=7177, points=7175, standing=7176, success=6390} +messages[95] = {bayld=7185, ease=7177, fail=7102, full=7100, notes=7184, points=7182, standing=7183, success=6390} +messages[96] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[97] = {bayld=7716, ease=7708, fail=7633, full=7631, notes=7715, points=7713, standing=7714, success=6390} +messages[98] = {bayld=7716, ease=7708, fail=7633, full=7631, notes=7715, points=7713, standing=7714, success=6390} +messages[100] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[101] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[102] = {bayld=7321, ease=7313, fail=7238, full=7236, notes=7320, points=7318, standing=7319, success=6390} +messages[103] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[104] = {bayld=7813, ease=7805, fail=7730, full=7728, notes=7812, points=7810, standing=7811, success=6412} +messages[105] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[106] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6571} +messages[107] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[108] = {bayld=7321, ease=7313, fail=7238, full=7236, notes=7320, points=7318, standing=7319, success=6390} +messages[109] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[110] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[111] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6571} +messages[112] = {bayld=7356, ease=7348, fail=7273, full=7271, notes=7355, points=7353, standing=7354, success=6403} +messages[113] = {bayld=7659, ease=7651, fail=7576, full=7574, notes=7658, points=7656, standing=7657, success=6390} +messages[114] = {bayld=7659, ease=7651, fail=7576, full=7574, notes=7658, points=7656, standing=7657, success=6390} +messages[115] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[116] = {bayld=7317, ease=7309, fail=7234, full=7232, notes=7316, points=7314, standing=7315, success=6390} +messages[117] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6571} +messages[118] = {bayld=7358, ease=7350, fail=7275, full=7273, notes=7357, points=7355, standing=7356, success=6425} +messages[119] = {bayld=7339, ease=7331, fail=7256, full=7254, notes=7338, points=7336, standing=7337, success=6412} +messages[120] = {bayld=7347, ease=7339, fail=7264, full=7262, notes=7346, points=7344, standing=7345, success=6412} +messages[121] = {bayld=7659, ease=7651, fail=7576, full=7574, notes=7658, points=7656, standing=7657, success=6390} +messages[122] = {bayld=7317, ease=7309, fail=7234, full=7232, notes=7316, points=7314, standing=7315, success=6390} +messages[123] = {bayld=7659, ease=7651, fail=7576, full=7574, notes=7658, points=7656, standing=7657, success=6390} +messages[124] = {bayld=7659, ease=7651, fail=7576, full=7574, notes=7658, points=7656, standing=7657, success=6390} +messages[125] = {bayld=7317, ease=7309, fail=7234, full=7232, notes=7316, points=7314, standing=7315, success=6390} +messages[126] = {bayld=7317, ease=7309, fail=7234, full=7232, notes=7316, points=7314, standing=7315, success=6390} +messages[127] = {bayld=7317, ease=7309, fail=7234, full=7232, notes=7316, points=7314, standing=7315, success=6390} +messages[128] = {bayld=7317, ease=7309, fail=7234, full=7232, notes=7316, points=7314, standing=7315, success=6390} +messages[136] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[137] = {bayld=7680, ease=7672, fail=7597, full=7595, notes=7679, points=7677, standing=7678, success=6390} +messages[260] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[261] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[262] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[263] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[265] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[266] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} +messages[267] = {bayld=7158, ease=7150, fail=7075, full=7073, notes=7157, points=7155, standing=7156, success=6390} diff --git a/addons/equipviewer/README.md b/addons/equipviewer/README.md new file mode 100644 index 0000000000..c528c70563 --- /dev/null +++ b/addons/equipviewer/README.md @@ -0,0 +1,44 @@ +**Author:** Tako, Rubenator
+**Version:** 3.3.0
+**Date:** April 13, 2021
+ +* Displays current equipment grid on screen. Also can show current Ammo count and current Encumbrance. + +## Settings + +* Most settings can be modified via commands, but you can edit the settings.xml directly for a few uncommon settings. + +**Abbreviation:** `//ev` + +## Commands +1. position : move display to position (from top left) +2. size : set pixel size of each item slot (defaults to 32 -- same as the size of the item icons) +3. scale : scale multiplier for size of each item slot (1 is 32px) -- modifies same setting as size +4. alpha : set opacity of icons (out of 255) +5. transparency : inverse of alpha (out of 255) -- modifies same setting as alpha +6. background : sets color and opacity of background (out of 255) +7. ammocount: toggles showing current ammo count (defaults to on/true) +8. encumbrance: toggles showing encumbrance Xs (defaultis on/true) +9. hideonzone: toggles hiding while crossing zone lines (default is on/true) +10. hideoncutscene: toggles hiding when in cutscene/npc menu/etc (default is on/true) +11. justify: toggles between ammo text being right or left justifed (default is right justified) +12. help: displays explanations of each command + +Legacy Command: +game_path : sets path to FFXI folder where you want dats extracted from. Backslashes `\` must be escaped (like so: `\\`) or use forewardslash `/` instead. (legacy command as of `3.3.1` in which the game path is now pulled from the registry, but this command is still here in case you want to pull from dats that exist elsewhere) + +### Example Commands +``` +//ev pos 700 400 +//ev size 64 +//ev scale 1.5 +//ev alpha 255 +//ev transparency 200 +//ev background 0 0 0 72 +//ev ammocount +//ev encumbrance +//ev hideonzone +//ev hideoncutscene +//ev justify +//ev help +``` diff --git a/addons/equipviewer/encumbrance.png b/addons/equipviewer/encumbrance.png new file mode 100644 index 0000000000..0b0bff3dde Binary files /dev/null and b/addons/equipviewer/encumbrance.png differ diff --git a/addons/equipviewer/equipviewer.lua b/addons/equipviewer/equipviewer.lua new file mode 100644 index 0000000000..ff5e1e1c02 --- /dev/null +++ b/addons/equipviewer/equipviewer.lua @@ -0,0 +1,743 @@ +--[[ + Copyright © 2021, Rubenator + 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 EquipViewer 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 Rubenator 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 = 'Equipviewer' +_addon.version = '3.3.1' +_addon.author = 'Tako, Rubenator' +_addon.commands = { 'equipviewer', 'ev' } + +require('luau') +local bit = require('bit') +local config = require('config') +local images = require('images') +local texts = require('texts') +local functions = require('functions') +local packets = require('packets') +local icon_extractor = require('icon_extractor') + +local equipment_data = { + [0] = {slot_name = 'main', slot_id = 0, display_pos = 0, item_id = 0, image = nil}, + [1] = {slot_name = 'sub', slot_id = 1, display_pos = 1, item_id = 0, image = nil}, + [2] = {slot_name = 'range', slot_id = 2, display_pos = 2, item_id = 0, image = nil}, + [3] = {slot_name = 'ammo', slot_id = 3, display_pos = 3, item_id = 0, image = nil}, + [4] = {slot_name = 'head', slot_id = 4, display_pos = 4, item_id = 0, image = nil}, + [5] = {slot_name = 'body', slot_id = 5, display_pos = 8, item_id = 0, image = nil}, + [6] = {slot_name = 'hands', slot_id = 6, display_pos = 9, item_id = 0, image = nil}, + [7] = {slot_name = 'legs', slot_id = 7, display_pos = 14, item_id = 0, image = nil}, + [8] = {slot_name = 'feet', slot_id = 8, display_pos = 15, item_id = 0, image = nil}, + [9] = {slot_name = 'neck', slot_id = 9, display_pos = 5, item_id = 0, image = nil}, + [10] = {slot_name = 'waist', slot_id = 10, display_pos = 13, item_id = 0, image = nil}, + [11] = {slot_name = 'left_ear', slot_id = 11, display_pos = 6, item_id = 0, image = nil}, + [12] = {slot_name = 'right_ear', slot_id = 12, display_pos = 7, item_id = 0, image = nil}, + [13] = {slot_name = 'left_ring', slot_id = 13, display_pos = 10, item_id = 0, image = nil}, + [14] = {slot_name = 'right_ring', slot_id = 14, display_pos = 11, item_id = 0, image = nil}, + [15] = {slot_name = 'back', slot_id = 15, display_pos = 12, item_id = 0, image = nil}, +} +local encumbrance_data = {} +for i=0,15 do + encumbrance_data[i] = { slot_name = 'encumbrance', slot_id = i, display_pos = equipment_data[i].display_pos, image = nil } +end +local ammo_count_text = nil +local bg_image = nil + +local defaults = { + pos = { + x = 500, + y = 500 + }, + size = 32, + ammo_text = { + alpha = 230, + red = 255, + green = 255, + blue = 255, + stroke = { + width = 1, + alpha = 127, + red = 0, + green = 0, + blue = 0, + }, + flags = { + bold = true, + italic = true, + } + }, + icon = { + alpha = 230, + red = 255, + green = 255, + blue = 255, + }, + bg = { + alpha = 72, + red = 0, + green = 0, + blue = 0, + }, + show_encumbrance = true, + show_ammo_count = true, + hide_on_zone = true, + hide_on_cutscene = true, + left_justify = false, +} +settings = config.load(defaults) +config.save(settings) +if settings.game_path then + icon_extractor.ffxi_path(settings.game_path) +end +local last_encumbrance_bitfield = 0 + +-- gets the currently equipped item data for the slot information provided +local function get_equipped_item(slotName, slotId, bag, index) + if not bag or not index then -- from memory + local equipment = windower.ffxi.get_items('equipment') + bag = equipment[string.format('%s_bag', slotName)] + index = equipment[slotName] + if equipment_data[slotId] then + equipment_data[slotId].bag_id = bag + equipment_data[slotId].index = index + end + end + if index == 0 then -- empty equipment slot + return 0, 0 + end + local item_data = windower.ffxi.get_items(bag, index) + return item_data.id, item_data.count +end + +-- desc: Updates the ui object(s) for the given slot +local function update_equipment_slot(source, slot, bag, index, item, count) + local slot_data = equipment_data[slot] + slot_data.bag_id = bag or slot_data.bag_id + slot_data.index = index or slot_data.index + if not item then + item, count = get_equipped_item(slot_data.slot_name, slot_data.slot_id, bag, index) + end + if evdebug then + bag = slot_data.bag_id + index = slot_data.index + log('%s %s %d %d %d':format(source, slot_data.slot_name, item, bag or -1, index or -1)) + print('%s %s %d %d %d':format(source, slot_data.slot_name, item, bag or -1, index or -1)) + end + if slot_data.slot_name == 'ammo' then + slot_data.count = count or slot_data.count or 0 + end + if slot_data.image and item ~= nil then + if item == 0 or item == 65535 then -- empty slot + slot_data.image:hide() + slot_data.image:clear() + slot_data.item_id = 0 + slot_data.count = nil + slot_data.image:update() + elseif slot_data.item_id ~= item then + slot_data.item_id = item + local icon_path = string.format('%sicons/%s.bmp', windower.addon_path, slot_data.item_id) + + if not windower.file_exists(icon_path) then + icon_extractor.item_by_id(slot_data.item_id, icon_path) + end + if windower.file_exists(icon_path) then + slot_data.image:path(icon_path) + slot_data.image:alpha(settings.icon.alpha) + slot_data.image:show() + end + end + if slot_data.slot_name == 'ammo' then + display_ammo_count(slot_data.count) + end + slot_data.image:update() + end +end + +-- Updates the texture for all slots if it's a different piece of equipment +local function update_equipment_slots(source) + for slot in pairs(equipment_data) do + update_equipment_slot(source, slot) + end +end + +-- Sets up the image and text ui objects for our equipment +local function setup_ui() + refresh_ui_settings() + destroy() + + bg_image = images.new(bg_image_settings) + bg_image:show() + + for key, slot in pairs(equipment_data) do + slot.item_id = 0 + slot.image = images.new(equipment_image_settings) + position(slot) + end + update_equipment_slots('setup_ui') + + for key, slot in pairs(encumbrance_data) do + slot.image = images.new(encumbrance_image_settings) + slot.image:path(windower.addon_path..'encumbrance.png') + slot.image:hide() + position(slot) + end + display_encumbrance() + + ammo_count_text = texts.new(settings.left_justify and ammo_count_text_settings_left_justify or ammo_count_text_settings) + display_ammo_count() +end + +-- Called when the addon is first loaded. +windower.register_event('load', function() + --Make sure icons directory exists + if not windower.dir_exists(string.format('%sicons', windower.addon_path)) then + windower.create_dir(string.format('%sicons', windower.addon_path)) + end + + if windower.ffxi.get_info().logged_in then + setup_ui() + end +end) + +-- Called whenever character logs out. +windower.register_event('logout', function() + clear_all_equipment_slots() + destroy() +end) + +-- Called whenever character logs in. +windower.register_event('login', function() + setup_ui() + update_equipment_slots('login') +end) + +-- Called when our addon receives an incoming chunk. +windower.register_event('incoming chunk', function(id, original, modified, injected, blocked) + if id == 0x050 then --Equip/Unequip + local packet = packets.parse('incoming', original) + local index = packet['Inventory Index'] + local slot = packet['Equipment Slot'] + local bag = packet['Inventory Bag'] + equipment_data[slot].bag_id = bag + equipment_data[slot].index = index + update_equipment_slot:schedule(0, '0x050', slot, bag, index) + elseif id == 0x020 or id == 0x01F or id == 0x01E then --Item Update / Item Assign (ammo consumption) / 0x01E item count/last ammo shot + local packet = packets.parse('incoming', original) + local bag = packet['Bag'] + local index = packet['Index'] + + local slot = nil + for _,slot_data in pairs(equipment_data) do + if slot_data.bag_id == bag and slot_data.index == index then + slot = slot_data.slot_id + break + end + end + + if slot then + if packet['Status'] ~= 5 and packet['Count'] == 0 then --item not equipped + update_equipment_slot:schedule(0, '0x%x':format(id), slot, 0, 0, 0) + return + end + if slot == 3 then --ammo + local count = packet['Count'] or 0 + display_ammo_count(count) + end + local item = packet['Item'] + update_equipment_slot:schedule(0,'0x%x':format(id), slot, bag, index, item, count) + end + elseif id == 0x01B then -- Job Info (Encumbrance Flags) + local packet = packets.parse('incoming', original) + display_encumbrance(packet['Encumbrance Flags']) + elseif id == 0x0A then -- Finish Zone + show() + elseif id == 0x0B then -- Zone + if settings.hide_on_zone then + hide() + end + end +end) + +-- Called when our addon receives an outgoing chunk. +windower.register_event('outgoing chunk', function(id, original, modified, injected, blocked) + if id == 0x100 then -- Job Change Request + clear_all_equipment_slots() + end +end) + + +-- Destroys all created ui objects +function destroy() + if bg_image then + bg_image:destroy() + bg_image = nil + end + for key, slot_data in pairs(equipment_data) do + if slot_data.image ~= nil then + slot_data.image:destroy() + slot_data.image = nil + end + end + for key, slot_data in pairs(encumbrance_data) do + if slot_data.image ~= nil then + slot_data.image:destroy() + slot_data.image = nil + end + end + if ammo_count_text then + ammo_count_text:destroy() + ammo_count_text = nil + end +end + +-- Shows appropriate ui objects +function show() + if bg_image then + bg_image:show() + end + for key, slot_data in pairs(equipment_data) do + if slot_data.item_id ~= 0 and slot_data.image then + slot_data.image:show() + end + end + display_encumbrance() + display_ammo_count() +end + +-- Hides all ui objects +function hide() + if bg_image then + bg_image:hide() + end + for key, slot_data in pairs(equipment_data) do + if slot_data.image then + slot_data.image:hide() + end + end + for key, slot_data in pairs(encumbrance_data) do + if slot_data.image then + slot_data.image:hide() + end + end + if ammo_count_text then + ammo_count_text:hide() + end +end + +-- Moves ui object to correct spot based on 'display_pos' field +function position(slot) + local pos_x = settings.pos.x + ((slot.display_pos % 4) * settings.size) + local pos_y = settings.pos.y + (math.floor(slot.display_pos / 4) * settings.size) + slot.image:pos(pos_x, pos_y) +end + +-- Clears all equipment slot data and hides ui object +function clear_slot(slot) + local slot_data = equipment_data[slot] + slot_data.image:hide() + slot_data.image:clear() + slot_data.item_id = 0 + slot_data.bag_id = nil + slot_data.index = nil + slot_data.count = nil + slot_data.image:update() + + display_ammo_count() +end + +-- Clears all equipment slot data and hides equipment slot ui objects +function clear_all_equipment_slots() + for slot in pairs(equipment_data) do + clear_slot(slot) + end +end + +-- Shows and hides appropriate encumbrance ui objects and possibly updates encumbrance +-- flags based on provided bitfield number +function display_encumbrance(bitfield) + bitfield = bitfield or last_encumbrance_bitfield + last_encumbrance_bitfield = bitfield + for key, slot in pairs(encumbrance_data) do + if slot.image then + if not settings.show_encumbrance or bit.band(bitfield, bit.lshift(1,key)) == 0 then + slot.image:hide() + else + slot.image:show() + end + end + end +end + +-- Displays appropriatly and possibly updates ammo count and ui object +function display_ammo_count(count) + if not ammo_count_text then return end + count = count or equipment_data[3] and equipment_data[3].count -- 3 == Ammo + equipment_data[3].count = count + if not settings.show_ammo_count or not count or count <= 1 then + ammo_count_text:hide() + else + ammo_count_text:text(count and tostring(count) or '') + ammo_count_text:show() + end +end + +-- Called when player status changes. +windower.register_event('status change', function(new_status_id) + if new_status_id == 4 and settings.hide_on_cutscene then --Cutscene/Menu + hide() + else + show() + end +end) + +-- Called when our addon is unloaded. +windower.register_event('unload', function() + destroy() +end) + +-- Called when the addon receives a command. +windower.register_event('addon command', function (...) + config.reload(settings) + coroutine.sleep(0.5) + local cmd = (...) and (...):lower() or '' + local cmd_args = {select(2, ...)} + if cmd == "gamepath" or cmd == "game_path" then + if #cmd_args == 0 then + error("Must provide path.") + log('Current Path: %s':format( + "\""..settings.game_path.."\"" or "(Default): \""..windower.ffxi_path + )) + return + end + local path = table.concat(cmd_args, " ") + if path:lower() == "default" then + settings.game_path = nil + else + settings.game_path = table.concat(cmd_args, " ") + end + config.save(settings) + icon_extractor.ffxi_path(settings.game_path) + + setup_ui() + + log('game_path set to "%s"':format(path)) + elseif cmd == 'position' or cmd == 'pos' then + if #cmd_args < 2 then + error('Not enough arguments.') + log('Current position: '..settings.pos.x..' '..settings.pos.y) + return + end + + settings.pos.x = tonumber(cmd_args[1]) + settings.pos.y = tonumber(cmd_args[2]) + config.save(settings) + + setup_ui() + + log('Position changed to '..settings.pos.x..', '..settings.pos.y) + elseif cmd == 'size' then + if #cmd_args < 1 then + error('Not enough arguments.') + log('Current size: '..settings.size) + return + end + + settings.size = tonumber(cmd_args[1]) + config.save(settings) + + setup_ui() + + log('Size changed to '..settings.size) + elseif cmd == 'scale' then + if #cmd_args < 1 then + error('Not enough arguments.') + log('Current scale: '..settings.size/32) + return + end + local size = tonumber(cmd_args[1])*32 + if size > 100 then + error('Size too large') + end + settings.size = size + config.save(settings) + + setup_ui() + + log('Size changed to '..settings.size) + elseif cmd == 'alpha' or cmd == 'opacity' then + if #cmd_args < 1 then + error('Not enough arguments.') + log('Current alpha/opacity: %d/255 = %d%%':format( + settings.icon.alpha, math.floor(settings.icon.alpha/255*100) + )) + return + end + local alpha = tonumber(cmd_args[1]) + if alpha <= 1 and alpha > 0 then + settings.icon.alpha = math.floor(255 * (alpha)) + else + settings.icon.alpha = math.floor(alpha) + end + config.save(settings) + + setup_ui() + + log('Alpha/Opacity changed to '..settings.icon.alpha..'/255') + elseif cmd:contains('transpar') then + if #cmd_args < 1 then + error('Not enough arguments.') + log('Current transparency: %d/255 = %d%%':format( + (255-settings.icon.alpha), math.floor((255-settings.icon.alpha)/255)*100 + )) + return + end + local transparency = tonumber(cmd_args[1]) + if transparency <= 1 and transparency > 0 then + settings.icon.alpha = math.floor(255 * (1-transparency)) + else + settings.icon.alpha = math.floor(255-transparency) + end + config.save(settings) + + setup_ui() + + log('Transparency changed to '..255-settings.icon.alpha..'/255') + elseif cmd == 'background' or cmd == 'bg' then + if #cmd_args < 1 then + error('Not enough arguments.') + log('Current BG color: RED:%d/255 GREEN:%d/255 BLUE:%d/255 ALPHA:%d/255 = %d%%':format( + settings.bg.red, settings.bg.green, settings.bg.blue, settings.bg.alpha, math.floor(settings.bg.alpha/255*100) + )) + return + elseif #cmd_args == 1 then + local alpha = tonumber(cmd_args[1]) + if alpha <= 1 and alpha > 0 then + settings.bg.alpha = math.floor(255 * (alpha)) + else + settings.bg.alpha = math.floor(alpha) + end + elseif #cmd_args >= 3 then + settings.bg.red = tonumber(cmd_args[1]) + settings.bg.green = tonumber(cmd_args[2]) + settings.bg.blue = tonumber(cmd_args[3]) + if #cmd_args == 4 then + local alpha = tonumber(cmd_args[4]) + if alpha <= 1 and alpha > 0 then + settings.bg.alpha = math.floor(255 * (alpha)) + else + settings.bg.alpha = math.floor(alpha) + end + end + end + config.save(settings) + + setup_ui() + + log('BG color changed to: RED:%d/255 GREEN:%d/255 BLUE:%d/255 ALPHA:%d/255 = %d%%':format( + settings.bg.red, settings.bg.green, settings.bg.blue, settings.bg.alpha, math.floor(settings.bg.alpha/255*100) + )) + elseif cmd:contains('encumb') then + settings.show_encumbrance = not settings.show_encumbrance + config.save(settings) + + display_encumbrance() + + log('show_encumbrance changed to '..tostring(settings.show_encumbrance)) + elseif cmd:contains('ammo') or cmd:contains('count') then + settings.show_ammo_count = not settings.show_ammo_count + config.save(settings) + + display_ammo_count() + + log('show_ammo_count changed to '..tostring(settings.show_ammo_count)) + elseif cmd == 'hideonzone' or cmd == 'zone' then + settings.hide_on_zone = not settings.hide_on_zone + config.save(settings) + + log('hide_on_zone changed to '..tostring(settings.hide_on_zone)) + elseif cmd == 'hideoncutscene' or cmd == 'cutscene' then + settings.hide_on_cutscene = not settings.hide_on_cutscene + config.save(settings) + + log('hide_on_cutscene changed to '..tostring(settings.hide_on_cutscene)) + elseif cmd == 'justify' then + settings.left_justify = not settings.left_justify + config.save(settings) + + setup_ui() + + log('Ammo text justification changed to '..tostring(settings.left_justify and 'Left' or 'Right')) + elseif cmd == 'testenc' then + display_encumbrance(0xffff) + elseif cmd == 'debug' then + if #cmd_args < 1 then + local e = windower.ffxi.get_items('equipment') + for i=0,15 do + local v = equipment_data[i] + local b = e[string.format('%s_bag', v.slot_name)] + local eb = v.bag_id + local ind = v.index + local eind = e[v.slot_name] + local it = v.item_id + local eit = windower.ffxi.get_items(eb, eind).id + log('%s[%d] it=%d eit=%d b=%d eb=%d i=%d ei=%d':format(v.slot_name,i, it, eit, b, eb, ind, eind)) + end + elseif S{'1', 'on', 'true'}:contains(cmd_args[1]) then + evdebug = true + elseif S{'0', 'off', 'false'}:contains(cmd_args[1]) then + evdebug = false + end + else + log('HELP:') + log('ev position : move to position (from top left)') + log('ev size : set pixel size of each item slot') + log('ev scale : scale multiplier for each item slot (from 32px)') + log('ev alpha : set opacity of icons (out of 255)') + log('ev transparency : inverse of alpha (out of 255)') + log('ev background : sets color and opacity of background (out of 255)') + log('ev ammocount: toggles showing current ammo count') + log('ev encumbrance: toggles showing encumbrance Xs') + log('ev hideonzone: toggles hiding while crossing zone line') + log('ev hideoncutscene: toggles hiding when in cutscene/npc menu/etc') + log('ev justify: toggles between ammo text left and right justify') + end +end) + +function refresh_ui_settings() + --Image and text settings + bg_image_settings = { + alpha = settings.bg.alpha, + color = { + alpha = settings.bg.alpha, + red = settings.bg.red, + green = settings.bg.green, + blue = settings.bg.blue, + }, + pos = { + x = settings.pos.x, + y = settings.pos.y, + }, + size = { + width = settings.size * 4, + height = settings.size * 4, + }, + draggable = false, + } + equipment_image_settings = { + color = { + alpha = settings.icon.alpha, + red = settings.icon.red, + green = settings.icon.green, + blue = settings.icon.blue, + }, + texture = { + fit = false, + }, + size = { + width = settings.size, + height = settings.size, + }, + draggable = false, + } + encumbrance_image_settings = { + color = { + alpha = settings.icon.alpha*0.8, + red = settings.icon.red, + green = settings.icon.green, + blue = settings.icon.blue, + }, + texture = { + fit = false, + }, + size = { + width = settings.size, + height = settings.size, + }, + draggable = false, + } + ammo_count_text_settings = { + text = { + size = settings.size*0.27, + alpha = settings.ammo_text.alpha, + red = settings.ammo_text.red, + green = settings.ammo_text.green, + blue = settings.ammo_text.blue, + stroke = { + width = settings.ammo_text.stroke.width, + alpha = settings.ammo_text.stroke.alpha, + red = settings.ammo_text.stroke.red, + green = settings.ammo_text.stroke.green, + blue = settings.ammo_text.stroke.blue, + }, + }, + bg = { + alpha = 0, + red = 255, + blue = 255, + green = 255 + }, + pos = { + x = (windower.get_windower_settings().ui_x_res - (settings.pos.x + settings.size*4))*-1, + y = settings.pos.y + settings.size*0.58, + }, + flags = { + draggable = false, + right = true, + bold = settings.ammo_text.flags.bold, + italic = settings.ammo_text.flags.italic, + }, + } + ammo_count_text_settings_left_justify = { + text = { + size = settings.size*0.27, + alpha = settings.ammo_text.alpha, + red = settings.ammo_text.red, + green = settings.ammo_text.green, + blue = settings.ammo_text.blue, + stroke = { + width = settings.ammo_text.stroke.width, + alpha = settings.ammo_text.stroke.alpha, + red = settings.ammo_text.stroke.red, + green = settings.ammo_text.stroke.green, + blue = settings.ammo_text.stroke.blue, + }, + }, + bg = { + alpha = 0, + red = 255, + blue = 255, + green = 255 + }, + pos = { + x = settings.pos.x + settings.size*3, + y = settings.pos.y + settings.size*0.58 + }, + flags = { + draggable = false, + right = false, + bold = settings.ammo_text.flags.bold, + italic = settings.ammo_text.flags.italic, + }, + } +end diff --git a/addons/equipviewer/icon_extractor.lua b/addons/equipviewer/icon_extractor.lua new file mode 100644 index 0000000000..0424e7b58d --- /dev/null +++ b/addons/equipviewer/icon_extractor.lua @@ -0,0 +1,266 @@ +--[[ + Copyright © 2021, Rubenator + 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 EquipViewer 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 Rubenator 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. +]] +-- icon_extractor v1.1.2 +-- Written by Rubenator of Leviathan +-- Base Extraction Code graciously provided by Trv of Windower discord +local icon_extractor = {} + +local game_path_default = windower.ffxi_path +local game_path = game_path_default + +local string = require('string') +local io = require('io') +local math = require('math') + +local concat = table.concat +local floor = math.floor +local byte = string.byte +local char = string.char +local sub = string.sub + +local file_size = '\122\16\00\00' +local reserved1 = '\00\00' +local reserved2 = '\00\00' +local starting_address = '\122\00\00\00' + +local default = '\00\00\00\00' + +local dib_header_size = '\108\00\00\00' +local bitmap_width = '\32\00\00\00' +local bitmap_height = '\32\00\00\00' +local n_color_planes = '\01\00' +local bits_per_pixel = '\32\00' +local compression_type = '\03\00\00\00' +local image_size = '\00\16\00\00' +local h_resolution_target = default +local v_resolution_target = default +local default_n_colors = default +local important_colors = default +local alpha_mask = '\00\00\00\255' +local red_mask = '\00\00\255\00' +local green_mask = '\00\255\00\00' +local blue_mask = '\255\00\00\00' +local colorspace = 'sRGB' +local endpoints = string.rep('\00', 36) +local red_gamma = default +local green_gamma = default +local blue_gamma = default + +local header = 'BM' .. file_size .. reserved1 .. reserved2 .. starting_address + .. dib_header_size .. bitmap_width .. bitmap_height .. n_color_planes + .. bits_per_pixel .. compression_type .. image_size + .. h_resolution_target .. v_resolution_target + .. default_n_colors .. important_colors + .. red_mask .. green_mask .. blue_mask .. alpha_mask + .. colorspace .. endpoints .. red_gamma .. green_gamma .. blue_gamma + +--local icon_file = io.open('C:/Program Files (x86)/PlayOnline/SquareEnix/FINAL FANTASY XI/ROM/118/106.DAT', 'rb') +local color_lookup = {} +local bmp_segments = {} + +for i = 0x000, 0x0FF do + color_lookup[string.char(i)] = '' +end + +--[[ +3072 bytes per icon +640 bytes for stats, string table, etc. +2432 bytes for pixel data +--]] + +local item_dat_map = { + [1]={min=0x0001, max=0x0FFF, dat_path='118/106', offset=-1}, -- General Items + [2]={min=0x1000, max=0x1FFF, dat_path='118/107', offset=0}, -- Usable Items + [3]={min=0x2000, max=0x21FF, dat_path='118/110', offset=0}, -- Automaton Items + [4]={min=0x2200, max=0x27FF, dat_path='301/115', offset=0}, -- General Items 2 + [5]={min=0x2800, max=0x3FFF, dat_path='118/109', offset=0}, -- Armor Items + [6]={min=0x4000, max=0x59FF, dat_path='118/108', offset=0}, -- Weapon Items + [7]={min=0x5A00, max=0x6FFF, dat_path='286/73', offset=0}, -- Armor Items 2 + [8]={min=0x7000, max=0x73FF, dat_path='217/21', offset=0}, -- Maze Items, Basic Items + [9]={min=0x7400, max=0x77FF, dat_path='288/80', offset=0}, -- Instinct Items + [10]={min=0xF000, max=0xF1FF, dat_path='288/67', offset=0}, -- Monipulator Items + [11]={min=0xFFFF, max=0xFFFF, dat_path='174/48', offset=0}, -- Gil +} + +local item_by_id = function (id, output_path) + local dat_stats = find_item_dat_map(id) + local icon_file = open_dat(dat_stats) + + local id_offset = dat_stats.min + dat_stats.offset + icon_file:seek('set', (id - id_offset) * 0xC00 + 0x2BD) + local data = icon_file:read(0x800) + + bmp = convert_item_icon_to_bmp(data) + + local f = io.open(output_path, 'wb') + f:write(bmp) + coroutine.yield() + f:close() +end +icon_extractor.item_by_id = item_by_id + +function find_item_dat_map(id) + for _,stats in pairs(item_dat_map) do + if id >= stats.min and id <= stats.max then + return stats + end + end + return nil +end + +function open_dat(dat_stats) + local icon_file = nil + if dat_stats.file then + icon_file = dat_stats.file + else + if not game_path then + error('ffxi_path must be set before using icon_extractor library') + end + filename = game_path .. '/ROM/' .. tostring(dat_stats.dat_path) .. '.DAT' + icon_file, err = io.open(filename, 'rb') + if not icon_file then + error(err) + return + end + dat_stats.file = icon_file + end + return icon_file +end + +-- 32 bit color palette-indexed bitmaps. Bits are rotated and must be decoded. +local encoded_to_decoded_char = {} +local encoded_byte_to_rgba = {} +local alpha_encoded_to_decoded_adjusted_char = {} +local decoded_byte_to_encoded_char = {} +for i = 0x000, 0x0FF do + encoded_byte_to_rgba[i] = '' + local n = (i % 0x20) * 0x8 + floor(i / 0x20) + encoded_to_decoded_char[char(i)] = char(n) + decoded_byte_to_encoded_char[n] = char(i) + n = n * 0x2 + n = n < 0x100 and n or 0x0FF + alpha_encoded_to_decoded_adjusted_char[char(i)] = char(n) +end +local decoder = function(a, b, c, d) + return encoded_to_decoded_char[a].. + encoded_to_decoded_char[b].. + encoded_to_decoded_char[c].. + alpha_encoded_to_decoded_adjusted_char[d] +end +function convert_item_icon_to_bmp(data) + local color_palette = string.gsub(sub(data, 0x001, 0x400), '(.)(.)(.)(.)', decoder) + -- rather than decoding all 2048 bytes, decode only the palette and index it by encoded byte + for i = 0x000, 0x0FF do + local offset = i * 0x4 + 0x1 + encoded_byte_to_rgba[decoded_byte_to_encoded_char[i]] = sub(color_palette, offset, offset + 0x3) + end + + return header .. string.gsub(sub(data, 0x401, 0x800), '(.)', function(a) return encoded_byte_to_rgba[a] end) +end + + +local buff_dat_map = { + [1]={min=0x000, max=0x400, dat_path='119/57', offset=0}, +} +function find_buff_dat_map(id) + for _,stats in pairs(buff_dat_map) do + if id >= stats.min and id <= stats.max then + return stats + end + end + return nil +end +local buff_by_id = function (id, output_path) + local dat_stats = find_buff_dat_map(id) + local icon_file = open_dat(dat_stats) + + local id_offset = dat_stats.min + dat_stats.offset + icon_file:seek('set', (id - id_offset) * 0x1800) + local data = icon_file:read(0x1800) + + bmp = convert_buff_icon_to_bmp(data) + + local f = io.open(output_path, 'wb') + f:write(bmp) + coroutine.yield() + f:close() +end +icon_extractor.buff_by_id = buff_by_id + + +local ffxi_path = function(location) + game_path = location or game_path_default + close_dats() +end +icon_extractor.ffxi_path = ffxi_path + + +-- A mix of 32 bit color uncompressed and *color palette-indexed bitmaps +-- Offsets defined specifically for status icons +-- * some maps use this format as well, but at 512 x 512 +function convert_buff_icon_to_bmp(data) + local length = byte(data, 0x282) -- The length is technically sub(0x281, 0x284), but only 0x282 is unique + + if length == 16 then -- uncompressed + data = sub(data, 0x2BE, 0x12BD) + data = string.gsub(data, '(...)\x80', '%1\xFF') -- All of the alpha bytes are currently 0 or 0x80. + elseif length == 08 then -- color table + local color_palette = sub(data, 0x2BE, 0x6BD) + color_palette = string.gsub(color_palette, '(...)\x80', '%1\xFF') + + local n = 0x0 + for i = 1, 0x400, 0x4 do + color_lookup[char(n)] = sub(color_palette, i, i + 3) + n = n + 1 + end + + data = string.gsub(sub(data, 0x6BE, 0xABD), '(.)', function(i) return color_lookup[i] end) + elseif length == 04 then -- XIVIEW + data = sub(data, 0x2BE, 0x12BD) + end + + return header .. data +end + +function close_dats() + for _,dat in pairs(item_dat_map) do + if dat and dat.file then + dat.file:close() + dat.file = nil + end + end + for _,dat in pairs(buff_dat_map) do + if dat and dat.file then + dat.file:close() + dat.file = nil + end + end +end + +windower.register_event('unload', function() + close_dats() +end); + +return icon_extractor diff --git a/addons/findAll/findAll.lua b/addons/findAll/findAll.lua index ae8f0fe6ba..69167ea3c5 100644 --- a/addons/findAll/findAll.lua +++ b/addons/findAll/findAll.lua @@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'findAll' _addon.author = 'Zohno' -_addon.version = '1.20170501' +_addon.version = '1.20190514' _addon.commands = {'findall'} require('chat') @@ -162,6 +162,9 @@ do end) end end +string.query_escape = function(str) + return (str:gsub('[()%.%+?-]', '%%%1')) +end zone_search = windower.ffxi.get_info().logged_in first_pass = true @@ -169,7 +172,7 @@ item_names = T{} key_item_names = T{} global_storages = T{} storages_path = 'data/' -storages_order_tokens = L{'temporary', 'inventory', 'wardrobe', 'wardrobe 2', 'safe', 'safe 2', 'storage', 'locker', 'satchel', 'sack', 'case'} +storages_order_tokens = L{'temporary', 'inventory', 'wardrobe', 'wardrobe 2', 'wardrobe 3', 'wardrobe 4', 'wardrobe 5', 'wardrobe 6', 'wardrobe 7', 'wardrobe 8', 'safe', 'safe 2', 'storage', 'locker', 'satchel', 'sack', 'case'} -- This is to maintain sorting order. I don't know why this was done, but omitting this will sort the bags arbitrarily, which (I guess) was not intended storages_order = S(res.bags:map(string.gsub-{' ', ''} .. string.lower .. table.get-{'english'})):sort(function(name1, name2) local index1 = storages_order_tokens:find(name1) @@ -189,10 +192,11 @@ storages_order = S(res.bags:map(string.gsub-{' ', ''} .. string.lower .. return index1 < index2 end) -storage_slips_order = L{'slip 01', 'slip 02', 'slip 03', 'slip 04', 'slip 05', 'slip 06', 'slip 07', 'slip 08', 'slip 09', 'slip 10', 'slip 11', 'slip 12', 'slip 13', 'slip 14', 'slip 15', 'slip 16', 'slip 17', 'slip 18', 'slip 19', 'slip 20', 'slip 21', 'slip 22', 'slip 23'} +storage_slips_order = L{'slip 01', 'slip 02', 'slip 03', 'slip 04', 'slip 05', 'slip 06', 'slip 07', 'slip 08', 'slip 09', 'slip 10', 'slip 11', 'slip 12', 'slip 13', 'slip 14', 'slip 15', 'slip 16', 'slip 17', 'slip 18', 'slip 19', 'slip 20', 'slip 21', 'slip 22', 'slip 23', 'slip 24', 'slip 25', 'slip 26', 'slip 27', 'slip 28', 'slip 29', 'slip 30'} merged_storages_orders = storages_order + storage_slips_order + L{'key items'} function search(query, export) + update_global_storage() update() if query:length() == 0 then return @@ -271,7 +275,7 @@ function search(query, export) local terms_pattern = '' if terms ~= '' then - terms_pattern = terms:escape():gsub('%a', function(char) return string.format("[%s%s]", char:lower(), char:upper()) end) + terms_pattern = terms:query_escape():gsub('%a', function(char) return string.format("[%s%s]", char:lower(), char:upper()) end) end for id, names in pairs(item_names) do @@ -468,7 +472,6 @@ function make_table(tab,tab_offset) ret = ret..tostring(v)..',\n' end end - coroutine.yield() return ret..offset..'}' end @@ -490,14 +493,6 @@ function update() self_storage:create() end - global_storages = T{} -- global_storages[server str][character_name str][inventory_name str][item_id num] = count num - - for _,f in pairs(windower.get_dir(windower.addon_path.."\\"..storages_path)) do - if f:sub(-4) == '.lua' and f:sub(1,-5) ~= player_name then - global_storages[f:sub(1,-5)] = dofile(windower.addon_path..'\\'..storages_path..'\\'..f) - end - end - local local_storage = get_local_storage() if local_storage then @@ -511,6 +506,24 @@ function update() return true end + +function update_global_storage() + local player_name = windower.ffxi.get_player().name + + global_storages = T{} -- global_storages[server str][character_name str][inventory_name str][item_id num] = count num + + for _,f in pairs(windower.get_dir(windower.addon_path.."\\"..storages_path)) do + if f:sub(-4) == '.lua' and f:sub(1,-5) ~= player_name then + local success,result = pcall(dofile,windower.addon_path..'\\'..storages_path..'\\'..f) + if success then + global_storages[f:sub(1,-5)] = result + else + warning('Unable to retrieve updated item storage for %s.':format(f:sub(1,-5))) + end + end + end +end + windower.register_event('load', update:cond(function() return windower.ffxi.get_info().logged_in end)) windower.register_event('incoming chunk', function(id,original,modified,injected,blocked) diff --git a/addons/gametime/gametime.lua b/addons/gametime/gametime.lua index 9ea880138a..6b9d4c2a03 100644 --- a/addons/gametime/gametime.lua +++ b/addons/gametime/gametime.lua @@ -1,4 +1,4 @@ --- Copyright © 2013-2016, Omnys of Valefor +-- Copyright © 2013-2016, 2022, Omnys of Valefor -- All rights reserved. -- Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ _addon.name = 'gametime' _addon.author = 'Omnys' -_addon.version = '0.6' +_addon.version = '0.7' _addon.commands = {'gametime','gt'} require('chat') @@ -287,6 +287,7 @@ end windower.register_event('time change', function(new, old) gt.hours = (new / 60):floor() gt.minutes = new % 60 + gt.dectime = timeconvert(gt.hours..':'..gt.minutes) gt.gtt:update(gt) end) diff --git a/addons/giltracker/README.md b/addons/giltracker/README.md new file mode 100644 index 0000000000..2c6e98dfc4 --- /dev/null +++ b/addons/giltracker/README.md @@ -0,0 +1,12 @@ +# giltracker +This addon displays the current gil, similar to the FFXIV Gil HUD widget. + +![Imgur](https://i.imgur.com/vZ8NkDr.png) + +## How to edit the settings +1. Login to your character in FFXI +2. Edit the addon settings file: **_Windower4\addons\giltracker\data\settings.xml_** +3. Save the file +4. Press Insert in FFXI to access the windower console +5. Type ``` lua r giltracker ``` to reload the addon +6. Press Insert in FFXI again to close the windower console diff --git a/addons/giltracker/gil.png b/addons/giltracker/gil.png new file mode 100644 index 0000000000..df56142f25 Binary files /dev/null and b/addons/giltracker/gil.png differ diff --git a/addons/giltracker/giltracker.lua b/addons/giltracker/giltracker.lua new file mode 100644 index 0000000000..3612a0e927 --- /dev/null +++ b/addons/giltracker/giltracker.lua @@ -0,0 +1,239 @@ +--[[ BSD License Disclaimer + Copyright © 2017, sylandro + 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 giltracker 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 sylandro 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 = 'giltracker' +_addon.author = 'sylandro' +_addon.version = '1.0.0' +_addon.language = 'English' + +config = require('config') +images = require('images') +texts = require('texts') +packets = require('packets') + +local GIL_ITEM_ID = 65535 +local CUTSCENE_STATUS_ID = 4 +local SCROLL_LOCK_KEY = 70 +local INVENTORY_FINISH_PACKET = 0x1D +local TREASURE_FIND_ITEM_PACKET = 0xD2 +local LOGIN_ZONE_PACKET = 0x0A +local ITEM_UPDATE_PACKET = 0x20 +local ITEM_MODIFY_PACKET = 0x1F + +local hideKey = SCROLL_LOCK_KEY +local is_hidden_by_cutscene = false +local is_hidden_by_key = false + +defaults = {} +defaults.hideKey = SCROLL_LOCK_KEY +defaults.gilText = {} +defaults.gilText.bg = {} +defaults.gilText.bg.alpha = 100 +defaults.gilText.bg.red = 0 +defaults.gilText.bg.green = 0 +defaults.gilText.bg.blue = 0 +defaults.gilText.bg.visible = false +defaults.gilText.text = {} +defaults.gilText.text.font = 'sans-serif' +defaults.gilText.text.fonts = {'Arial','Trebuchet MS'} +defaults.gilText.text.size = 9 +defaults.gilText.flags = {} +defaults.gilText.flags.italic = true +defaults.gilText.flags.bold = false +defaults.gilText.flags.right = true +defaults.gilText.flags.bottom = true +defaults.gilText.pos = {} +defaults.gilText.pos.x = -285 +defaults.gilText.pos.y = -35 +defaults.gilText.text.alpha = 255 +defaults.gilText.text.red = 253 +defaults.gilText.text.green = 252 +defaults.gilText.text.blue = 250 +defaults.gilText.text.stroke = {} +defaults.gilText.text.stroke.alpha = 200 +defaults.gilText.text.stroke.red = 50 +defaults.gilText.text.stroke.green = 50 +defaults.gilText.text.stroke.blue = 50 +defaults.gilText.text.stroke.width = 2 +defaults.gilText.text.visible = true +defaults.gilImage = {} +defaults.gilImage.color = {} +defaults.gilImage.color.alpha = 255 +defaults.gilImage.color.red = 255 +defaults.gilImage.color.green = 255 +defaults.gilImage.color.blue = 255 +defaults.gilImage.visible = true + +local settings = config.load(defaults) +config.save(settings) + +settings.gilImage.texture = {} +settings.gilImage.texture.path = windower.addon_path..'gil.png' +settings.gilImage.texture.fit = true +settings.gilImage.size = {} +settings.gilImage.size.height = 23 +settings.gilImage.size.width = 23 +settings.gilImage.draggable = false +settings.gilImage.repeatable = {} +settings.gilImage.repeatable.x = 1 +settings.gilImage.repeatable.y = 1 + +local gil_image = images.new(settings.gilImage) +local gil_text = texts.new(settings.gilText) +local inventory_loaded = false +local ready = false + +config.register(settings, function(settings) + hideKey = settings.hideKey + local windower_settings = windower.get_windower_settings() + local xRes = windower_settings.ui_x_res + local yRes = windower_settings.ui_y_res + gil_image:pos(xRes + settings.gilText.pos.x + 1, + yRes + settings.gilText.pos.y - (settings.gilImage.size.height/6)) +end) + +windower.register_event('load',function() + if windower.ffxi.get_info().logged_in then + initialize() + end +end) + +windower.register_event('login',function() + gil_text:text('Loading...') +end) + +windower.register_event('logout', function(...) + inventory_loaded = false + hide() +end) + +windower.register_event('add item', function(_bag,_index,id,...) + if (id == GIL_ITEM_ID) then ready = true end +end) + +windower.register_event('remove item', function(_bag,_index,id,...) + if (id == GIL_ITEM_ID) then ready = true end +end) + +windower.register_event('incoming chunk',function(id,org,_modi,_is_injected,_is_blocked) + if (id == LOGIN_ZONE_PACKET) then + inventory_loaded = false + elseif (id == TREASURE_FIND_ITEM_PACKET) then + ready_if_valid_treasure_packet(org) + elseif (id == ITEM_UPDATE_PACKET) then + update_if_valid_item_packet(org) + elseif (id == INVENTORY_FINISH_PACKET) then + refresh_gil() + elseif (id == ITEM_MODIFY_PACKET) then + update_if_valid_item_packet(org) + end +end) + +windower.register_event('status change', function(new_status_id) + local is_cutscene_playing = is_cutscene(new_status_id) + toggle_display_if_cutscene(is_cutscene_playing) +end) + +windower.register_event('keyboard', function(dik, down, _flags, _blocked) + toggle_display_if_hide_key_is_pressed(dik, down) +end) + +function ready_if_valid_treasure_packet(packet_data) + local p = packets.parse('incoming',packet_data) + if (p.Count > 0) then ready = true end +end + +function update_if_valid_item_packet(packet_data) + local p = packets.parse('incoming',packet_data) + if (p.Item == GIL_ITEM_ID and p.Count >= 0) then + update_gil() + end +end + +function refresh_gil() + if (ready and inventory_loaded) then + update_gil() + ready = false + elseif (not inventory_loaded) then + initialize() + end +end + +function initialize() + inventory_loaded = true + update_gil() + if not is_hidden_by_key and not is_hidden_by_cutscene then show() end +end + +function update_gil() + local gil = windower.ffxi.get_items('gil') + gil_text:text(comma_value(gil)) +end + +function show() + gil_text:show() + gil_image:show() +end + +function hide() + gil_text:hide() + gil_image:hide() +end + +function comma_value(amount) + local formatted = tostring(amount) + while true do + formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') + if (k==0) then break end + end + return formatted +end + +function is_cutscene(status_id) + return status_id == CUTSCENE_STATUS_ID +end + +function toggle_display_if_cutscene(is_cutscene_playing) + if (is_cutscene_playing) and (not is_hidden_by_key) then + is_hidden_by_cutscene = true + hide() + elseif (not is_cutscene_playing) and (not is_hidden_by_key) then + is_hidden_by_cutscene = false + show() + end +end + +function toggle_display_if_hide_key_is_pressed(key_pressed, key_down) + if (key_pressed == hideKey) and (key_down) and (is_hidden_by_key) and (not is_hidden_by_cutscene) then + is_hidden_by_key = false + show() + elseif (key_pressed == hideKey) and (key_down) and (not is_hidden_by_key) and (not is_hidden_by_cutscene) then + is_hidden_by_key = true + hide() + end +end diff --git a/addons/indinope/README.md b/addons/indinope/README.md new file mode 100644 index 0000000000..16c82a4e4d --- /dev/null +++ b/addons/indinope/README.md @@ -0,0 +1,15 @@ +# IndiNope 1.0.4 +Hides visual effects from geomancy on players. + +Currently does not hide geomancy effect around luopans. + +**No commands.** Load it and it's on, unload and it's off. + +### Changelog: + +1.0.4 - More tweaks. +1.0.3 - A few tweaks. +1.0.1 - Fixed a bug where Indi-Nope would make Master stars disappear. Thanks Kenshi for finding out. +1.0.0 - Initial release. + +Thanks to Thorny, this addon is a port to windower of his Ashita code with the same functionality. diff --git a/addons/indinope/indinope.lua b/addons/indinope/indinope.lua new file mode 100644 index 0000000000..9e8a6678f5 --- /dev/null +++ b/addons/indinope/indinope.lua @@ -0,0 +1,48 @@ +--[[ +Copyright © Lili, 2020 +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 IndiNope 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 LILI 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 = 'IndiNope' +_addon.author = 'Lili' +_addon.version = '1.0.4' + +require('bit') + +offsets = { [0x00D] = 67, [0x037] = 89, } + +windower.register_event('incoming chunk', function(id, original, modified, injected, blocked) + if injected or blocked or not offsets[id] then return end + + offset = offsets[id] + flags = modified:byte(offsets[id]) + + -- if any of the bits 0 through 7 are set, a bubble is shown and we want to block it. + if bit.band(flags, 0x7F) ~= 0 then + packet = modified:sub(1, offset - 1) .. string.char(bit.band(flags, 0x80)) .. modified:sub(offset + 1) -- preserve bit 8 (Job Master stars) + return packet + end +end) diff --git a/addons/instaLS/instaLS.lua b/addons/instaLS/instaLS.lua index 26b7e8b784..ca729bec52 100644 --- a/addons/instaLS/instaLS.lua +++ b/addons/instaLS/instaLS.lua @@ -25,27 +25,27 @@ --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'instaLS' -_addon.version = 0.160309 +_addon.version = 0.220213 _addon.author = 'Byrth' -flag=false +linkshell_inventories_loaded = true chatmode = {} chatcolor = {} message = false require 'strings' - +bit = require 'bit' function translate_escape(str) return str:escape():gsub(string.char(0xFD)..".-"..string.char(0xFD),string.char(0xEF,0x27).."(.-)"..string.char(0xEF,0x25,0x25,0x28)) end windower.register_event('zone change',function() - flag=false + linkshell_inventories_loaded = false end) -windower.register_event('incoming chunk',function(id) - if id == 0x1D then - flag = true +windower.register_event('incoming chunk', function(id,org) + if not linkshell_inventories_loaded and id == 0x01D then + linkshell_inventories_loaded = bit.band(org:byte(0x09), 225) == 225 end end) @@ -68,7 +68,7 @@ windower.register_event('incoming text',function(org, mod, col) end) windower.register_event('outgoing text',function(org,mod,bool) - if bool or flag then return end + if bool or linkshell_inventories_loaded then return end if mod:sub(1,3) == '/l ' then chatmode[#chatmode+1] = 0x05 chatcolor[#chatcolor+1] = 6 @@ -90,4 +90,4 @@ windower.register_event('outgoing text',function(org,mod,bool) end return '/s '..message -end) \ No newline at end of file +end) diff --git a/addons/invtracker/README.md b/addons/invtracker/README.md new file mode 100644 index 0000000000..4c327fa2d7 --- /dev/null +++ b/addons/invtracker/README.md @@ -0,0 +1,15 @@ +# invtracker +This addon displays a grid detailing empty and filled inventory slots, similar to the FFXIV Inventory Grid HUD widget. + +![Imgur](https://i.imgur.com/PgiMxRZ.png) + +## How to edit the settings +1. Login to your character in FFXI +2. Edit the addon settings file: **_Windower4\addons\invtracker\data\settings.xml_** +3. Save the file +4. Press Insert in FFXI to access the windower console +5. Type ``` lua r invtracker ``` to reload the addon +6. Press Insert in FFXI again to close the windower console + +## Issues: +1. There is no way to get the inventory sort order, so all items in the grid will be ordered by status and item count. diff --git a/addons/invtracker/invtracker.lua b/addons/invtracker/invtracker.lua new file mode 100644 index 0000000000..df04f1f612 --- /dev/null +++ b/addons/invtracker/invtracker.lua @@ -0,0 +1,701 @@ +--[[ BSD License Disclaimer + Copyright © 2017, sylandro + 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 invtracker 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 sylandro 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 = 'invtracker' +_addon.author = 'sylandro' +_addon.version = '1.0.1' +_addon.language = 'English' + +config = require('config') +images = require('images') +texts = require('texts') +res = require('resources') +packets = require('packets') + +local CUTSCENE_STATUS_ID = 4 +local SCROLL_LOCK_KEY = 70 +local MAX_EQUIPMENT_SIZE = 16 +local DEFAULT_ITEM_STATUS = 0 +local EQUIPPED_ITEM_STATUS = 5 +local LINKSHELL_EQUIPPED_ITEM_STATUS = 19 +local BAZAAR_ITEM_STATUS = 25 +local EQUIPMENT_CHANGED_PACKET = 0x50 +local BAZAAR_PRICE_PACKET = 0x10A +local EQUIPSET_CHANGED_PACKET = 0x051 +local INVENTORY_FINISH_PACKET = 0x1D +local LOGIN_ZONE_PACKET = 0x0A +local TREASURE_FIND_ITEM_PACKET = 0xD2 +local TREASURE_LOT_ITEM_PACKET = 0xD3 +local EQUIP_LINKSHELL_PACKET = 0xC4 +local INVENTORY_SIZE_PACKET = 0x1C +local GIL_ITEM_ID = 65535 +local NO_ITEM_ID = 0 + +local hideKey = SCROLL_LOCK_KEY +local is_hidden_by_cutscene = false +local is_hidden_by_key = false + +defaults = {} +defaults.HideKey = SCROLL_LOCK_KEY +defaults.slotImage = {} +defaults.slotImage.sort = true +defaults.slotImage.spacing = 4 +defaults.slotImage.blockSpacing = 4 +defaults.slotImage.visible = true +defaults.slotImage.pos = {} +defaults.slotImage.pos.x = -365 +defaults.slotImage.pos.y = -50 +defaults.slotImage.equipment = {} +defaults.slotImage.equipment.visible = true +defaults.slotImage.equipment.maxColumns = 4 +defaults.slotImage.inventory = {} +defaults.slotImage.inventory.visible = true +defaults.slotImage.inventory.maxColumns = 5 +defaults.slotImage.mogSafe = {} +defaults.slotImage.mogSafe.visible = false +defaults.slotImage.mogSafe.maxColumns = 5 +defaults.slotImage.mogStorage = {} +defaults.slotImage.mogStorage.visible = false +defaults.slotImage.mogStorage.maxColumns = 4 +defaults.slotImage.mogLocker = {} +defaults.slotImage.mogLocker.visible = false +defaults.slotImage.mogLocker.maxColumns = 5 +defaults.slotImage.mogSatchel = {} +defaults.slotImage.mogSatchel.visible = true +defaults.slotImage.mogSatchel.maxColumns = 5 +defaults.slotImage.mogSack = {} +defaults.slotImage.mogSack.visible = true +defaults.slotImage.mogSack.maxColumns = 5 +defaults.slotImage.mogCase = {} +defaults.slotImage.mogCase.visible = true +defaults.slotImage.mogCase.maxColumns = 5 +defaults.slotImage.mogWardrobe = {} +defaults.slotImage.mogWardrobe.visible = false +defaults.slotImage.mogWardrobe.maxColumns = 5 +defaults.slotImage.tempInventory = {} +defaults.slotImage.tempInventory.maxColumns = 1 +defaults.slotImage.tempInventory.visible = true +defaults.slotImage.treasury = {} +defaults.slotImage.treasury.visible = true +defaults.slotImage.treasury.maxColumns = 1 +defaults.slotImage.status = {} +defaults.slotImage.status.default = {} +defaults.slotImage.status.default.color = {} +defaults.slotImage.status.default.color.alpha = 255 +defaults.slotImage.status.default.color.red = 0 +defaults.slotImage.status.default.color.green = 170 +defaults.slotImage.status.default.color.blue = 170 +defaults.slotImage.status.default.background = {} +defaults.slotImage.status.default.background.color = {} +defaults.slotImage.status.default.background.color.alpha = 200 +defaults.slotImage.status.default.background.color.red = 0 +defaults.slotImage.status.default.background.color.green = 60 +defaults.slotImage.status.default.background.color.blue = 60 +defaults.slotImage.status.fullStack = {} +defaults.slotImage.status.fullStack.color = {} +defaults.slotImage.status.fullStack.color.alpha = 255 +defaults.slotImage.status.fullStack.color.red = 245 +defaults.slotImage.status.fullStack.color.green = 40 +defaults.slotImage.status.fullStack.color.blue = 40 +defaults.slotImage.status.fullStack.background = {} +defaults.slotImage.status.fullStack.background.color = {} +defaults.slotImage.status.fullStack.background.color.alpha = 200 +defaults.slotImage.status.fullStack.background.color.red = 100 +defaults.slotImage.status.fullStack.background.color.green = 0 +defaults.slotImage.status.fullStack.background.color.blue = 0 +defaults.slotImage.status.equipment = {} +defaults.slotImage.status.equipment.color = {} +defaults.slotImage.status.equipment.color.alpha = 255 +defaults.slotImage.status.equipment.color.red = 253 +defaults.slotImage.status.equipment.color.green = 252 +defaults.slotImage.status.equipment.color.blue = 250 +defaults.slotImage.status.equipment.background = {} +defaults.slotImage.status.equipment.background.color = {} +defaults.slotImage.status.equipment.background.color.alpha = 200 +defaults.slotImage.status.equipment.background.color.red = 50 +defaults.slotImage.status.equipment.background.color.green = 50 +defaults.slotImage.status.equipment.background.color.blue = 50 +defaults.slotImage.status.equipped = {} +defaults.slotImage.status.equipped.color = {} +defaults.slotImage.status.equipped.color.alpha = 255 +defaults.slotImage.status.equipped.color.red = 150 +defaults.slotImage.status.equipped.color.green = 255 +defaults.slotImage.status.equipped.color.blue = 150 +defaults.slotImage.status.equipped.background = {} +defaults.slotImage.status.equipped.background.color = {} +defaults.slotImage.status.equipped.background.color.alpha = 200 +defaults.slotImage.status.equipped.background.color.red = 0 +defaults.slotImage.status.equipped.background.color.green = 100 +defaults.slotImage.status.equipped.background.color.blue = 0 +defaults.slotImage.status.linkshellEquipped = {} +defaults.slotImage.status.linkshellEquipped.color = {} +defaults.slotImage.status.linkshellEquipped.color.alpha = 255 +defaults.slotImage.status.linkshellEquipped.color.red = 150 +defaults.slotImage.status.linkshellEquipped.color.green = 255 +defaults.slotImage.status.linkshellEquipped.color.blue = 150 +defaults.slotImage.status.linkshellEquipped.background = {} +defaults.slotImage.status.linkshellEquipped.background.color = {} +defaults.slotImage.status.linkshellEquipped.background.color.alpha = 200 +defaults.slotImage.status.linkshellEquipped.background.color.red = 0 +defaults.slotImage.status.linkshellEquipped.background.color.green = 100 +defaults.slotImage.status.linkshellEquipped.background.color.blue = 0 +defaults.slotImage.status.bazaar = {} +defaults.slotImage.status.bazaar.color = {} +defaults.slotImage.status.bazaar.color.alpha = 255 +defaults.slotImage.status.bazaar.color.red = 225 +defaults.slotImage.status.bazaar.color.green = 160 +defaults.slotImage.status.bazaar.color.blue = 30 +defaults.slotImage.status.bazaar.background = {} +defaults.slotImage.status.bazaar.background.color = {} +defaults.slotImage.status.bazaar.background.color.alpha = 200 +defaults.slotImage.status.bazaar.background.color.red = 100 +defaults.slotImage.status.bazaar.background.color.green = 100 +defaults.slotImage.status.bazaar.background.color.blue = 0 +defaults.slotImage.status.tempItem = {} +defaults.slotImage.status.tempItem.color = {} +defaults.slotImage.status.tempItem.color.alpha = 255 +defaults.slotImage.status.tempItem.color.red = 255 +defaults.slotImage.status.tempItem.color.green = 130 +defaults.slotImage.status.tempItem.color.blue = 255 +defaults.slotImage.status.tempItem.background = {} +defaults.slotImage.status.tempItem.background.color = {} +defaults.slotImage.status.tempItem.background.color.alpha = 200 +defaults.slotImage.status.tempItem.background.color.red = 100 +defaults.slotImage.status.tempItem.background.color.green = 0 +defaults.slotImage.status.tempItem.background.color.blue = 100 +defaults.slotImage.status.empty = {} +defaults.slotImage.status.empty.color = {} +defaults.slotImage.status.empty.color.alpha = 150 +defaults.slotImage.status.empty.color.red = 0 +defaults.slotImage.status.empty.color.green = 0 +defaults.slotImage.status.empty.color.blue = 0 +defaults.slotImage.status.empty.background = {} +defaults.slotImage.status.empty.background.color = {} +defaults.slotImage.status.empty.background.color.alpha = 150 +defaults.slotImage.status.empty.background.color.red = 0 +defaults.slotImage.status.empty.background.color.green = 0 +defaults.slotImage.status.empty.background.color.blue = 0 + +local settings = config.load(defaults) +config.save(settings) + +settings.slotImage.box = {} +settings.slotImage.box.size = {} +settings.slotImage.box.size.height = 2 +settings.slotImage.box.size.width = 2 +settings.slotImage.box.texture = {} +settings.slotImage.box.texture.path = windower.addon_path..'slot.png' +settings.slotImage.box.texture.fit = false +settings.slotImage.box.repeatable = {} +settings.slotImage.box.repeatable.x = 1 +settings.slotImage.box.repeatable.y = 1 +settings.slotImage.background = {} +settings.slotImage.background.size = {} +settings.slotImage.background.size.height = 3 +settings.slotImage.background.size.width = 3 +settings.slotImage.background.texture = {} +settings.slotImage.background.texture.path = windower.addon_path..'slot.png' +settings.slotImage.background.texture.fit = false +settings.slotImage.background.repeatable = {} +settings.slotImage.background.repeatable.x = 1 +settings.slotImage.background.repeatable.y = 1 + +local windower_settings = windower.get_windower_settings() +local yRes = windower_settings.ui_y_res +local xRes = windower_settings.ui_x_res +local current_block = 0 +local current_slot = 1 +local current_row = 1 +local current_column = 1 +local last_column = 1 +local items = {} +local slot_images = {} +local inventory_loaded = false +local refresh_all = false +local refresh_items = false +local refresh_inventory = false +local refresh_linkshell = false +local last_treasure_count = 0 + +config.register(settings, function(settings) + hideKey = settings.HideKey + xBase = settings.slotImage.pos.x + yBase = settings.slotImage.pos.y +end) + +windower.register_event('load',function() + if windower.ffxi.get_info().logged_in then + initialize() + end +end) + +windower.register_event('login',function() + update_all() + hide() +end) + +windower.register_event('logout', function(...) + inventory_loaded = false + hide() + clear() +end) + +windower.register_event('add item', function(_bag,_index,id,...) + if (id ~= GIL_ITEM_ID and id ~= NO_ITEM_ID) then refresh_items = true end +end) + +windower.register_event('remove item', function(_bag,_index,id,...) + if (id ~= GIL_ITEM_ID and id ~= NO_ITEM_ID) then refresh_items = true end +end) + +windower.register_event('linkshell change', function(new,old) + if (refresh_linkshell) then + refresh_inventory = true + refresh_linkshell = false + end +end) + +windower.register_event('incoming chunk',function(id,org,_modi,_is_injected,_is_blocked) + if (id == LOGIN_ZONE_PACKET) then + inventory_loaded = false + elseif (id == INVENTORY_FINISH_PACKET) then + update() + elseif (id == TREASURE_FIND_ITEM_PACKET) then + update_treasure_only() + elseif (id == TREASURE_LOT_ITEM_PACKET) then + update_treasure_only() + elseif (id == INVENTORY_SIZE_PACKET) then + update_if_different_size(org) + end +end) + +windower.register_event('outgoing chunk',function(id,org,_modi,_is_injected,_is_blocked) + if (id == EQUIPMENT_CHANGED_PACKET or id == EQUIPSET_CHANGED_PACKET) then + refresh_all = true + elseif (id == BAZAAR_PRICE_PACKET) then + refresh_inventory = true + elseif (id == EQUIP_LINKSHELL_PACKET) then + refresh_linkshell = true + end +end) + +windower.register_event('status change', function(new_status_id) + local is_cutscene_playing = is_cutscene(new_status_id) + toggle_display_if_cutscene(is_cutscene_playing) +end) + +windower.register_event('keyboard', function(dik, down, _flags, _blocked) + toggle_display_if_hide_key_is_pressed(dik, down) +end) + +function update() + if (inventory_loaded) then + update_if_event() + else + initialize() + end +end + +function initialize() + inventory_loaded = true + update_all() + refresh_all = false + refresh_items = false + refresh_inventory = false + if not is_hidden_by_key and not is_hidden_by_cutscene then show() end +end + +function update_all() + setup_indexes() + update_equipment() + update_items() + update_treasure_bag(settings.slotImage.treasury,items.treasure) +end + +function update_if_event() + if (refresh_all) then + update_all() + refresh_all = false + refresh_items = false + refresh_inventory = false + elseif (refresh_items) then + update_items_only() + refresh_items = false + refresh_inventory = false + elseif (refresh_inventory) then + update_inventory_only() + refresh_inventory = false + end +end + +function update_inventory_only() + setup_indexes() + skip_block_if_enabled(settings.slotImage.equipment.visible, true,settings.slotImage.equipment.maxColumns,MAX_EQUIPMENT_SIZE) + update_bag(settings.slotImage.inventory,items.inventory,items.max_inventory,items.enabled_inventory) +end + +function update_items_only() + setup_indexes() + skip_block_if_enabled(settings.slotImage.equipment.visible, true,settings.slotImage.equipment.maxColumns,MAX_EQUIPMENT_SIZE) + update_items() +end + +function update_treasure_only() + local s = settings.slotImage + if (inventory_loaded and s.treasury.visible) then + setup_indexes() + skip_block_if_enabled(s.equipment.visible, true,s.equipment.maxColumns,MAX_EQUIPMENT_SIZE) + skip_block_if_enabled(s.inventory.visible,items.enabled_inventory,s.inventory.maxColumns,items.max_inventory) + skip_block_if_enabled(s.mogSafe.visible,items.safe.enabled,s.mogSafe.maxColumns,items.max_safe) + skip_block_if_enabled(s.mogSafe.visible,items.safe2.enabled,s.mogSafe.maxColumns,items.max_safe2) + skip_block_if_enabled(s.mogStorage.visible,items.storage.enabled,s.mogStorage.maxColumns,items.storage.max) + skip_block_if_enabled(s.mogLocker.visible,items.enabled_locker,s.mogLocker.maxColumns,items.max_locker) + skip_block_if_enabled(s.mogSatchel.visible,items.enabled_satchel,s.mogSatchel.maxColumns,items.max_satchel) + skip_block_if_enabled(s.mogSack.visible,items.enabled_sack,s.mogSack.maxColumns,items.max_sack) + skip_block_if_enabled(s.mogCase.visible,items.enabled_case,s.mogCase.maxColumns,items.max_case) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe,s.mogWardrobe.maxColumns,items.max_wardrobe) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe2,s.mogWardrobe.maxColumns,items.max_wardrobe2) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe3,s.mogWardrobe.maxColumns,items.max_wardrobe3) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe4,s.mogWardrobe.maxColumns,items.max_wardrobe4) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe5,s.mogWardrobe.maxColumns,items.max_wardrobe5) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe6,s.mogWardrobe.maxColumns,items.max_wardrobe6) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe7,s.mogWardrobe.maxColumns,items.max_wardrobe7) + skip_block_if_enabled(s.mogWardrobe.visible,items.enabled_wardrobe8,s.mogWardrobe.maxColumns,items.max_wardrobe8) + skip_block_if_enabled(s.tempInventory.visible,true,s.tempInventory.maxColumns,items.temporary.max) + update_treasure_bag(s.treasury,items.treasure) + end +end + +function update_if_different_size(packet_data) + if (inventory_loaded) then + local p = packets.parse('incoming',packet_data) + local s = settings.slotImage + if size_changed(s.inventory.visible,items.enabled_inventory,items.max_inventory,p['Inventory Size']) + or size_changed(s.mogSafe.visible,items.safe.enabled,items.max_safe,p['Safe Size']) + or size_changed(s.mogSafe.visible,items.safe2.enabled,items.max_safe2,p['Safe 2 Size']) + or size_changed(s.mogStorage.visible,items.storage.enabled,items.storage.max,p['Storage Size']) + or size_changed(s.mogLocker.visible,items.enabled_locker,items.max_locker,p['Locker Size']) + or size_changed(s.mogSatchel.visible,items.enabled_satchel,items.max_satchel,p['Satchel Size']) + or size_changed(s.mogSack.visible,items.enabled_sack,items.max_sack,p['Sack Size']) + or size_changed(s.mogCase.visible,items.enabled_case,items.max_case,p['Case Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe,items.max_wardrobe,p['Wardrobe Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe2,items.max_wardrobe2,p['Wardrobe 2 Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe3,items.max_wardrobe3,p['Wardrobe 3 Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe4,items.max_wardrobe4,p['Wardrobe 4 Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe5,items.max_wardrobe5,p['Wardrobe 5 Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe6,items.max_wardrobe6,p['Wardrobe 6 Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe7,items.max_wardrobe7,p['Wardrobe 7 Size']) + or size_changed(s.mogWardrobe.visible,items.enabled_wardrobe8,items.max_wardrobe8,p['Wardrobe 8 Size']) then + refresh_all = true + end + end +end + +function size_changed(visible, enabled, current_size, new_size) + return (visible and enabled and ((current_size+1) ~= new_size)) +end + +function setup_indexes() + current_block = 0 + last_column = 1 + items = windower.ffxi.get_items() +end + +function update_equipment() + if (settings.slotImage.equipment.visible) then + initialize_block() + print_equipment(items.equipment.back) + print_equipment(items.equipment.waist) + print_equipment(items.equipment.legs) + print_equipment(items.equipment.feet) + print_equipment(items.equipment.body) + print_equipment(items.equipment.hands) + print_equipment(items.equipment.left_ring) + print_equipment(items.equipment.right_ring) + print_equipment(items.equipment.head) + print_equipment(items.equipment.neck) + print_equipment(items.equipment.left_ear) + print_equipment(items.equipment.right_ear) + print_equipment(items.equipment.main) + print_equipment(items.equipment.sub) + print_equipment(items.equipment.range) + print_equipment(items.equipment.ammo) + end +end + +function update_items() + local s = settings.slotImage + update_bag(s.inventory,items.inventory,items.max_inventory,items.enabled_inventory) + update_bag(s.mogSafe,items.safe,items.max_safe,items.safe.enabled) + update_bag(s.mogSafe,items.safe2,items.max_safe2,items.safe2.enabled) + update_bag(s.mogStorage,items.storage,items.storage.max,items.storage.enabled) + update_bag(s.mogLocker,items.locker,items.max_locker,items.enabled_locker) + update_bag(s.mogSatchel,items.satchel,items.max_satchel,items.enabled_satchel) + update_bag(s.mogSack,items.sack,items.max_sack,items.enabled_sack) + update_bag(s.mogCase,items.case,items.max_case,items.enabled_case) + update_bag(s.mogWardrobe,items.wardrobe,items.max_wardrobe,items.enabled_wardrobe) + update_bag(s.mogWardrobe,items.wardrobe2,items.max_wardrobe2,items.enabled_wardrobe2) + update_bag(s.mogWardrobe,items.wardrobe3,items.max_wardrobe3,items.enabled_wardrobe3) + update_bag(s.mogWardrobe,items.wardrobe4,items.max_wardrobe4,items.enabled_wardrobe4) + update_bag(s.mogWardrobe,items.wardrobe5,items.max_wardrobe5,items.enabled_wardrobe5) + update_bag(s.mogWardrobe,items.wardrobe6,items.max_wardrobe6,items.enabled_wardrobe6) + update_bag(s.mogWardrobe,items.wardrobe7,items.max_wardrobe7,items.enabled_wardrobe7) + update_bag(s.mogWardrobe,items.wardrobe8,items.max_wardrobe8,items.enabled_wardrobe8) + update_temp_bag(s.tempInventory,items.temporary) +end + +function update_treasure_bag(config,bag) + if (config.visible) then + local treasure_count = count_treasure() + if (treasure_count ~= last_treasure_count) then + initialize_block() + for k, _v in ipairs(slot_images[current_block]) do + slot_images[current_block][k].background:alpha(0) + slot_images[current_block][k].box:alpha(0) + end + for _k, _v in pairs(bag) do + print_slot(settings.slotImage.status.tempItem,config.maxColumns,80) + end + last_treasure_count = treasure_count + end + end +end + +function update_bag(config, bag, max, enabled) + if (config.visible and enabled) then + initialize_block() + print_bag(config, bag, max) + end +end + +function update_temp_bag(config, bag) + if (config.visible) then + initialize_block() + local occupied_slots = 0 + for key=1,bag.max,1 do + if bag[key].count > 0 then + occupied_slots = occupied_slots + 1 + end + end + for k, _v in ipairs(slot_images[current_block]) do + slot_images[current_block][k].background:alpha(0) + slot_images[current_block][k].box:alpha(0) + end + for _k=1,occupied_slots,1 do + print_slot(settings.slotImage.status.tempItem,config.maxColumns,bag.max) + end + current_slot = bag.max + current_column = config.maxColumns + update_indexes(config.maxColumns,bag.max) + end +end + +function count_treasure() + local count = 0 + for _k, _v in pairs(items.treasure) do count = count + 1 end + return count +end + +function skip_block_if_enabled(visible,enabled,max_columns,last_index) + if visible and enabled then + initialize_block() + current_slot = last_index + current_column = max_columns + update_indexes(max_columns,last_index) + end +end + +function initialize_block() + current_block = current_block + 1 + if slot_images[current_block] == nil then + slot_images[current_block] = {} + end + current_slot = 1 + current_row = 1 + current_column = 1 +end + +function print_equipment(status) + if (status > 0) then + print_slot(settings.slotImage.status.equipment,settings.slotImage.equipment.maxColumns,MAX_EQUIPMENT_SIZE) + else + print_slot(settings.slotImage.status.empty,settings.slotImage.equipment.maxColumns,MAX_EQUIPMENT_SIZE) + end +end + +function print_bag(config, bag, max) + sort_table(bag) + for key=1,max,1 do + if (bag[key].count > 0) then + print_item(config,bag[key],max) + else + print_slot(settings.slotImage.status.empty,config.maxColumns,max) + end + end +end + +function sort_table(bag) + if (settings.slotImage.sort) then + table.sort(bag, function(a,b) + if (a.status ~= b.status) then + return a.status > b.status + end + if (a.count > 0 and b.count > 0) then + full_stack_a = res.items[a.id].stack - a.count + full_stack_b = res.items[b.id].stack - b.count + if (full_stack_a ~= full_stack_b) then + return full_stack_a < full_stack_b + end + end + return a.count > b.count + end) + end +end + +function print_item(config, item, last_index) + local s = settings.slotImage + if (item.status == DEFAULT_ITEM_STATUS) then + if (item.count == res.items[item.id].stack) then + print_slot(s.status.fullStack,config.maxColumns,last_index) + else + print_slot(s.status.default,config.maxColumns,last_index) + end + elseif (item.status == EQUIPPED_ITEM_STATUS) then + print_slot(s.status.equipped,config.maxColumns,last_index) + elseif (item.status == LINKSHELL_EQUIPPED_ITEM_STATUS) then + print_slot(s.status.linkshellEquipped,config.maxColumns,last_index) + elseif (item.status == BAZAAR_ITEM_STATUS) then + print_slot(s.status.bazaar,config.maxColumns,last_index) + else + print_slot(s.status.empty,config.maxColumns,last_index) + end +end + +function print_slot(status, max_columns, last_index) + update_coordinates() + if slot_images[current_block][current_slot] == nil then + slot_images[current_block][current_slot] = {} + end + print_slot_background(status.background.color) + print_slot_box(status.color) + update_indexes(max_columns,last_index) +end + +function print_slot_background(slot_color, max_columns, last_index) + local slot_image = slot_images[current_block][current_slot] + local s = settings.slotImage + if slot_image.background == nil then + slot_image.background = images.new(s.background) + slot_image.background:pos(current_x,current_y) + end + slot_image.background:width(s.background.size.width) + slot_image.background:height(s.background.size.height) + slot_image.background:alpha(slot_color.alpha) + slot_image.background:color(slot_color.red,slot_color.green,slot_color.blue) +end + +function print_slot_box(slot_color, max_columns, last_index) + local slot_image = slot_images[current_block][current_slot] + local s = settings.slotImage + if slot_image.box == nil then + slot_image.box = images.new(s.box) + slot_image.box:pos(current_x,current_y) + end + slot_image.box:width(s.box.size.width) + slot_image.box:height(s.box.size.height) + slot_image.box:color(slot_color.red,slot_color.green,slot_color.blue) + slot_image.box:alpha(slot_color.alpha) +end + +function update_coordinates() + local s = settings.slotImage + current_x = xRes + xBase + + ((current_column - 1) * s.spacing) + + ((current_block - 1) * s.blockSpacing) + + ((last_column - 1) * s.spacing) + current_y = yRes + yBase - ((current_row - 1) * s.spacing) +end + +function update_indexes(max_columns, last_index) + if (current_slot % max_columns) == 0 then + if (current_slot == last_index) then + last_column = last_column + current_column + end + current_column = 1 + current_row = current_row + 1 + else + current_column = current_column + 1 + end + current_slot = current_slot + 1 +end + +function show() + for key,block in ipairs(slot_images) do + for key,slot in ipairs(block) do + slot.background:show() + slot.box:show() + end + end +end + +function hide() + for key,block in ipairs(slot_images) do + for key,slot in ipairs(block) do + slot.background:hide() + slot.box:hide() + end + end +end + +function clear() + slot_images = {} +end + +function is_cutscene(status_id) + return status_id == CUTSCENE_STATUS_ID +end + +function toggle_display_if_cutscene(is_cutscene_playing) + if (is_cutscene_playing) and (not is_hidden_by_key) then + is_hidden_by_cutscene = true + hide() + elseif (not is_cutscene_playing) and (not is_hidden_by_key) then + is_hidden_by_cutscene = false + show() + end +end + +function toggle_display_if_hide_key_is_pressed(key_pressed, key_down) + if (key_pressed == hideKey) and (key_down) and (is_hidden_by_key) and (not is_hidden_by_cutscene) then + is_hidden_by_key = false + show() + elseif (key_pressed == hideKey) and (key_down) and (not is_hidden_by_key) and (not is_hidden_by_cutscene) then + is_hidden_by_key = true + hide() + end +end diff --git a/addons/invtracker/slot.png b/addons/invtracker/slot.png new file mode 100644 index 0000000000..f2d13ec092 Binary files /dev/null and b/addons/invtracker/slot.png differ diff --git a/addons/itemizer/itemizer.lua b/addons/itemizer/itemizer.lua index 5074ee9f6e..31015e34ea 100644 --- a/addons/itemizer/itemizer.lua +++ b/addons/itemizer/itemizer.lua @@ -328,7 +328,7 @@ windower.register_event('outgoing text', function() if bag == 'inventory' then inventory_items:add(item.id) - elseif S{'wardrobe','wardrobe2','wardrobe3','wardrobe4'}:contains(bag) then + elseif S{'wardrobe','wardrobe2','wardrobe3','wardrobe4','wardrobe5','wardrobe6','wardrobe7','wardrobe8'}:contains(bag) then wardrobe_items:add(item.id) end end diff --git a/addons/latentchecker/latentchecker.lua b/addons/latentchecker/latentchecker.lua index 5b339ce761..354ad77f93 100644 --- a/addons/latentchecker/latentchecker.lua +++ b/addons/latentchecker/latentchecker.lua @@ -68,7 +68,7 @@ windower.register_event('addon command', function(command, ...) "werebuster","mage's staff","vorpal sword","swordbreaker","brave blade","death sickle","double axe","dancing dagger","killer bow","windslicer", "sasuke katana","radiant lance","scepter staff","wightslayer","quicksilver","inferno claws","main gauche","elder staff","destroyers","senjuinrikio", "heart snatcher","subduer","dissector","expunger","morgenstern","gravedigger","rampager","coffinmaker","gonzo-shizunori","retributor","michishiba","thyrsusstab", - "trial wand","trial blade"} + "trial wand","trial blade","chaosbringer"} if command == 'run' then windower.add_to_chat(121,'latentchecker: Starting...') windower.ffxi.set_equip(0, 0, 0) -- Remove main/sub weapons diff --git a/addons/libs/actions.lua b/addons/libs/actions.lua index 0096e604a5..4ff11b6df4 100644 --- a/addons/libs/actions.lua +++ b/addons/libs/actions.lua @@ -5,7 +5,7 @@ The primary functionality provided here are iterators which allow for easy traversal of the sub-tables within the packet. Example: ======================================================================================= -require 'actions' +require('actions') function event_action(act) action = Action(act) -- constructor @@ -27,9 +27,13 @@ end ]] _libs = _libs or {} + +require('tables') + +local table = _libs.tables +local res = require('resources') + _libs.actions = true -_libs.tables = _libs.tables or require 'tables' -local res = require 'resources' local category_strings = { 'melee', @@ -52,7 +56,6 @@ local category_strings = { -- ActionPacket operations ActionPacket = {} - local actionpacket = {} -- Constructor for Actions. -- Usage: actionpacket = ActionPacket(raw_action) @@ -114,9 +117,10 @@ local function act_to_string(original,act) offset = offset + 36 for n = 1,act.targets[i].action_count do react = assemble_bit_packed(react,act.targets[i].actions[n].reaction,offset,offset+5) - react = assemble_bit_packed(react,act.targets[i].actions[n].animation,offset+5,offset+16) - react = assemble_bit_packed(react,act.targets[i].actions[n].effect,offset+16,offset+21) - react = assemble_bit_packed(react,act.targets[i].actions[n].stagger,offset+21,offset+27) + react = assemble_bit_packed(react,act.targets[i].actions[n].animation,offset+5,offset+17) + react = assemble_bit_packed(react,act.targets[i].actions[n].effect,offset+17,offset+21) + react = assemble_bit_packed(react,act.targets[i].actions[n].stagger,offset+21,offset+24) + react = assemble_bit_packed(react,act.targets[i].actions[n].knockback,offset+24,offset+27) react = assemble_bit_packed(react,act.targets[i].actions[n].param,offset+27,offset+44) react = assemble_bit_packed(react,act.targets[i].actions[n].message,offset+44,offset+54) react = assemble_bit_packed(react,act.targets[i].actions[n].unknown,offset+54,offset+85) @@ -151,7 +155,6 @@ local function act_to_string(original,act) return react end - -- Opens a listener event for the action packet at the incoming chunk level before modifications. -- Passes in the documented act structures for the original and modified packets. -- If a table is returned, the library will treat it as a modified act table and recompose the packet string from it. @@ -197,9 +200,9 @@ end function actionpacket:get_spell() local info = self:get_targets()():get_actions()():get_basic_info() - if rawget(info,'resource') and rawget(info,'spell_id') and rawget(rawget(res,rawget(info,'resource')),rawget(info,'spell_id')) then + if rawget(info,'resource') and rawget(info,'spell_id') and rawget(res[rawget(info,'resource')],rawget(info,'spell_id')) then local copied_line = {} - for i,v in pairs(rawget(rawget(res,rawget(info,'resource')),rawget(info,'spell_id'))) do + for i,v in pairs(rawget(res[rawget(info,'resource')],rawget(info,'spell_id'))) do rawset(copied_line,i,v) end setmetatable(copied_line,getmetatable(res[rawget(info,'resource')][rawget(info,'spell_id')])) @@ -220,7 +223,7 @@ end --Returns the id of the actor function actionpacket:get_id() - return self.raw['actor_id'] + return self.raw['actor_id'] end -- Returns an iterator for this actionpacket's targets @@ -383,13 +386,13 @@ expandable[{1, 2, 67, 77, 110,157, 292,293,294,295,296,297, 298,299,300,301,302,317, 352,353,379,419,522,576, - 577,648,650,732}] = {subject="target", verb="loses", objects={"HP"} } + 577,648,650,732,767,768}] = {subject="target", verb="loses", objects={"HP"} } expandable[{122,167,383}] = {subject="actor", verb="gains", objects={"HP"} } expandable[{7, 24, 102,103,238,263, 306,318,357,367,373,382,384, 385,386,387,388,389,390,391, 392,393,394,395,396,397,398, - 539,587,606,651}] = {subject="target", verb="gains", objects={"HP"} } + 539,587,606,651,769,770}] = {subject="target", verb="gains", objects={"HP"} } expandable[{25, 224,276,358,451,588}] = {subject="target", verb="gains", objects={"MP"} } expandable[{161,187,227,274,281}] = {subject="actor", verb="steals", objects={"HP"} } expandable[{165,226,454,652}] = {subject="actor", verb="steals", objects={"TP"} } @@ -480,7 +483,6 @@ function action:get_message_id() return message_id or 0 end - ---------------------------------------- Additional Effects ---------------------------------------- local add_effect_animation_strings = {} @@ -517,12 +519,16 @@ add_effect_animation_strings['weaponskill_finish'] = { [12] = 'scission', [13] = 'detonation', [14] = 'impaction', + [15] = 'radiance', + [16] = 'umbra', } add_effect_animation_strings['spell_finish'] = add_effect_animation_strings['weaponskill_finish'] +add_effect_animation_strings['mob_tp_finish'] = add_effect_animation_strings['weaponskill_finish'] +add_effect_animation_strings['avatar_tp_finish'] = add_effect_animation_strings['weaponskill_finish'] + +local add_effect_effect_strings = {} -local add_effect_effect_strings = { - } function action:get_add_effect() if not rawget(rawget(self,'raw'),'has_add_effect') then return false end local animation = self:get_add_effect_animation_string() @@ -590,11 +596,8 @@ function action:get_additional_effect_conclusion() return msg_id_to_conclusion(rawget(rawget(self,'raw'),'spike_effect_message')) end - - - --[[ -Copyright (c) 2013, Suji +Copyright © 2013, Suji All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/addons/libs/chat.lua b/addons/libs/chat.lua index fea9f81fa6..89b10cdf40 100644 --- a/addons/libs/chat.lua +++ b/addons/libs/chat.lua @@ -2,21 +2,23 @@ A collection of FFXI-specific chat/text functions and character/control database. ]] +_libs = _libs or {} + +require('tables') +require('sets') +require('strings') + +local table, set, string = _libs.tables, _libs.sets, _libs.strings + local chat = {} -_libs = _libs or {} -_libs.chat = chat -_libs.tables = _libs.tables or require('tables') -_libs.sets = _libs.sets or require('sets') -_libs.strings = _libs.strings or require('strings') -_libs.chat.colors = _libs.chat.colors or require('chat.colors') -_libs.chat.controls = _libs.chat.controls or require('chat.controls') +chat.colors = require('chat/colors') +chat.controls = require('chat/controls') --- Local functions -local make_color +_libs.chat = chat -- Returns a color from a given input. -function make_color(col) +local function make_color(col) if type(col) == 'number' then if col <= 0x000 or col == 0x100 or col == 0x101 or col > 0x1FF then warning('Invalid color number '..col..'. Only numbers between 1 and 511 permitted, except 256 and 257.') @@ -103,7 +105,7 @@ chat.text_color_reset = '\\cr' return chat --[[ -Copyright (c) 2013, Windower +Copyright © 2013, Windower All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/addons/libs/config.lua b/addons/libs/config.lua index 1e147dd17c..7829c7f199 100644 --- a/addons/libs/config.lua +++ b/addons/libs/config.lua @@ -2,16 +2,21 @@ Functions that facilitate loading, parsing, manipulating and storing of config files. ]] +_libs = _libs or {} + +require('tables') +require('sets') +require('lists') +require('strings') + +local table, set, list, string = _libs.tables, _libs.sets, _libs.lists, _libs.strings +local xml = require('xml') +local files = require('files') +local json = require('json') + local config = {} -_libs = _libs or {} _libs.config = config -_libs.tables = _libs.tables or require('tables') -_libs.sets = _libs.sets or require('sets') -_libs.lists = _libs.lists or require('lists') -_libs.strings = _libs.strings or require('strings') -_libs.xml = _libs.xml or require('xml') -_libs.files = _libs.files or require('files') local error = error or print+{'Error:'} local warning = warning or print+{'Warning:'} @@ -47,7 +52,7 @@ function config.load(filepath, defaults) -- Settings member variables, in separate struct local meta = {} - meta.file = _libs.files.new(filepath, true) + meta.file = files.new(filepath, true) meta.original = T{global = table.copy(settings)} meta.chars = S{} meta.comments = {} @@ -85,10 +90,10 @@ function parse(settings) local meta = settings_map[settings] if meta.file.path:endswith('.json') then - parsed = _libs.json.read(meta.file) + parsed = json.read(meta.file) elseif meta.file.path:endswith('.xml') then - parsed, err = _libs.xml.read(meta.file) + parsed, err = xml.read(meta.file) if not parsed then error(err or 'XML error: Unknown error.') @@ -110,7 +115,7 @@ function parse(settings) local full_parsed = parsed.global local player = windower.ffxi.get_player() if player then - full_parsed = full_parsed:update(parsed[player.name:lower()], true) + full_parsed = table.update(full_parsed, rawget(parsed, player.name:lower()), true) end return settings:update(full_parsed, true) @@ -128,7 +133,7 @@ function parse(settings) local player = windower.ffxi.get_player() if player then - full_parsed = full_parsed:update(parsed[player.name:lower()], true) + full_parsed = table.update(full_parsed, rawget(parsed, player.name:lower()), true) end return merge(settings, full_parsed) @@ -337,7 +342,7 @@ function config.save(t, char) end meta.original[char]:update(t) - + if char == 'global' then meta.original = T{global = meta.original.global} meta.chars = S{} diff --git a/addons/libs/dialog.lua b/addons/libs/dialog.lua new file mode 100644 index 0000000000..02423389cb --- /dev/null +++ b/addons/libs/dialog.lua @@ -0,0 +1,295 @@ +-- This library was written to help find the ID of a known +-- action message corresponding to an entry in the dialog tables. +-- While the IDs can be collected in-game, they occasionally +-- change and would otherwise need to be manually updated. +-- It can also be used to find and decode an entry given the ID. + +-- Common parameters: +-- +-- dat: Either the entire content of the zone dialog DAT file or +-- a file descriptor. +-- i.e. either local dat = io.open('path/to/dialog/DAT', 'rb') +-- or dat = dat:read('*a') +-- The functions are expected to be faster when passed a string, +-- but will use less memory when receiving a file descriptor. +-- +-- entry: The string you are looking for. Whether or not the string +-- is expected to be encoded should be indicated in the parameter's +-- name. If you do not know the entire string, use dev.find_substring +-- and serialize the result. + +local xor = require('bit').bxor +local floor = require('math').floor +local string = require('string') +local find = string.find +local sub = string.sub +local gsub = string.gsub +local format = string.format +local char = string.char +local byte = string.byte +require('pack') +local unpack = string.unpack +local pack = string.pack + +local function decode(int) + return xor(int, 0x80808080) +end +local encode = decode + +local function binary_search(pos, dat, n) + local l, r, m = 1, n + while l < r do + m = floor((l + r) / 2) + if decode(unpack(dat, ' last_offset then + break + elseif offset == last_offset then + next_pos = #dat + 1 + else + next_pos = decode(unpack(dat, ' 299 then + -- The English dialog files are currently 300 ids + -- ahead of the Japanese dialog files. If a zone with + -- id 300 or greater is added, SE will have to move to + -- a new range of ids which someone will need to locate. + print('Dialog library: zone id out of range.') + return + elseif zone_id > 255 then + dat_id = zone_id + 85035 + else + dat_id = zone_id + 6120 + end + if language == 'english' then + dat_id = dat_id + 300 + elseif language ~= 'japanese' then + print( + _addon and _addon.name or '???', + 'Dialog library: open_dat_by_zone_id expected ' + .. '"english" or "japanese". (Got: ' .. language .. ')' + ) + return + end + + local dat_path = windower.ffxi_path + if sub(dat_path, -1, -1) ~= '\\' then + dat_path = dat_path .. '\\' + end + local path + local vtable = dat_path .. 'VTABLE.DAT' + local ftable = dat_path .. 'FTABLE.DAT' + local n = 1 + local rom = dat_path .. 'ROM/' + repeat + local v = io.open(vtable, 'rb') + v:seek('set', dat_id) + if byte(v:read(1)) > 0 then + local f = io.open(ftable, 'rb') + local dat = f:read('*a') + f:close() + + local offset = 2*dat_id+1 + local packed_16bit = byte(dat, offset + 1) * 256 + byte(dat, offset) + local dir = floor(packed_16bit / 128) + local file = packed_16bit - dir * 128 + + path = rom .. tostring(dir) .. '/' .. tostring(file) .. '.DAT' + end + v:close() + n = n + 1 + local d = tostring(n) + rom = dat_path .. 'ROM' .. d .. '/' + vtable = rom .. 'VTABLE' .. d .. '.DAT' + ftable = rom .. 'FTABLE' .. d .. '.DAT' + until path or not windower.dir_exists(rom) + + if path then + return io.open(path, 'rb') + end +end + +dialog.dev = {} + +-- Returns the hex offset of the dialog entry with the given ID. +-- May be useful if you are viewing the file in a hex editor. +function dialog.dev.get_offset(dat, id) + local offset + if type(dat) == 'string' then + offset = unpack(dat, '= math.ceil((start+1)/8) do -- Grabs the most significant byte first and works down towards the least significant. - local cur_val = dat_string:byte(c_count) + local cur_val = dat_string:byte(c_count) or 0 local scal = 1 if c_count == math.ceil(stop/8) then -- Take the least significant bits of the most significant byte @@ -1521,6 +1670,8 @@ function tools.aug.unpack_augment(sys,short) return short:byte(1), short:byte(2) elseif sys == 3 then return short:byte(1) + short:byte(2)%8*256, math.floor(short:byte(2)%128/8) + elseif sys == 4 then + return short:byte(1), short:byte(2) end end @@ -1587,8 +1738,8 @@ function decode.Augmented(str) if flag_2%16/8 >= 1 then -- Crafting shields rettab.objective = str:byte(6) - local units = {30,40,50,100} - rettab.stage = math.min(1,math.max(4,str:byte(0x9))) + local units = {30,50,100,100} + rettab.stage = math.max(1,math.min(4,str:byte(0x9))) rettab.completion = str:unpack('H',7)/units[rettab.stage] elseif flag_2%64/32 >=1 then rettab.augment_system = 2 @@ -1598,6 +1749,11 @@ function decode.Augmented(str) rettab.rank = math.floor(str:byte(3)%128/4) rettab.RP = math.max(points_map[rettab.rank] or 0 - str:byte(6)*256 - str:byte(5),0) rettab.augments = tools.aug.augments_to_table(rettab.augment_system,str:sub(7,12)) + elseif flag_2 == 131 then + rettab.augment_system = 4 + local path_map = {[0] = 'A',[1] = 'B', [2] = 'C', [3] = 'D'} + rettab.path = path_map[math.floor(str:byte(5)%4)] + rettab.augments = {'Path: ' ..rettab.path} elseif flag_2/128 >= 1 then -- Evolith rettab.augment_system = 3 local slot_type_map = {[0] = 'None', [1] = 'Filled Upside-down Triangle', [2] = 'Filled Diamond', [3] = 'Filled Star', [4] = 'Empty Triangle', [5] = 'Empty Square', [6] = 'Empty Circle', [7] = 'Empty Upside-down Triangle', [8] = 'Empty Diamond', [9] = 'Empty Star', [10] = 'Filled Triangle', [11] = 'Filled Square', [12] = 'Filled Circle', [13] = 'Empty Circle', [14] = 'Fire', [15] = 'Ice'} @@ -1645,6 +1801,7 @@ function decode.Equipment(str) local flag_1_mapping = { [1] = decode.Enchanted, [2] = decode.Augmented, + [3] = decode.Augmented, } if flag_1_mapping[flag_1] then rettab = flag_1_mapping[flag_1](str:sub(1,12)) @@ -1660,18 +1817,21 @@ end function decode.Linkshell(str) local status_map = {[0]='Unopened',[1]='Linkshell',[2]='Pearlsack',[3]='Linkpearl',[4]='Broken'} - local name_end = string.find(str,string.char(0),10) + local name_end = #str + while str:byte(name_end) == 0 and name_end > 10 do + name_end = name_end - 1 + end local name_map = {[0]="'",[1]="a",[2]='b',[3]='c',[4]='d',[5]='e',[6]='f',[7]='g',[8]='h',[9]='i',[10]='j', [11]='k',[12]='l',[13]='m',[14]='n',[15]='o',[16]='p',[17]='q',[18]='r',[19]='s',[20]='t',[21]='u',[22]='v',[23]='w', - [24]='x',[25]='yx',[26]='z',[27]='A',[28]='B',[29]='C',[30]='D',[31]='E',[32]='F',[33]='G',[34]='H',[35]='I',[36]='J', + [24]='x',[25]='y',[26]='z',[27]='A',[28]='B',[29]='C',[30]='D',[31]='E',[32]='F',[33]='G',[34]='H',[35]='I',[36]='J', [37]='K',[38]='L',[39]='M',[40]='N',[41]='O',[42]='P',[43]='Q',[44]='R',[45]='S',[46]='T',[47]='U',[48]='V',[49]='W', [50]='X',[51]='Y',[52]='Z' } local rettab = {type = 'Linkshell', linkshell_id = str:unpack('I'), - r = 17*str:byte(7)%16, + r = 17*(str:byte(7)%16), g = 17*math.floor(str:byte(7)/16), - b = 17*str:byte(8)%16, + b = 17*(str:byte(8)%16), status_id = str:byte(9), status = status_map[str:byte(9)]} @@ -1969,7 +2129,9 @@ id_mapping = { -- ACTUAL EXTDATA LIB FUNCTIONS local extdata = {} - + +_libs.extdata = extdata + function extdata.decode(tab) if not tab then error('extdata.decode was passed a nil value') end if not tab.id or not tonumber(tab.id) then diff --git a/addons/libs/files.lua b/addons/libs/files.lua index 7e67cf03ca..52a99092d7 100644 --- a/addons/libs/files.lua +++ b/addons/libs/files.lua @@ -2,11 +2,16 @@ File handler. ]] +_libs = _libs or {} + +require('strings') +require('tables') + +local string, table = _libs.strings, _libs.tables + local files = {} -_libs = _libs or {} _libs.files = files -_libs.strings = _libs.strings or require('strings') -- Create a new file object. function files.new(path, create) diff --git a/addons/libs/functions.lua b/addons/libs/functions.lua index 5f3e5be276..5dc15f3004 100644 --- a/addons/libs/functions.lua +++ b/addons/libs/functions.lua @@ -3,11 +3,16 @@ ]] _libs = _libs or {} -_libs.functions = true + +local string, math, table, coroutine = require('string'), require('math'), require('table'), require('coroutine') functions = {} boolean = {} +_libs.functions = functions + +local functions, boolean = functions, boolean + -- The empty function. functions.empty = function() end @@ -67,7 +72,7 @@ end function functions.prepare(fn, ...) local args = {...} return function() - fn(unpack(args)) + return fn(unpack(args)) end end @@ -140,18 +145,18 @@ function functions.it(fn, ...) end end --- Schedules the current function to run delayed by the provided time in seconds +-- Schedules the current function to run delayed by the provided time in seconds and returns the coroutine function functions.schedule(fn, time, ...) - coroutine.schedule(fn:prepare(...), time) + return coroutine.schedule(fn:prepare(...), time) end -- Returns a function that, when called, will execute the underlying function delayed by the provided number of seconds function functions.delay(fn, time, ...) - local args = {...} + local args = {...} - return function() - fn:schedule(time, unpack(args)) - end + return function() + fn:schedule(time, unpack(args)) + end end -- Returns a wrapper table representing the provided function with additional functions: @@ -223,6 +228,7 @@ end -- * fn+{...} partially applies a function to arguments. -- * fn-{...} partially applies a function to arguments from the end. -- * fn1..fn2 pipes input from fn2 to fn1. + debug.setmetatable(functions.empty, { __index = index, __add = add, @@ -269,7 +275,7 @@ end -- Returns true if two values are the same. function boolean._is(val1, val2) - return val1 ~= val2 + return val1 == val2 end --[[ @@ -489,7 +495,7 @@ function string.map(str, fn) end --[[ -Copyright 2013-2015, Windower +Copyright © 2013-2015, Windower All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/addons/libs/images.lua b/addons/libs/images.lua index ec4738ea0d..b540210254 100644 --- a/addons/libs/images.lua +++ b/addons/libs/images.lua @@ -2,6 +2,9 @@ A library to facilitate image primitive creation and manipulation. ]] +local table = require('table') +local math = require('math') + local images = {} local meta = {} @@ -99,8 +102,8 @@ local apply_settings = function(_, t, settings) images.alpha(t, settings.color.alpha) images.color(t, settings.color.red, settings.color.green, settings.color.blue) images.size(t, settings.size.width, settings.size.height) - images.path(t, settings.texture.path) images.fit(t, settings.texture.fit) + images.path(t, settings.texture.path) images.repeat_xy(t, settings.repeatable.x, settings.repeatable.y) images.draggable(t, settings.draggable) @@ -216,7 +219,7 @@ end function images.pos(t, x, y) local m = meta[t] - if not x then + if x == nil then return m.settings.pos.x, m.settings.pos.y end @@ -226,7 +229,7 @@ function images.pos(t, x, y) end function images.pos_x(t, x) - if not x then + if x == nil then return meta[t].settings.pos.x end @@ -234,7 +237,7 @@ function images.pos_x(t, x) end function images.pos_y(t, y) - if not y then + if y == nil then return meta[t].settings.pos.y end @@ -243,7 +246,7 @@ end function images.size(t, width, height) local m = meta[t] - if not width then + if width == nil then return m.settings.size.width, m.settings.size.height end @@ -253,7 +256,7 @@ function images.size(t, width, height) end function images.width(t, width) - if not width then + if width == nil then return meta[t].settings.size.width end @@ -261,7 +264,7 @@ function images.width(t, width) end function images.height(t, height) - if not height then + if height == nil then return meta[t].settings.size.height end @@ -269,7 +272,7 @@ function images.height(t, height) end function images.path(t, path) - if not path then + if path == nil then return meta[t].settings.texture.path end @@ -278,7 +281,7 @@ function images.path(t, path) end function images.fit(t, fit) - if not fit then + if fit == nil then return meta[t].settings.texture.fit end @@ -288,7 +291,7 @@ end function images.repeat_xy(t, x, y) local m = meta[t] - if not x then + if x == nil then return m.settings.repeatable.x, m.settings.repeatable.y end @@ -298,7 +301,7 @@ function images.repeat_xy(t, x, y) end function images.draggable(t, drag) - if not drag then + if drag == nil then return meta[t].settings.draggable end @@ -307,7 +310,7 @@ end function images.color(t, red, green, blue) local m = meta[t] - if not red then + if red == nil then return m.settings.color.red, m.settings.color.green, m.settings.color.blue end @@ -319,7 +322,7 @@ end function images.alpha(t, alpha) local m = meta[t] - if not alpha then + if alpha == nil then return m.settings.color.alpha end @@ -330,7 +333,7 @@ end -- Sets/returns image transparency. Based on percentage values, with 1 being fully transparent, while 0 is fully opaque. function images.transparency(t, alpha) local m = meta[t] - if not alpha then + if alpha == nil then return 1 - m.settings.color.alpha/255 end @@ -345,15 +348,13 @@ function images.hover(t, x, y) return false end - local pos_x, pos_y = t:pos() - local off_x, off_y = t:get_extents() - - -- print(pos_x, pos_y, off_x, off_y) + local start_pos_x, start_pos_y = t:pos() + local end_pos_x, end_pos_y = t:get_extents() - return (pos_x <= x and x <= pos_x + off_x - or pos_x >= x and x >= pos_x + off_x) - and (pos_y <= y and y <= pos_y + off_y - or pos_y >= y and y >= pos_y + off_y) + return (start_pos_x <= x and x <= end_pos_x + or start_pos_x >= x and x >= end_pos_x) + and (start_pos_y <= y and y <= end_pos_y + or start_pos_y >= y and y >= end_pos_y) end function images.destroy(t) diff --git a/addons/libs/json.lua b/addons/libs/json.lua index 09451111e3..ff8e3142af 100644 --- a/addons/libs/json.lua +++ b/addons/libs/json.lua @@ -2,15 +2,19 @@ Small implementation of a JSON file reader. ]] +_libs = _libs or {} + +require('tables') +require('lists') +require('sets') +require('strings') + +local table, list, set, string = _libs.tables, _libs.lists, _libs.sets, _libs.strings +local files = require('files') + local json = {} -_libs = _libs or {} _libs.json = json -_libs.tables = _libs.tables or require('tables') -_libs.lists = _libs.lists or require('lists') -_libs.sets = _libs.sets or require('sets') -_libs.strings = _libs.strings or require('strings') -_libs.files = _libs.files or require('files') -- Define singleton JSON characters that can delimit strings. local singletons = '{}[],:' @@ -20,7 +24,7 @@ local value_types = S{'boolean', 'number', 'string', 'nil'} -- Takes a filename and tries to parse the JSON in it, after a validity check. function json.read(file) if type(file) == 'string' then - file = _libs.files.new(file) + file = files.new(file) end if not file:exists() then diff --git a/addons/libs/lists.lua b/addons/libs/lists.lua index 936cd74b02..2ea86e1706 100644 --- a/addons/libs/lists.lua +++ b/addons/libs/lists.lua @@ -3,16 +3,23 @@ ]] _libs = _libs or {} -_libs.lists = true -_libs.tables = _libs.tables or require('tables') -_raw = _raw or {} -_raw.table = _raw.table or {} +require('tables') + +local table = _libs.tables list = {} +local list = list + +_libs.lists = list + +_raw = _raw or {} +_raw.table = _raw.table or {} + _meta = _meta or {} _meta.L = {} + _meta.L.__index = function(l, k) if type(k) == 'number' then k = k < 0 and l.n + k + 1 or k @@ -22,6 +29,7 @@ _meta.L.__index = function(l, k) return list[k] or table[k] end + _meta.L.__newindex = function(l, k, v) if type(k) == 'number' then k = k < 0 and l.n + k + 1 or k diff --git a/addons/libs/logger.lua b/addons/libs/logger.lua index c5ea5a7bc0..b1fb36058a 100644 --- a/addons/libs/logger.lua +++ b/addons/libs/logger.lua @@ -3,16 +3,21 @@ This library provides a set of functions to aid in debugging. ]] _libs = _libs or {} -_libs.logger = true -_libs.strings = _libs.strings or require('strings') -_libs.chat = _libs.chat or require('chat') -_raw = _raw or {} +require('strings') +require('chat') + +local string, chat = _libs.strings, _libs.chat +local table = require('table') local logger = {} -logger.defaults = {} + +_libs.logger = logger + +_raw = _raw or {} -- Set up, based on addon. +logger.defaults = {} logger.defaults.logtofile = false logger.defaults.defaultfile = 'lua.log' logger.defaults.logcolor = 207 diff --git a/addons/libs/maths.lua b/addons/libs/maths.lua index a7a5d4e22e..732f8bdeb5 100644 --- a/addons/libs/maths.lua +++ b/addons/libs/maths.lua @@ -3,8 +3,15 @@ ]] _libs = _libs or {} -_libs.maths = true -_libs.functions = _libs.functions or require('functions') + +require('functions') + +local functions = _libs.functions +local string = require('string') + +local math = require('math') + +_libs.maths = math _raw = _raw or {} _raw.math = setmetatable(_raw.math or {}, {__index = math}) @@ -26,7 +33,7 @@ math.phi = (1 + 5:sqrt())/2 -- Rounds to prec decimal digits. Accepts negative numbers for precision. function math.round(num, prec) local mult = 10^(prec or 0) - return ((num * mult + 0.5) / mult):floor() + return (num * mult + 0.5):floor() / mult end -- Returns the sign of num, -1 for a negative number, +1 for a positive number and 0 for 0. diff --git a/addons/libs/matrices.lua b/addons/libs/matrices.lua index b607dc042d..5931aad15f 100644 --- a/addons/libs/matrices.lua +++ b/addons/libs/matrices.lua @@ -3,13 +3,17 @@ Library for a matrix data structure and operations defined on it. ]] _libs = _libs or {} -_libs.matrices = true -_libs.tables = _libs.tables or require('tables') -_libs.maths = _libs.maths or require('maths') -_libs.vectors = _libs.vectors or require('vectors') + +require('tables') +require('maths') +require('vectors') + +local table, math, vector = _libs.tables, _libs.maths, _libs.vectors matrix = {} +_libs.matrices = matrix + _meta = _meta or {} _meta.M = _meta.M or {} _meta.M.__index = matrix @@ -249,7 +253,7 @@ function matrix.vprint(m) end --[[ -Copyright (c) 2013, Windower +Copyright © 2013, Windower All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/addons/libs/packets.lua b/addons/libs/packets.lua index 8548b4aa1a..86c4fbbcb4 100644 --- a/addons/libs/packets.lua +++ b/addons/libs/packets.lua @@ -1,18 +1,21 @@ --[[ -A library to facilitate packet usage +A library to facilitate packet usage ]] -local packets = {} - _libs = _libs or {} -_libs.packets = packets -_libs.lists = _libs.lists or require('lists') -_libs.maths = _libs.maths or require('maths') -_libs.strings = _libs.strings or require('strings') -_libs.functions = _libs.functions or require('functions') +require('lists') +require('maths') +require('strings') +require('functions') require('pack') +local table = require('table') + +local packets = {} + +_libs.packets = packets + if not warning then warning = print+{_addon.name and '%s warning:':format(_addon.name) or 'Warning:'} end @@ -65,7 +68,7 @@ local sizes = { } -- This defines whether to treat a type with brackets at the end as an array or something special -local non_array_types = S{'bit', 'data', 'char'} +local non_array_types = S{'bit', 'data', 'char'} -- Pattern to match variable size array local pointer_pattern = '(.+)%*' @@ -96,8 +99,8 @@ local size size = function(fields, count) -- A single field if fields.ctype then - local bits, type_count, type = parse_type(fields) - return bits or count * sizes[type] + local bits, _, type = parse_type(fields) + return bits or type == 'char' and 8 or count and count * sizes[type] or 0 end -- A reference field @@ -143,7 +146,7 @@ parse = function(fields, data, index, max, lookup, depth) if lookup then -- Look up index name in provided table local resource = lookup[1][count + lookup[2] - 1] - field.label = '%s %s':format(resource and resource.name or 'Unknown %d':format(count + lookup[2] - 1), field.label) + field.label = '%s %s':format(resource and resource.english or 'Unknown %d':format(count + lookup[2] - 1), field.label) else -- Just increment numerically field.label = '%s %d':format(field.label, count) @@ -293,7 +296,7 @@ end -- If data is a string it parses an existing packet, otherwise it will create -- a new packet table for injection. In that case, data can ba an optional -- table containing values to initialize the packet to. --- +-- -- Example usage -- Injection: -- local packet = packets.new('outgoing', 0x050, { @@ -307,7 +310,7 @@ end -- packet['Inventory Index'] = 27 -- 27th item in the inventory -- packet['Equipment Slot'] = 15 -- 15th slot, left ring -- packets.inject(packet) --- +-- -- Parsing: -- windower.register_event('outgoing chunk', function(id, data) -- if id == 0x0B6 then -- outgoing /tell @@ -390,6 +393,11 @@ function packets.new(dir, id, values, ...) return packet end +local lookup = function(packet, field) + local val = packet[field.label] + return field.enc and val:encode(field.enc) or val +end + -- Returns binary data from a packet function packets.build(packet) local fields = packets.fields(packet._dir, packet._id, packet._raw, unpack(packet._args or {})) @@ -399,7 +407,7 @@ function packets.build(packet) end local pack_string = fields:map(make_pack_string):concat() - local data = pack_string:pack(fields:map(table.lookup-{packet, 'label'}):unpack()) + local data = pack_string:pack(fields:map(lookup+{packet}):unpack()) local rem = #data % 4 if rem ~= 0 then data = data .. 0:char():rep(4 - rem) diff --git a/addons/libs/packets/data.lua b/addons/libs/packets/data.lua index 3d64c38ca0..ff1a674731 100644 --- a/addons/libs/packets/data.lua +++ b/addons/libs/packets/data.lua @@ -152,7 +152,7 @@ data.incoming[0x038] = {name='Entity Animation', description='Sent when a mod data.incoming[0x039] = {name='Env. Animation', description='Sent to force animations to specific objects.'} data.incoming[0x03A] = {name='Independ. Animation', description='Used for arbitrary battle animations that are unaccompanied by an action packet.'} data.incoming[0x03C] = {name='Shop', description='Displays items in a vendors shop.'} -data.incoming[0x03D] = {name='Value', description='Returns the value of an item.'} +data.incoming[0x03D] = {name='Shop Value/Sale', description='Returns the value of an item or notice it has been sold.'} data.incoming[0x03E] = {name='Open Buy/Sell', description='Opens the buy/sell menu for vendors.'} data.incoming[0x03F] = {name='Shop Buy Response', description='Sent when you buy something from normal vendors.'} data.incoming[0x041] = {name='Blacklist', description='Contains player ID and name for blacklist.'} @@ -200,9 +200,11 @@ data.incoming[0x08D] = {name='Job Points', description='Contains all jo data.incoming[0x0A0] = {name='Party Map Marker', description='Marks where players are on your map.'} data.incoming[0x0AA] = {name='Spell List', description='Packet that shows the spells that you know.'} data.incoming[0x0AC] = {name='Ability List', description='Packet that shows your current abilities and traits.'} +data.incoming[0x0AD] = {name='MMM List', description='Packet that shows your current Moblin Maze Mongers Vouchers and Runes.'} data.incoming[0x0AE] = {name='Mount List', description='Packet that shows your current mounts.'} data.incoming[0x0B4] = {name='Seek AnonResp', description='Server response sent after you put up party or anon flag.'} data.incoming[0x0B5] = {name='Help Desk Open', description='Sent when you open the Help Desk submenu.'} +data.incoming[0x0BF] = {name='Reservation Response',description='Sent to inform the client about the status of entry to an instanced area.'} data.incoming[0x0C8] = {name='Party Struct Update', description='Updates all party member info in one struct. No player vital data (HP/MP/TP) or names are sent here.'} data.incoming[0x0C9] = {name='Show Equip', description='Shows another player your equipment after using the Check command.'} data.incoming[0x0CA] = {name='Bazaar Message', description='Shows another players bazaar message after using the Check command or sets your own on zoning.'} diff --git a/addons/libs/packets/fields.lua b/addons/libs/packets/fields.lua index 16254679d3..4813bed35b 100644 --- a/addons/libs/packets/fields.lua +++ b/addons/libs/packets/fields.lua @@ -20,12 +20,23 @@ local func = { } -- String decoding definitions -local ls_name_msg = T('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':split()) -ls_name_msg[0] = 0:char() -local item_inscr = T('0123456798ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{':split()) -item_inscr[0] = 0:char() -local ls_name_ext = T(('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' .. 0:char():rep(11)):split()) -ls_name_ext[0] = '`' +local ls_enc = { + charset = T('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':split()):update({ + [0] = '`', + [60] = 0:char(), + [63] = 0:char(), + }), + bits = 6, + terminator = function(str) + return (#str % 4 == 2 and 60 or 63):binary() + end +} +local sign_enc = { + charset = T('0123456798ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{':split()):update({ + [0] = 0:char(), + }), + bits = 6, +} -- Function definitions. Used to display packet field information. local res = require('resources') @@ -95,8 +106,7 @@ do end bufftime = function(ts) - -- Todo... - return fn(ts) + return fn(1009810800 + (ts / 60) + 0x100000000 / 60 * 9) -- increment last number every 2.27 years end end @@ -118,9 +128,7 @@ local function zone(val) end local function item(val) - return val ~= 0 and res.items[val] - and res.items[val].name - or '-' + return val ~= 0 and res.items[val] and res.items[val].name or '-' end local function server(val) @@ -156,7 +164,7 @@ local function emote(val) end local function bag(val) - return res.bags[val].name + return res.bags[val] and res.bags[val].name or 'Unknown' end local function race(val) @@ -168,7 +176,7 @@ local function slot(val) end local function statuses(val) - return res.statuses[val].name + return res.statuses[val] and res.statuses[val].name or 'Unknown' end local function srank(val) @@ -184,12 +192,7 @@ local function inv(bag, val) return '-' end - local items = windower.ffxi.get_items()[res.bags[bag].english:lower()] - if not items[val] then - return '-' - end - - return item(items[val].id) + return item(windower.ffxi.get_items(bag, val).id) end local function invp(index, val, data) @@ -266,7 +269,7 @@ local enums = { } local e = function(t, val) - return enums[t][val] or 'Unknown value for \'%s\': %i':format(t, val) + return enums[t][val] or 'Unknown value for \'%s\': %s':format(t, tostring(val)) end --[[ @@ -348,7 +351,9 @@ enums['action'] = { [0x0E] = 'Cast Fishing Rod', [0x0F] = 'Switch target', [0x10] = 'Ranged attack', + [0x11] = 'Chocobo dig', [0x12] = 'Dismount Chocobo', + [0x13] = 'Tractor Dialogue', [0x14] = 'Zoning/Appear', -- I think, the resource for this is ambiguous. [0x19] = 'Monsterskill', [0x1A] = 'Mount', @@ -393,7 +398,7 @@ fields.outgoing[0x029] = L{ fields.outgoing[0x02B] = L{ {ctype='unsigned char', label='Starting Language'}, -- 04 0 == JP, 1 == EN {ctype='unsigned char', label='Ending Language'}, -- 05 0 == JP, 1 == EN - {ctype='unsigned short', label='_unknown1', const=0x0000}, -- 06 + {ctype='unsigned short', label='_unknown1', const=0x0000}, -- 06 {ctype='char[64]', label='Phrase'}, -- 08 Quotation marks are removed. Phrase is truncated at 64 characters. } @@ -414,7 +419,7 @@ enums[0x033] = { -- Sent when accepting, confirming or canceling a trade fields.outgoing[0x033] = L{ {ctype='unsigned int', label='Type', fn=e+{0x033}}, -- 04 - {ctype='data[4]', label='_unknown1'} -- 08 + {ctype='unsigned int', label='Trade Count'} -- 08 Necessary to set if you are receiving items, comes from incoming packet 0x023 } -- Trade offer @@ -446,7 +451,7 @@ fields.outgoing[0x037] = L{ {ctype='unsigned char', label='Slot', fn=inv+{0}}, -- 0E {ctype='unsigned char', label='_unknown2'}, -- 0F Takes values {ctype='unsigned char', label='Bag', fn=bag}, -- 10 - {ctype='data[3]', label='_unknown2'} -- 11 + {ctype='data[3]', label='_unknown3'} -- 11 } -- Sort Item @@ -577,14 +582,10 @@ func.outgoing[0x04E][0x10] = L{ } -- Auction Interaction -fields.outgoing[0x04E] = function() - local self = func.outgoing[0x04E] - local fields = self.base - - return function(data, type) - return self.base + (self[type or data:byte(5)] or L{}) - end -end() +fields.outgoing[0x04E] = function(data, type) + type = type or data and data:byte(5) + return func.outgoing[0x04E].base + (func.outgoing[0x04E][type] or L{}) +end -- Equip fields.outgoing[0x050] = L{ @@ -646,7 +647,7 @@ types.lockstyleset = L{ } -- lockstyleset -fields.outgoing[0x53] = L{ +fields.outgoing[0x053] = L{ -- First 4 bytes are a header for the set {ctype='unsigned char', label='Count'}, -- 04 {ctype='unsigned char', label='Type'}, -- 05 0 = "Stop locking style", 1 = "Continue locking style", 3 = "Lock style in this way". Might be flags? @@ -688,7 +689,17 @@ fields.outgoing[0x05C] = L{ {ctype='unsigned short', label='Zone'}, -- 18 {ctype='unsigned short', label='Menu ID'}, -- 1A {ctype='unsigned short', label='Target Index', fn=index}, -- 1C - {ctype='unsigned short', label='_unknown3'}, -- 1E Not zone ID + {ctype='unsigned char', label='_unknown2', const=1}, -- 1E + {ctype='unsigned char', label='Rotation'}, -- 1F +} + +-- Outgoing emote +fields.outgoing[0x05D] = L{ + {ctype='unsigned int', label='Target ID', fn=id}, -- 04 + {ctype='unsigned short', label='Target Index', fn=index}, -- 08 + {ctype='unsigned char', label='Emote', fn=emote}, -- 0A + {ctype='unsigned char', label='Type'}, -- 0B 2 for motion, 0 otherwise + {ctype='unsigned int', label='_unknown1', const=0}, -- 0C } -- Zone request @@ -705,8 +716,9 @@ fields.outgoing[0x05E] = L{ {ctype='unsigned char', label='Type'}, -- 17 03 for leaving the MH, 00 otherwise } --- Equipment Screen (0x02 length) -- Also observed when zoning +-- Equipment Screen, also observed when zoning fields.outgoing[0x061] = L{ + {ctype='data[4]', label='_unknown1'}, -- 04 Always zero? } -- Digging Finished @@ -723,7 +735,7 @@ fields.outgoing[0x063] = L{ --"New" Key Item examination packet fields.outgoing[0x064] = L{ {ctype='unsigned int', label='Player', fn=id}, -- 04 - {ctype='byte[0x40]', label='flags'}, -- 08 These correspond to a particular section of the 0x55 incoming packet + {ctype='data[0x40]', label='flags'}, -- 08 These correspond to a particular section of the 0x55 incoming packet {ctype='unsigned int', label='_unknown1'}, -- 48 This field somehow denotes which half-0x55-packet the flags corresponds to } @@ -749,7 +761,7 @@ fields.outgoing[0x070] = L{ -- Kick fields.outgoing[0x071] = L{ - {ctype='data[6]', label='_unknown1'}, -- 04 + {ctype='data[6]', label='_unknown1'}, -- 04 {ctype='unsigned char', label='Kick Type'}, -- 0A 0 for party, 1 for linkshell, 2 for alliance (maybe) {ctype='unsigned char', label='_unknown2'}, -- 0B {ctype='data[16]', label='Member Name'} -- 0C Null terminated string @@ -783,8 +795,8 @@ fields.outgoing[0x078] = L{ -- Guild NPC Buy -- Sent when buying an item from a guild NPC fields.outgoing[0x082] = L{ - {ctype='unsigned short', label='Item', fn=item}, -- 08 - {ctype='unsigned char', label='_unknown1', const=0x00}, -- 0A + {ctype='unsigned short', label='Item', fn=item}, -- 08 + {ctype='unsigned char', label='_unknown1', const=0x00}, -- 0A {ctype='unsigned char', label='Count'}, -- 0B Number you are buying } @@ -848,8 +860,8 @@ fields.outgoing[0x0A2] = L{ -- Guild Buy Item -- Sent when buying an item from a guild NPC fields.outgoing[0x0AA] = L{ - {ctype='unsigned short', label='Item', fn=item}, -- 04 - {ctype='unsigned char', label='_unknown1', const=0x00}, -- 06 + {ctype='unsigned short', label='Item', fn=item}, -- 04 + {ctype='unsigned char', label='_unknown1', const=0x00}, -- 06 {ctype='unsigned char', label='Count'}, -- 07 Number you are buying } @@ -861,8 +873,8 @@ fields.outgoing[0x0AB] = L{ -- Guild Sell Item -- Sent when selling an item to a guild NPC fields.outgoing[0x0AC] = L{ - {ctype='unsigned short', label='Item', fn=item}, -- 04 - {ctype='unsigned char', label='_unknown1'}, -- 06 + {ctype='unsigned short', label='Item', fn=item}, -- 04 + {ctype='unsigned char', label='_unknown1'}, -- 06 {ctype='unsigned char', label='Count'}, -- 07 Number you are selling } @@ -880,9 +892,9 @@ fields.outgoing[0x0B5] = L{ -- Tell fields.outgoing[0x0B6] = L{ - {ctype='unsigned char', label='_unknown1', const=0x00}, -- 04 00 for a normal tell -- Varying this does nothing. - {ctype='char[15]', label='Target Name'}, -- 05 - {ctype='char*', label='Message'}, -- 14 + {ctype='unsigned short', label='_unknown1', const=0x0003}, -- 04 03 00 for a normal tell -- Varying this did nothing. + {ctype='char[15]', label='Target Name'}, -- 06 + {ctype='char*', label='Message'}, -- 15 } -- Merit Point Increase @@ -894,9 +906,9 @@ fields.outgoing[0x0BE] = L{ } -- Job Point Increase --- This chunk was sent on three consecutive outgoing packets the only time I've used it fields.outgoing[0x0BF] = L{ - {ctype='unsigned short', label='Job Point'}, -- 04 + {ctype='bit[5]', label='Type'}, -- 04 + {ctype='bit[11]', label='Job', fn=job}, -- 04 {ctype='unsigned short', label='_junk1', const=0x0000}, -- 06 No values seen so far } @@ -907,8 +919,8 @@ fields.outgoing[0x0C0] = L{ -- /makelinkshell fields.outgoing[0x0C3] = L{ - {ctype='unsigned char', label='_unknown1'}, -- 04 - {ctype='unsigned char', label='Linkshell Numbger'}, -- 05 + {ctype='unsigned char', label='_unknown1'}, -- 04 + {ctype='unsigned char', label='Linkshell Number'}, -- 05 {ctype='data[2]', label='_junk1'} -- 05 } @@ -975,6 +987,14 @@ fields.outgoing[0x0E7] = L{ {ctype='unsigned char', label='_unknown3'}, -- 07 Observed to be 00 } +-- Toggle Heal +fields.outgoing[0x0E8] = L{ + {ctype='unsigned char', label='Movement'}, -- 04 02 if caused by movement + {ctype='unsigned char', label='_unknown2'}, -- 05 00 observed + {ctype='unsigned char', label='_unknown3'}, -- 06 00 observed + {ctype='unsigned char', label='_unknown4'}, -- 07 00 observed +} + -- Sit fields.outgoing[0x0EA] = L{ {ctype='unsigned char', label='Movement'}, -- 04 @@ -1136,7 +1156,7 @@ fields.outgoing[0x10D] = L{ fields.outgoing[0x10E] = L{ {ctype='unsigned short', label='RoE Quest'}, -- 04 This field is likely actually 12 bits } - + -- Currency Menu fields.outgoing[0x10F] = L{ } @@ -1179,7 +1199,7 @@ fields.outgoing[0x115] = L{ -- Open Unity Menu :: Two of these are sent whenever I open my unity menu. The first one has a bool of 0 and the second of 1. fields.outgoing[0x116] = L{ {ctype='bool', label='_unknown1'}, -- 04 - {ctype='char[3]', label='_unknown2'}, -- 05 + {ctype='char[3]', label='_unknown2'}, -- 05 } -- Unity Ranking Results :: Sent when I open my Unity Ranking Results menu. Triggers a Sparks Update packet and may trigger ranking packets that I could not record. @@ -1190,7 +1210,7 @@ fields.outgoing[0x117] = L{ -- Open Chat status fields.outgoing[0x118] = L{ {ctype='bool', label='Chat Status'}, -- 04 0 for Inactive and 1 for Active - {ctype='char[3]', label='_unknown2'}, -- 05 + {ctype='char[3]', label='_unknown2'}, -- 05 } types.job_level = L{ @@ -1201,7 +1221,18 @@ types.job_level = L{ fields.incoming[0x00A] = L{ {ctype='unsigned int', label='Player', fn=id}, -- 04 {ctype='unsigned short', label='Player Index', fn=index}, -- 08 - {ctype='data[38]', label='_unknown1'}, -- 0A + {ctype='unsigned char', label='_padding'}, -- 0A + {ctype='unsigned char', label='Heading', fn=dir}, -- 0B -- 0B to + {ctype='float', label='X'}, -- 0C + {ctype='float', label='Z'}, -- 10 + {ctype='float', label='Y'}, -- 14 + {ctype='unsigned short', label='Run Count'}, -- 18 + {ctype='unsigned short', label='Target Index', fn=index}, -- 1A + {ctype='unsigned char', label='Movement Speed'}, -- 1C 32 represents 100% + {ctype='unsigned char', label='Animation Speed'}, -- 1D 32 represents 100% + {ctype='unsigned char', label='HP %', fn=percent}, -- 1E + {ctype='unsigned char', label='Status', fn=statuses}, -- 1F + {ctype='data[16]', label='_unknown1'}, -- 20 {ctype='unsigned short', label='Zone', fn=zone}, -- 30 {ctype='data[6]', label='_unknown2'}, -- 32 {ctype='unsigned int', label='Timestamp 1', fn=time}, -- 38 @@ -1218,22 +1249,30 @@ fields.incoming[0x00A] = L{ {ctype='unsigned short', label='Main'}, -- 50 {ctype='unsigned short', label='Sub'}, -- 52 {ctype='unsigned short', label='Ranged'}, -- 54 - {ctype='data[18]', label='_unknown4'}, -- 56 + {ctype='unsigned short', label='Day Music'}, -- 56 + {ctype='unsigned short', label='Night Music'}, -- 58 + {ctype='unsigned short', label='Solo Combat Music'}, -- 5A + {ctype='unsigned short', label='Party Combat Music'}, -- 5C + {ctype='unsigned short', label='Mount Music'}, -- 5E + {ctype='data[2]', label='_unknown4'}, -- 60 + {ctype='unsigned short', label='Menu Zone'}, -- 62 Only set if the menu ID is sent, used as the zone for menu responses (0x5b, 0x5c) + {ctype='unsigned short', label='Menu ID'}, -- 64 + {ctype='unsigned short', label='_unknown5'}, -- 66 {ctype='unsigned short', label='Weather', fn=weather}, -- 68 - {ctype='unsigned short', label='_unknown5'}, -- 6A - {ctype='data[24]', label='_unknown6'}, -- 6C + {ctype='unsigned short', label='_unknown6'}, -- 6A + {ctype='data[24]', label='_unknown7'}, -- 6C {ctype='char[16]', label='Player Name'}, -- 84 - {ctype='data[12]', label='_unknown7'}, -- 94 + {ctype='data[12]', label='_unknown8'}, -- 94 {ctype='unsigned int', label='Abyssea Timestamp', fn=time}, -- A0 - {ctype='unsigned int', label='_unknown8', const=0x0003A020}, -- A4 - {ctype='data[2]', label='_unknown9'}, -- A8 + {ctype='unsigned int', label='_unknown9', const=0x0003A020}, -- A4 + {ctype='data[2]', label='_unknown10'}, -- A8 {ctype='unsigned short', label='Zone model'}, -- AA - {ctype='data[8]', label='_unknown10'}, -- AC 0xAC is 2 for some zones, 0 for others + {ctype='data[8]', label='_unknown11'}, -- AC 0xAC is 2 for some zones, 0 for others {ctype='unsigned char', label='Main Job', fn=job}, -- B4 - {ctype='unsigned char', label='_unknown11'}, -- B5 - {ctype='unsigned char', label='_unknown12'}, -- B6 + {ctype='unsigned char', label='_unknown12'}, -- B5 + {ctype='unsigned char', label='_unknown13'}, -- B6 {ctype='unsigned char', label='Sub Job', fn=job}, -- B7 - {ctype='unsigned int', label='_unknown13'}, -- B8 + {ctype='unsigned int', label='_unknown14'}, -- B8 {ref=types.job_level, lookup={res.jobs, 0x00}, count=0x10}, -- BC {ctype='signed short', label='STR'}, -- CC {ctype='signed short', label='DEX'}, -- CE @@ -1251,7 +1290,7 @@ fields.incoming[0x00A] = L{ {ctype='signed short', label='CHR Bonus'}, -- E6 {ctype='unsigned int', label='Max HP'}, -- E8 {ctype='unsigned int', label='Max MP'}, -- EC - {ctype='data[20]', label='_unknown14'}, -- F0 + {ctype='data[20]', label='_unknown15'}, -- F0 } -- Zone Response @@ -1314,7 +1353,7 @@ fields.incoming[0x00D] = L{ {ctype='unsigned int', label='Player', fn=id}, -- 04 {ctype='unsigned short', label='Index', fn=index}, -- 08 - {ctype='boolbit', label='Update Position'}, -- 0A:0 Position, Rotation, Target, Speed + {ctype='boolbit', label='Update Position'}, -- 0A:0 Position, Rotation, Target, Speed {ctype='boolbit', label='Update Status'}, -- 1A:1 Not used for 0x00D {ctype='boolbit', label='Update Vitals'}, -- 0A:2 HP%, Status, Flags, LS color, "Face Flags" {ctype='boolbit', label='Update Name'}, -- 0A:3 Name @@ -1338,10 +1377,26 @@ fields.incoming[0x00D] = L{ {ctype='unsigned char', label='Linkshell Red'}, -- 24 {ctype='unsigned char', label='Linkshell Green'}, -- 25 {ctype='unsigned char', label='Linkshell Blue'}, -- 26 - {ctype='unsigned char', label='_unknown5'}, -- 27 Probably junk from the LS color dword - {ctype='data[0x1B]', label='_unknown6'}, -- 28 DSP notes that the 6th bit of byte 54 is the Ballista flag + {ctype='unsigned char', label='_flags1'}, -- 27 0x80 Autogroup flag + {ctype='unsigned char', label='_flags2'}, -- 28 0x01 puts your weapon on hand, 0x02 Request flag, + {ctype='unsigned char', label='PvP Stuff'}, -- 29 Same pattern than incoming 0x037 packet + {ctype='unsigned char', label='_flags3'}, -- 2A 0x20 Sneak Effect flag, 0x80 New Adventurer flag + {ctype='unsigned char', label='_flags4'}, -- 2B 0x01 Mentor flag + {ctype='data[4]', label='_unknown6'}, -- 2C + {ctype='unsigned short', label='Costume'}, -- 30 ID of the Model + {ctype='data[1]', label='_unknown7'}, -- 32 + {ctype='unsigned char', label='_flags5'}, -- 33 0x02 Trial Account flag, 0x40 Job Master Stars flag + {ctype='unsigned int', label='_unknown8'}, -- 34 Related to mounts + {ctype='data[4]', label='_unknown9'}, -- 38 + {ctype='unsigned short', label='Pet Index', fn=index}, -- 3C + {ctype='unsigned short', label='Monstrosity Species'}, -- 3E High bit is always set while in monstrosity and determines the display of the third name + {ctype='unsigned char', label='Monstrosity Name 1'}, -- 40 + {ctype='unsigned char', label='Monstrosity Name 2'}, -- 41 + {ctype='unsigned char', label='Indi Bubble'}, -- 42 Geomancer (GEO) Indi spell effect on players. 0 is no effect. {ctype='unsigned char', label='Face Flags'}, -- 43 0, 3, 4, or 8 - {ctype='data[4]', label='_unknown7'}, -- 44 + {ctype='bit[4]', label='_unknown10'}, -- 44 + {ctype='bit[8]', label='Mount'}, -- 44 Related to Mounts, seems to be mount id + 1, except for chocobo. The value doesn't get zeroed after dismount + {ctype='bit[20]', label='_unknown11'}, -- 45 {ctype='unsigned char', label='Face'}, -- 48 {ctype='unsigned char', label='Race'}, -- 49 {ctype='unsigned short', label='Head'}, -- 4A @@ -1397,32 +1452,71 @@ fields.incoming[0x00E] = L{ {ctype='unsigned char', label='Status', fn=statuses}, -- 1F Status used to be 0x20 {ctype='unsigned int', label='_unknown2', fn=bin+{4}}, -- 20 {ctype='unsigned int', label='_unknown3', fn=bin+{4}}, -- 24 - {ctype='unsigned int', label='_unknown4', fn=bin+{4}}, -- 28 + {ctype='unsigned int', label='_unknown4', fn=bin+{4}}, -- 28 In Dynamis - Divergence statue's eye colors {ctype='unsigned int', label='Claimer', fn=id}, -- 2C {ctype='unsigned short', label='_unknown5'}, -- 30 {ctype='unsigned short', label='Model'}, -- 32 {ctype='char*', label='Name'}, -- 34 - * } --- Incoming Chat -fields.incoming[0x017] = L{ - {ctype='unsigned char', label='Mode', fn=chat}, -- 04 +enums['mentor icon'] = { + [0] = 'None', + [1] = 'Bronze', + [2] = 'Silver', + [3] = 'Gold' +} + +func.incoming[0x017] = {} +func.incoming[0x017].base = L{ + {ctype='unsigned char', label='Mode', fn=chat}, -- 04 +} +func.incoming[0x017].default = L{ + {ctype='bool', label='GM'}, -- 05 + {ctype='unsigned short', label='_padding1',}, -- 06 Reserved for Yell and Assist Modes + {ctype='char[0xF]', label='Sender Name'}, -- 08 + {ctype='char*', label='Message'}, -- 17 Max of 150 characters +} +func.incoming[0x017][0x1A] = L{ -- Yell + {ctype='bool', label='GM'}, -- 05 + {ctype='unsigned short', label='Zone', fn=zone}, -- 06 Zone ID of sender + {ctype='char[0xF]', label='Sender Name'}, -- 08 + {ctype='char*', label='Message'}, -- 17 Max of 150 characters +} +func.incoming[0x017][0x22] = L{ -- AssistJ {ctype='bool', label='GM'}, -- 05 - {ctype='unsigned short', label='Zone', fn=zone}, -- 06 Set only for Yell - {ctype='char[16]', label='Sender Name'}, -- 08 - {ctype='char*', label='Message'}, -- 18 Max of 150 characters + {ctype='unsigned char', label='Mastery Rank'}, -- 06 Sender Mastery Rank + {ctype='unsigned char', label='Mentor Icon', fn=e+{'mentor icon'}},-- 07 Color of Mentor Flag + {ctype='char[0xF]', label='Sender Name'}, -- 08 + {ctype='char*', label='Message'}, -- 17 Max of 150 characters +} +func.incoming[0x017][0x23] = func.incoming[0x017][0x22] -- AssistE + +-- Incoming Chat +fields.incoming[0x017] = function() + local fields = func.incoming[0x017] + + return function(data, type) + return fields.base + (fields[type or data:byte(5)] or fields.default) + end +end() + +types.job_master= L{ + {ctype='boolbit', label='Master'} +} +types.job_master_level= L{ + {ctype='unsigned char', label='Master Level'} } -- Job Info fields.incoming[0x01B] = L{ {ctype='unsigned int', label='_unknown1'}, -- 04 Observed value of 05 - {ctype='unsigned char', label='Main Job', fn=job}, -- 08 + {ctype='unsigned char', label='Main Job', fn=job}, -- 08 {ctype='unsigned char', label='Flag or Main Job Level?'}, -- 09 {ctype='unsigned char', label='Flag or Sub Job Level?'}, -- 0A - {ctype='unsigned char', label='Sub Job', fn=job}, -- 0B + {ctype='unsigned char', label='Sub Job', fn=job}, -- 0B {ctype='bit[32]', label='Sub/Job Unlock Flags'}, -- 0C Indicate whether subjob is unlocked and which jobs are unlocked. lsb of 0x0C indicates subjob unlock. {ctype='unsigned char', label='_unknown3'}, -- 10 Flag or List Start - {ref=types.job_level, lookup={res.jobs, 0x01}, count=0x0F}, -- 11 + {ref=types.job_level, lookup={res.jobs, 0x01}, count=0x0F}, -- 11 {ctype='unsigned short', label='Base STR'}, -- 20 -- Altering these stat values has no impact on your equipment menu. {ctype='unsigned short', label='Base DEX'}, -- 22 {ctype='unsigned short', label='Base VIT'}, -- 24 @@ -1435,9 +1529,18 @@ fields.incoming[0x01B] = L{ {ctype='unsigned int', label='Maximum MP'}, -- 40 {ctype='unsigned int', label='Flags'}, -- 44 Looks like a bunch of flags. Observed value if 01 00 00 00 {ctype='unsigned char', label='_unknown5'}, -- 48 Potential flag to signal the list start. Observed value of 01 - {ref=types.job_level, lookup={res.jobs, 0x01}, count=0x16}, -- 49 + {ref=types.job_level, lookup={res.jobs, 0x01}, count=0x16}, -- 49 {ctype='unsigned char', label='Current Monster Level'}, -- 5F {ctype='unsigned int', label='Encumbrance Flags'}, -- 60 [legs, hands, body, head, ammo, range, sub, main,] [back, right_ring, left_ring, right_ear, left_ear, waist, neck, feet] [HP, CHR, MND, INT, AGI, VIT, DEX, STR,] [X X X X X X X MP] + {ctype='unsigned char', label='_unknown7'}, -- 64 + {ctype='unsigned char', label='Mentor Icon', fn=e+{'mentor icon'}},-- 65 + {ctype='unsigned char', label='Mastery Rank'}, -- 66 + {ctype='unsigned char', label='_unknown8'}, -- 67 + {ctype='bit[1]', label='_junk1'}, -- 68 + {ref=types.job_master, lookup={res.jobs, 0x01}, count=0x16}, -- 68 Indicates if the job is mastered, but only after receiving "Master Breaker" KI. Used to populate "Master Levels" Menu + {ctype='bit[1]', label='_junk2'}, -- 6A + {ctype='unsigned short', label='_junk3'}, -- 6B + {ref=types.job_master_level,lookup={res.jobs, 0x01}, count=0x16}, -- 6D } -- Inventory Count @@ -1461,27 +1564,43 @@ fields.incoming[0x01C] = L{ {ctype='unsigned char', label='Wardrobe 2 Size'}, -- 0E {ctype='unsigned char', label='Wardrobe 3 Size'}, -- 0F {ctype='unsigned char', label='Wardrobe 4 Size'}, -- 10 - {ctype='data[3]', label='_padding1', const=''}, -- 11 - {ctype='unsigned short', label='_dupeInventory Size'}, -- 14 These "dupe" sizes are set to 0 if the inventory disabled. - {ctype='unsigned short', label='_dupeSafe Size'}, -- 16 - {ctype='unsigned short', label='_dupeStorage Size'}, -- 18 The accumulated storage from all items (uncapped) -1 - {ctype='unsigned short', label='_dupeTemporary Size'}, -- 1A - {ctype='unsigned short', label='_dupeLocker Size'}, -- 1C + {ctype='unsigned char', label='Wardrobe 5 Size'}, -- 11 + {ctype='unsigned char', label='Wardrobe 6 Size'}, -- 12 + {ctype='unsigned char', label='Wardrobe 7 Size'}, -- 13 + {ctype='unsigned char', label='Wardrobe 8 Size'}, -- 14 + {ctype='unsigned char', label='Recycle Bin Size'}, -- 15 + {ctype='data[14]', label='_padding1', const=''}, -- 16 + {ctype='unsigned short', label='_dupeInventory Size'}, -- 24 These "dupe" sizes are set to 0 if the inventory disabled. + {ctype='unsigned short', label='_dupeSafe Size'}, -- 26 + {ctype='unsigned short', label='_dupeStorage Size'}, -- 28 The accumulated storage from all items (uncapped) -1 + {ctype='unsigned short', label='_dupeTemporary Size'}, -- 2A + {ctype='unsigned short', label='_dupeLocker Size'}, -- 2C {ctype='unsigned short', label='_dupeSatchel Size'}, -- 2E - {ctype='unsigned short', label='_dupeSack Size'}, -- 20 - {ctype='unsigned short', label='_dupeCase Size'}, -- 22 - {ctype='unsigned short', label='_dupeWardrobe Size'}, -- 24 - {ctype='unsigned short', label='_dupeSafe 2 Size'}, -- 26 - {ctype='unsigned short', label='_dupeWardrobe 2 Size'}, -- 28 - {ctype='unsigned short', label='_dupeWardrobe 3 Size'}, -- 2A This is not set to 0 despite being disabled for whatever reason - {ctype='unsigned short', label='_dupeWardrobe 4 Size'}, -- 2C This is not set to 0 despite being disabled for whatever reason - {ctype='data[6]', label='_padding2', const=''}, -- 2E + {ctype='unsigned short', label='_dupeSack Size'}, -- 30 + {ctype='unsigned short', label='_dupeCase Size'}, -- 32 + {ctype='unsigned short', label='_dupeWardrobe Size'}, -- 34 + {ctype='unsigned short', label='_dupeSafe 2 Size'}, -- 36 + {ctype='unsigned short', label='_dupeWardrobe 2 Size'}, -- 38 + {ctype='unsigned short', label='_dupeWardrobe 3 Size'}, -- 3A This is not set to 0 despite being disabled for whatever reason + {ctype='unsigned short', label='_dupeWardrobe 4 Size'}, -- 3C This is not set to 0 despite being disabled for whatever reason + {ctype='unsigned short', label='_dupeWardrobe 5 Size'}, -- 3E This is not set to 0 despite being disabled for whatever reason + {ctype='unsigned short', label='_dupeWardrobe 6 Size'}, -- 40 This is not set to 0 despite being disabled for whatever reason + {ctype='unsigned short', label='_dupeWardrobe 7 Size'}, -- 42 This is not set to 0 despite being disabled for whatever reason + {ctype='unsigned short', label='_dupeWardrobe 8 Size'}, -- 44 This is not set to 0 despite being disabled for whatever reason + {ctype='unsigned short', label='_dupeRecycle Bin Size'}, -- 46 + {ctype='data[28]', label='_padding2', const=''}, -- 48 +} + +types.bagbits= L{ + {ctype='boolbit', label='Finished'} } - -- Finish Inventory fields.incoming[0x01D] = L{ - {ctype='unsigned char', label='Flag', const=0x01}, -- 04 - {ctype='data[3]', label='_junk1'}, -- 06 + {ctype='unsigned char', label='Flag'}, -- 04 0 for bag finished updates, 1 for finished loading all bags + {ctype='unsigned char', label='Bag', fn=bag}, -- 05 18 (0x12) when Flag is 1, and 18 is not a valid bag id (currently last bag + 1) + {ctype='data[2]', label='_junk1'}, -- 06 + {ref=types.bagbits, lookup={res.bags, 0x00}, count=0x12}, -- 08 due to the way packets are sent, false does not necsarilly mean its not Finished, true simple means that it is Finished. + {ctype='data[1]', label='_junk2'}, -- 0B } -- Modify Inventory @@ -1693,12 +1812,13 @@ func.incoming[0x028].target_base = L{ func.incoming[0x028].action_base = L{ {ctype='bit[5]', label='Reaction'}, -- 00:0 - {ctype='bit[11]', label='Animation'}, -- 00:5 - {ctype='bit[5]', label='Effect'}, -- 02:0 - {ctype='bit[6]', label='Stagger'}, -- 02:5 + {ctype='bit[12]', label='Animation'}, -- 00:5 + {ctype='bit[4]', label='Effect'}, -- 02:1 Particle effects: bit 1 finishing blow, bit 2 critical hit, bit 3 hit not connected, bit 4 effect follow up (I have only seen in jishnu's radiance) + {ctype='bit[3]', label='Stagger'}, -- 02:5 head moving animation when getting hit, the value seems to be set based on dmg done, more dmg more bits sets (not sure if raw or percentage) + {ctype='bit[3]', label='Knockback'}, -- 03:0 Knockback effect, the more value the more distance {ctype='bit[17]', label='Param'}, -- 03:3 {ctype='bit[10]', label='Message'}, -- 06:2 - {ctype='bit[31]', label='_unknown'}, -- 07:4 + {ctype='bit[31]', label='_unknown'}, -- 07:4 Message Modifier: Cover=0x01 Resist!=0x02 Magic Burst=0x03 Immunobreak=0x04 Critical Hit=0x05 } func.incoming[0x028].add_effect_base = L{ @@ -1746,9 +1866,9 @@ fields.incoming[0x029] = L{ 5 = 'Tier 6', --- furiously. Unused currently - But if there are no mobs left in area, or no mobs nearby, field1 will be the KeyItem# 1253 = 'Clear Abyssite' - 1254 = 'Colorful Abyssite' - 1564 = 'Clear Demilune Abyssite' - etc. + 1254 = 'Colorful Abyssite' + 1564 = 'Clear Demilune Abyssite' + etc. Field2 will be direction: 0 = 'East' @@ -1764,9 +1884,9 @@ fields.incoming[0x029] = L{ Field4 will be KI# of the abyssite used. Ex: 1253 = 'Clear Abyssite' - 1254 = 'Colorful Abyssite' - 1564 = 'Clear Demilune Abyssite' - etc. + 1254 = 'Colorful Abyssite' + 1564 = 'Clear Demilune Abyssite' + etc. ]] --[[ 0x2A can also be triggered by buying/disposing of a VWNM KI from an NPC: @@ -1779,8 +1899,8 @@ fields.incoming[0x029] = L{ --[[ 0x2A can also be triggered by spending cruor by buying non-vwnm related items, or even activating/using Flux Field1 will be the amount of cruor spent ]] - - + + --[[ 0x2A can also be triggered by zoning into Abyssea: Field1 will be set to your remaining time. 5 at first, then whatever new value when acquiring visiting status. 0x2A will likely be triggered as well when extending your time limit. Needs verification. @@ -1840,7 +1960,7 @@ fields.incoming[0x030] = L{ -- Synth List / Synth Recipe --[[ This packet is used for list of recipes, but also for details of a specific recipe. - If you ask the guild NPC that provides regular Image Suppor for recipes, + If you ask the guild NPC that provides regular Image Suppor for recipes, s/he will give you a list of recipes, fields are as follows: Field1-2: NPC ID Field3: NPC Index @@ -1850,13 +1970,13 @@ fields.incoming[0x030] = L{ Field24: Usually Item ID of the recipe on next page - If you ask a guild NPC for a specific recipe, fields are as follows: + If you ask a guild NPC for a specific recipe, fields are as follows: field1: item to make (item id) field2,3,4: sub-crafts needed. Note that main craft will not be listed. 1 = woodworking 2 = smithing 3 = goldsmithing - 4 = clothcraft + 4 = clothcraft 5 = leatherworking 6 = bonecraft 7 = Alchemy @@ -1865,10 +1985,10 @@ fields.incoming[0x030] = L{ field6: KeyItem needed, if any (in Big Endian) field7-14: material required (item id) field15-22: qty for each material above. - field23-24: Unknown + field23-24: Unknown ]] fields.incoming[0x031] = L{ - {ctype='unsigned short[24]', label='Field'}, -- 04 + {ctype='unsigned short[24]', label='Field'}, -- 04 } -- NPC Interaction Type 1 @@ -1899,11 +2019,11 @@ fields.incoming[0x033] = L{ -- NPC Interaction Type 2 fields.incoming[0x034] = L{ {ctype='unsigned int', label='NPC', fn=id}, -- 04 - {ctype='data[32]', label='Menu Parameters'}, -- 08 + {ctype='data[32]', label='Menu Parameters'}, -- 08 {ctype='unsigned short', label='NPC Index', fn=index}, -- 28 {ctype='unsigned short', label='Zone', fn=zone}, -- 2A {ctype='unsigned short', label='Menu ID'}, -- 2C Seems to select between menus within a zone - {ctype='unsigned short', label='_unknown1', const=0x08}, -- 2E 08 00 for me, but FFing did nothing + {ctype='unsigned short', label='_unknown1'}, -- 2E Ususually 8, but often not for newer menus {ctype='unsigned short', label='_dupeZone', fn=zone}, -- 30 {ctype='data[2]', label='_junk1'}, -- 31 Always 00s for me } @@ -1961,14 +2081,14 @@ enums.indi = { -- 0x2000 -- No obvious effect -- 0x4000 -- No obvious effect -- 0x8000 -- No obvious effect - + _flags2: -- 0x01 -- POL Icon :: Actually a flag, overrides everything else but does not affect name color -- 0x02 -- No obvious effect -- 0x04 -- Disconnection icon :: Actually a flag, overrides everything but POL Icon -- 0x08 -- No linkshell -- 0x0A -- No obvious effect - + -- 0x10 -- No linkshell -- 0x20 -- Trial account icon -- 0x40 -- Trial account icon @@ -1982,13 +2102,13 @@ enums.indi = { -- Bit 0x80 overpowers those bits -- Bit 0x80 combines with 0x04 and 0x02 to make SGM. -- These are basically flags, but they can be combined to mean different things sometimes. - + _flags3: -- 0x10 -- No obvious effect -- 0x20 -- Event mode? Can't activate the targeting cursor but can still spin the camera -- 0x40 -- No obvious effect -- 0x80 -- Invisible model - + _flags4: -- 0x02 -- No obvious effect -- 0x04 -- No obvious effect @@ -1997,43 +2117,46 @@ enums.indi = { -- 0x20 -- Bazaar icon -- 0x40 -- Event status again? Can't activate the targeting cursor but can move the camera. -- 0x80 -- No obvious effects - + _flags5: -- 0x01 -- No obvious effect -- 0x02 -- No obvious effect -- 0x04 -- Autoinvite icon - + _flags6: -- 0x08 -- Terror flag -- 0x10 -- No obvious effect - - Ballista stuff: + + PvP stuff: -- 0x0020 -- No obvious effect -- 0x0040 -- San d'Oria ballista flag -- 0x0060 -- Bastok ballista flag -- 0x0080 -- Windurst Ballista flag - -- 0x0100 -- Participation icon? + -- 0x00A0 -- Wyverns team icon + -- 0x00C0 -- Gryphons team icon + -- 0x0100 -- Belligerency icon (used in monstrosity) -- 0x0200 -- Has some effect - -- 0x0400 -- I don't know anything about ballista + -- 0x0400 -- Pankration red icon + -- 0x0420 -- Pankration blue icon -- 0x0800 -- and I still don't D:< -- 0x1000 -- and I still don't D:< - + _flags7: -- 0x0020 -- No obvious effect -- 0x0040 -- Individually, this bit has no effect. When combined with 0x20, it prevents you from returning to a walking animation after you stop (sliding along the ground while bound) -- 0x0080 -- No obvious effect - -- 0x0100 -- No obvious effect + -- 0x0100 -- Request icon -- 0x0200 -- Trial Account emblem - -- 0x0400 -- No obvious effect - -- 0x0800 -- Question mark icon + -- 0x0400 -- Sneak Effect + -- 0x0800 -- New Adventurer icon -- 0x1000 -- Mentor icon ]] fields.incoming[0x037] = L{ {ctype='unsigned char[32]', label='Buff', fn=buff}, -- 04 {ctype='unsigned int', label='Player', fn=id}, -- 24 {ctype='unsigned short', label='_flags1'}, -- 28 Called "Flags" on the old dev wiki. Second byte might not be part of the flags, actually. - {ctype='unsigned char', label='HP %', fn=percent}, -- 2A - {ctype='bit[8]', label='_flags2'}, -- 2B + {ctype='unsigned char', label='HP %', fn=percent}, -- 2A + {ctype='bit[8]', label='_flags2'}, -- 2B {ctype='bit[12]', label='Movement Speed/2'}, -- 2C Player movement speed {ctype='bit[4]', label='_flags3'}, -- 2D {ctype='bit[9]', label='Yalms per step'}, -- 2E Determines how quickly your animation walks @@ -2043,20 +2166,36 @@ fields.incoming[0x037] = L{ {ctype='unsigned char', label='LS Color Green'}, -- 32 {ctype='unsigned char', label='LS Color Blue'}, -- 33 {ctype='bit[3]', label='_flags5'}, -- 34 - {ctype='bit[16]', label='Pet Index'}, -- 34 From 0x08 of byte 0x34 to 0x04 of byte 0x36 - {ctype='bit[2]', label='_flags6'}, -- 36 - {ctype='bit[9]', label='Ballista Stuff'}, -- 36 The first few bits seem to determine the icon, but the icon appears to be tied to the type of fight, so it's more than just an icon. - {ctype='bit[8]', label='_flags7'}, -- 37 This is probably tied up in the Ballista stuff too + {ctype='bit[16]', label='Pet Index', fn=index}, -- 34 From 0x08 of byte 0x34 to 0x04 of byte 0x36 + {ctype='bit[2]', label='_flags6'}, -- 36 + {ctype='bit[9]', label='PvP Stuff'}, -- 36 Ballista flags here also makes appear the score, but it is probably modified in a ballista specific packet. + {ctype='bit[8]', label='_flags7'}, -- 37 {ctype='bit[26]', label='_unknown1'}, -- 38 No obvious effect from any of these {ctype='unsigned int', label='Time offset?', fn=time}, -- 3C For me, this is the number of seconds in 66 hours {ctype='unsigned int', label='Timestamp', fn=time}, -- 40 This is 32 years off of JST at the time the packet is sent. - {ctype='data[8]', label='_unknown3'}, -- 44 + {ctype='unsigned short', label='Costume'}, -- 44 ID of the Model + {ctype='data[2]', label='_unknown3'}, -- 46 + {ctype='unsigned short', label='Fellow Index', fn=index}, -- 48 + {ctype='unsigned char', label='Fishing Start Animation'}, -- 4A mostly 0x0D value and sometimes 0x0C observed + {ctype='data[1]', label='_unknown4'}, -- 4B {ctype='data[8]', label='Bit Mask'}, -- 4C - {ctype='data[4]', label='_unknown4'}, -- 54 + {ctype='unsigned short', label='Monstrosity Species'}, -- 54 High bit is always set while in monstrosity and determines the display of the third name + {ctype='unsigned char', label='Monstrosity Name 1'}, -- 56 + {ctype='unsigned char', label='Monstrosity Name 2'}, -- 57 {ctype='bit[7]', label='Indi Buff', fn=e+{'indi'}}, -- 58 - {ctype='bit[9]', label='_unknown5'}, -- 58 - {ctype='unsigned short', label='_junk1'}, -- 5A - {ctype='unsigned int', label='_flags8'}, -- 5C Two least significant bits seem to indicate whether Wardrobes 3 and 4, respectively, are enabled + {ctype='boolbit', label='Job Master Flag'}, -- 58 + {ctype='unsigned char', label='Face Flags'}, -- 59 + {ctype='unsigned char', label='_unknown5'}, -- 5A + {ctype='unsigned char', label='Mount'}, -- 5B Related to Mounts, seems to be mount id + 1, except for chocobo. The value doesn't get zeroed after dismount + {ctype='boolbit', label='Wardrobe 3'}, -- 5C + {ctype='boolbit', label='Wardrobe 4'}, -- 5C + {ctype='bit', label='_unknown6'}, -- 5C + {ctype='boolbit', label='Wardrobe 5'}, -- 5C + {ctype='boolbit', label='Wardrobe 6'}, -- 5C + {ctype='boolbit', label='Wardrobe 7'}, -- 5C + {ctype='boolbit', label='Wardrobe 8'}, -- 5C + {ctype='bit', label='_flags8'}, -- 5C + {ctype='data[3]', label='_junk1'}, -- 5D } -- Entity Animation @@ -2104,19 +2243,19 @@ types.shop_item = L{ -- Shop fields.incoming[0x03C] = L{ - {ctype='unsigned short', label='_zero1', const=0x0000}, -- 04 + {ctype='unsigned short', label='Starting Index'}, -- 04 {ctype='unsigned short', label='_padding1'}, -- 06 {ref=types.shop_item, label='Item', count='*'}, -- 08 - * } --- Price response --- Sent after an outgoing price request for an NPC vendor (0x085) +-- Price/sale response +-- Sent in response to an outgoing price request for an NPC vendor (0x085), and in response to player finalizing a sale. fields.incoming[0x03D] = L{ {ctype='unsigned int', label='Price', fn=gil}, -- 04 - {ctype='unsigned char', label='Inventory Index', fn=invp+{0x09}}, -- 08 - {ctype='unsigned char', label='Bag', fn=bag}, -- 09 + {ctype='unsigned char', label='Inventory Index', fn=inv+{0}}, -- 08 + {ctype='unsigned char', label='Type'}, -- 09 0 = on price check, 1 = when sale is finalized {ctype='unsigned short', label='_junk1'}, -- 0A - {ctype='unsigned int', label='_unknown1', const=1}, -- 0C + {ctype='unsigned int', label='Count'}, -- 0C Will be 1 on price check } -- Open Buy/Sell @@ -2238,8 +2377,9 @@ func.incoming[0x044][0x17] = L{ {ctype='unsigned short', label='Species'}, -- 08 {ctype='unsigned short', label='_unknown2'}, -- 0A {ctype='unsigned short[12]',label='Instinct'}, -- 0C Instinct assignments are based off their position in the equipment list. - {ctype='unsigned short', label='_unknown3'}, -- 24 - {ctype='data[118]', label='_unknown4'}, -- 26 Zeroing everything beyond this point has no notable effect. + {ctype='unsigned char', label='Monstrosity Name 1'}, -- 24 + {ctype='unsigned char', label='Monstrosity Name 2'}, -- 25 + {ctype='data[118]', label='_unknown3'}, -- 26 Zeroing everything beyond this point has no notable effect. } -- Translate Response @@ -2309,7 +2449,7 @@ func.incoming[0x04B].base = L{ {ctype='signed char', label='Delivery Slot'}, -- 06 This goes left to right and then drops down a row and left to right again. Value is 00 through 07 -- 01 if Type is 06, otherwise FF -- 06 Type always seems to come in a pair, this field is only 01 for the first packet - {ctype='signed char', label='_unknown2'}, -- 07 Always FF FF FF FF? + {ctype='signed char', label='_unknown2'}, -- 07 Always FF FF FF FF? {ctype='signed int', label='_unknown3', const=-1}, -- 0C When in a 0x0D/0x0E type, 01 grants request to open inbox/outbox. With FA you get "Please try again later" {ctype='signed char', label='_unknown4'}, -- 0D 02 and 03 observed {ctype='signed char', label='Packet Number'}, -- 0E FF FF observed @@ -2342,6 +2482,7 @@ enums['ah itype'] = { [0x0A] = 'Open menu confirmation', [0x0B] = 'Sell item confirmation', [0x0D] = 'Sales item status', + [0x0E] = 'Purchase item result', } func.incoming[0x04C] = {} @@ -2390,6 +2531,12 @@ enums['sale stat'] = { [0x0B] = 'Not sold', [0x10] = 'Checking', } +enums['buy stat'] = { + [0x01] = 'Success', + [0x02] = 'Placing', + [0xC5] = 'Failed', + [0xE5] = 'Cannot Bid' +} -- 0x0A, 0x0B and 0x0D could probably be combined, the fields seem the same. -- However, they're populated a bit differently. Both 0x0B and 0x0D are sent twice @@ -2451,6 +2598,25 @@ func.incoming[0x04C][0x0D] = L{ {ctype='unsigned int', label='Timestamp', fn=utime}, -- 38 } +func.incoming[0x04C][0x0E] = L{ + {ctype='unsigned char', label='_unknown1'}, -- 05 + {ctype='unsigned char', label='Buy Status', fn=e+{'buy stat'}}, -- 06 + {ctype='unsigned char', label='_unknown2'}, -- 07 + {ctype='unsigned int', label='Price', fn=gil}, -- 08 + {ctype='unsigned short', label='Item ID', fn=item}, -- 0C + {ctype='unsigned short', label='_unknown3'}, -- 0E + {ctype='unsigned short', label='Count'}, -- 10 + {ctype='unsigned int', label='_unknown4'}, -- 12 + {ctype='unsigned short', label='_unknown5'}, -- 16 + {ctype='char[16]', label='Name'}, -- 18 Character name (pending buy only) + {ctype='unsigned short', label='Pending Item ID', fn=item}, -- 28 Only filled out during pending packets + {ctype='unsigned short', label='Pending Count'}, -- 2A Only filled out during pending packets + {ctype='unsigned int', label='Pending Price', fn=gil}, -- 2C Only filled out during pending packets + {ctype='unsigned int', label='_unknown6'}, -- 30 + {ctype='unsigned int', label='_unknown7'}, -- 34 + {ctype='unsigned int', label='Timestamp', fn=utime}, -- 38 Only filled out during pending packets +} + func.incoming[0x04C][0x10] = L{ {ctype='unsigned char', label='_unknown1', const=0x00}, -- 05 {ctype='unsigned char', label='Success', fn=bool}, -- 06 @@ -2518,6 +2684,28 @@ fields.incoming[0x051] = L{ {ctype='unsigned short', label='_unknown1'}, -- 16 May varying meaningfully, but it's unclear } +enums[0x052] = { + [0x00] = 'Standard', + [0x01] = 'Event', + [0x02] = 'Event Skipped', + [0x03] = 'String Event', + [0x04] = 'Fishing', +} + +func.incoming[0x052] = {} +func.incoming[0x052].base = L{ + {ctype='unsigned char', label='Type', fn=e+{0x052}}, -- 04 +} + +func.incoming[0x052][0x02] = L{ + {ctype='unsigned short', label='Menu ID'}, -- 05 +} + +-- NPC Release +fields.incoming[0x052] = function(data, type) + return func.incoming[0x052].base + (func.incoming[0x052][type or data:byte(5)] or L{}) +end + -- Logout Time -- This packet is likely used for an entire class of system messages, -- but the only one commonly encountered is the logout counter. @@ -2537,6 +2725,100 @@ fields.incoming[0x055] = L{ {ctype='unsigned int', label='Type'}, -- 84 Goes from 0 to 5, determines which KI are being sent } +enums.quest_mission_log = { + [0x0030] = 'Completed Campaign Missions', + [0x0038] = 'Completed Campaign Missions (2)', -- Starts at index 256 + [0x0050] = 'Current San d\'Oria Quests', + [0x0058] = 'Current Bastok Quests', + [0x0060] = 'Current Windurst Quests', + [0x0068] = 'Current Jeuno Quests', + [0x0070] = 'Current Other Quests', + [0x0078] = 'Current Outlands Quests', + [0x0080] = 'Current TOAU Quests and Missions (TOAU, WOTG, Assault, Campaign)', + [0x0088] = 'Current WOTG Quests', + [0x0090] = 'Completed San d\'Oria Quests', + [0x0098] = 'Completed Bastok Quests', + [0x00A0] = 'Completed Windurst Quests', + [0x00A8] = 'Completed Jeuno Quests', + [0x00B0] = 'Completed Other Quests', + [0x00B8] = 'Completed Outlands Quests', + [0x00C0] = 'Completed TOAU Quests and Assaults', + [0x00C8] = 'Completed WOTG Quests', + [0x00D0] = 'Completed Missions (Nations, Zilart)', + [0x00D8] = 'Completed Missions (TOAU, WOTG)', + [0x00E0] = 'Current Abyssea Quests', + [0x00E8] = 'Completed Abyssea Quests', + [0x00F0] = 'Current Adoulin Quests', + [0x00F8] = 'Completed Adoulin Quests', + [0x0100] = 'Current Coalition Quests', + [0x0108] = 'Completed Coalition Quests', + [0xFFFE] = 'Current TVR Missions', + [0xFFFF] = 'Current Missions', +} + +-- There are 27 variations of this packet to populate different quest information. +-- Current quests, completed quests, and completed missions (where applicable) are represented by bit flags where the position +-- corresponds to the quest index in the respective DAT. +-- "Current Mission" fields refer to the mission ID, except COP, SOA, and ROV, which represent a mapping of some sort(?) +-- Additionally, COP, SOA, and ROV do not have a "completed" missions packet, they are instead updated with the current mission. +-- Quests will remain in your 'current' list after they are completed unless they are repeatable. + +func.incoming[0x056] = {} +fields.incoming[0x056] = function (data, type) + return (func.incoming[0x056][type or data and data:unpack('H',0x25)] or L{{ctype='data[32]', label='Quest Flags'}}) + func.incoming[0x056].type +end + +func.incoming[0x056].type = L{ + {ctype='unsigned short',label='Type', fn=e+{'quest_mission_log'}} -- 24 +} + +func.incoming[0x056][0x0080] = L{ + {ctype='data[16]', label='Current TOAU Quests'}, -- 04 + {ctype='int', label='Current Assault Mission'}, -- 14 + {ctype='int', label='Current TOAU Mission'}, -- 18 + {ctype='int', label='Current WOTG Mission'}, -- 1C + {ctype='int', label='Current Campaign Mission'}, -- 20 +} + +func.incoming[0x056][0x00C0] = L{ + {ctype='data[16]', label='Completed TOAU Quests'}, -- 04 + {ctype='data[16]', label='Completed Assaults'}, -- 14 +} + +func.incoming[0x056][0x00D0] = L{ + {ctype='data[8]', label='Completed San d\'Oria Missions'}, -- 04 + {ctype='data[8]', label='Completed Bastok Missions'}, -- 0C + {ctype='data[8]', label='Completed Windurst Missions'}, -- 14 + {ctype='data[8]', label='Completed Zilart Missions'}, -- 1C +} + +func.incoming[0x056][0x00D8] = L{ + {ctype='data[8]', label='Completed TOAU Missions'}, -- 04 + {ctype='data[8]', label='Completed WOTG Missions'}, -- 0C + {ctype='data[16]', label='_junk'}, -- 14 +} + +func.incoming[0x056][0xFFFE] = L{ + {ctype='int', label='Current TVR Mission'}, -- 04 + {ctype='data[28]', label='_junk'}, -- 08 +} + +func.incoming[0x056][0xFFFF] = L{ + {ctype='int', label='Nation'}, -- 04 + {ctype='int', label='Current Nation Mission'}, -- 08 + {ctype='int', label='Current ROZ Mission'}, -- 0C + {ctype='int', label='Current COP Mission'}, -- 10 Doesn't correspond directly to DAT + {ctype='int', label='_unknown1'}, -- 14 + {ctype='bit[4]', label='Current ACP Mission'}, -- 18 lower 4 + {ctype='bit[4]', label='Current MKD Mission'}, -- 18 upper 4 + {ctype='bit[4]', label='Current ASA Mission'}, -- 19 lower 4 + {ctype='bit[4]', label='_junk1'}, -- 19 upper 4 + {ctype='short', label='_junk2'}, -- 1A + {ctype='int', label='Current SOA Mission'}, -- 1C Doesn't correspond directly to DAT + {ctype='int', label='Current ROV Mission'}, -- 20 Doesn't correspond directly to DAT +} + + -- Weather Change fields.incoming[0x057] = L{ {ctype='unsigned int', label='Vanadiel Time', fn=vtime}, -- 04 Units of minutes. @@ -2551,6 +2833,27 @@ enums.spawntype = { [0x0A] = 'Self', } +-- Assist Response +fields.incoming[0x058] = L{ + {ctype='unsigned int', label='Player', fn=id}, -- 04 + {ctype='unsigned int', label='Target', fn=id}, -- 08 + {ctype='unsigned short', label='Player Index', fn=index}, -- 0C +} + +-- Emote +fields.incoming[0x05A] = L{ + {ctype='unsigned int', label='Player ID', fn=id}, -- 04 + {ctype='unsigned int', label='Target ID', fn=id}, -- 08 + {ctype='unsigned short', label='Player Index', fn=index}, -- 0C + {ctype='unsigned short', label='Target Index', fn=index}, -- 0E + {ctype='unsigned short', label='Emote', fn=emote}, -- 10 + {ctype='unsigned short', label='_unknown1'}, -- 12 + {ctype='unsigned short', label='_unknown2'}, -- 14 + {ctype='unsigned char', label='Type'}, -- 16 2 for motion, 0 otherwise + {ctype='unsigned char', label='_unknown3'}, -- 17 + {ctype='data[32]', label='_unknown4'}, -- 18 +} + -- Spawn fields.incoming[0x05B] = L{ {ctype='float', label='X'}, -- 04 @@ -2654,7 +2957,7 @@ fields.incoming[0x05E] = L{ {ctype='unsigned char', label="Days to tally"}, -- 8C Number of days to the next conquest tally {ctype='data[3]', label="_unknown4"}, -- 8D All Zeros, and changed nothing when 0xFF'd. {ctype='int', label='Conquest Points'}, -- 90 - {ctype='unsigned char', label="Beastmen region bar"}, -- 94 + {ctype='unsigned char', label="Beastmen region bar"}, -- 94 {ctype='data[12]', label="_unknown5"}, -- 95 Mostly zeros and noticed no change when 0xFF'd. -- These bytes are for the overview summary on the map. @@ -2725,17 +3028,24 @@ fields.incoming[0x061] = L{ {ctype='unsigned short', label='_unknown2'}, -- 4E {ctype='unsigned char', label='Nation'}, -- 50 0 = sandy, 1 = bastok, 2 = windy {ctype='unsigned char', label='_unknown3'}, -- 51 Possibly Unity ID (always 7 for me, I'm in Aldo's unity) - {ctype='unsigned char', label='Su Level'}, -- 52 + {ctype='unsigned char', label='Su Level'}, -- 52 {ctype='unsigned char', label='_unknown4'}, -- 53 Always 00 for me - {ctype='unsigned char', label='Maximum iLevel'}, -- 54 + {ctype='unsigned char', label='Maximum iLevel'}, -- 54 {ctype='unsigned char', label='iLevel over 99'}, -- 55 0x10 would be an iLevel of 115 - {ctype='unsigned char', label='Main Hand iLevel'}, -- 56 + {ctype='unsigned char', label='Main Hand iLevel'}, -- 56 {ctype='unsigned char', label='_unknown5'}, -- 57 Always 00 for me {ctype='bit[5]', label='Unity ID'}, -- 58 0=None, 1=Pieuje, 2=Ayame, 3=Invincible Shield, 4=Apururu, 5=Maat, 6=Aldo, 7=Jakoh Wahcondalo, 8=Naja Salaheem, 9=Flavira - {ctype='bit[5]', label='_unknown5'}, -- 58 Danger, 00ing caused my client to crash - {ctype='bit[16]', label='Unity Points'}, -- 59 - {ctype='bit[6]', label='_unknown6'}, -- 5A No obvious function - {ctype='unsigned int', label='_junk1'}, -- 5B + {ctype='bit[5]', label='Unity Rank'}, -- 58 Danger, 00ing caused my client to crash + {ctype='bit[17]', label='Unity Points'}, -- 59 + {ctype='bit[5]', label='_unknown6'}, -- 5A No obvious function + {ctype='unsigned int', label='_junk1'}, -- 5C + {ctype='unsigned int', label='_junk2'}, -- 60 + {ctype='unsigned char', label='_unknown7'}, -- 64 + {ctype='unsigned char', label='Master Level'}, -- 65 + {ctype='boolbit', label='Master Breaker'}, -- 66 + {ctype='bit[15]', label='_junk3'}, -- 66 + {ctype='unsigned int', label='Current Exemplar Points'}, -- 68 + {ctype='unsigned int', label='Required Exemplar Points'}, -- 6C } types.combat_skill = L{ @@ -2772,7 +3082,14 @@ func.incoming[0x063].base = L{ } func.incoming[0x063][0x02] = L{ - {ctype='data[7]', label='_flags1', fn=bin+{7}}, -- 06 The 3rd bit of the last byte is the flag that indicates whether or not you are xp capped (blue levels) + {ctype='unsigned short', label='_unknown1', const=0x000C}, -- 06 + {ctype='unsigned short', label='Limit Points'}, -- 08 + {ctype='bit[7]', label='Merit Points'}, -- 0A + {ctype='bit[6]', label='Assimilation'}, -- 0A Bonus Blue Magic Points + {ctype='boolbit', label='Limit Breaker'}, -- 0A Level >=75 and have KI + {ctype='boolbit', label='EXP Capped'}, -- 0A + {ctype='boolbit', label='Limit Point Mode'}, -- 0A + {ctype='unsigned char', label='Max Merit Points'}, -- 0C } func.incoming[0x063][0x03] = L{ @@ -2784,8 +3101,8 @@ func.incoming[0x063][0x03] = L{ {ctype='unsigned short', label='_unknown2'}, -- 0E 00 00 {ctype='unsigned short', label='_unknown3'}, -- 10 76 00 {ctype='unsigned short', label='Infamy'}, -- 12 - {ctype='unsigned int', label='_unknown2'}, -- 14 00s - {ctype='unsigned int', label='_unknown3'}, -- 18 00s + {ctype='unsigned int', label='_unknown4'}, -- 14 00s + {ctype='unsigned int', label='_unknown5'}, -- 18 00s {ctype='data[64]', label='Instinct Bitfield 1'}, -- 1C See below -- Bitpacked 2-bit values. 0 = no instincts from that species, 1 == first instinct, 2 == first and second instinct, 3 == first, second, and third instinct. {ctype='data[128]', label='Monster Level Char field'}, -- 5C Mapped onto the item ID for these creatures. (00 doesn't exist, 01 is rabbit, 02 is behemoth, etc.) @@ -2827,8 +3144,8 @@ fields.incoming[0x065] = L{ {ctype='float', label='Y'}, -- 0C {ctype='unsigned int', label='ID', fn=id}, -- 10 {ctype='unsigned short', label='Index', fn=index}, -- 14 - {ctype='unsigned char', label='_unknown1'}, -- 16 1 observed. May indicate repositoning type. - {ctype='unsigned char', label='_unknown2'}, -- 17 Unknown, but matches the same byte of a matching spawn packet + {ctype='unsigned char', label='Animation'}, -- 16 + {ctype='unsigned char', label='Rotation'}, -- 17 {ctype='data[6]', label='_unknown3'}, -- 18 All zeros observed. } @@ -2874,6 +3191,12 @@ fields.incoming[0x068] = L{ {ctype='char*', label='Pet Name'}, -- 18 } +types.synth_skills = L{ + {ctype='bit[6]', label='Skill'}, -- 1A - 1D:0 + {ctype='boolbit', label='Skillup Allowed'}, -- 1A - 1D:6 + {ctype='boolbit', label='Desynth'}, -- 1A - 1D:7 +} + -- Self Synth Result fields.incoming[0x06F] = L{ {ctype='unsigned char', label='Result', fn=e+{'synth'}}, -- 04 @@ -2882,9 +3205,9 @@ fields.incoming[0x06F] = L{ {ctype='unsigned char', label='_junk1'}, -- 07 {ctype='unsigned short', label='Item', fn=item}, -- 08 {ctype='unsigned short[8]', label='Lost Item', fn=item}, -- 0A - {ctype='unsigned char[4]', label='Skill', fn=skill}, -- 1A + {ref=types.synth_skills, count=4}, {ctype='unsigned char[4]', label='Skillup', fn=div+{10}}, -- 1E - {ctype='unsigned short', label='_junk2'}, -- 22 + {ctype='unsigned short', label='Crystal', fn=item}, -- 22 } -- Others Synth Result @@ -2895,19 +3218,53 @@ fields.incoming[0x070] = L{ {ctype='unsigned char', label='_junk1'}, -- 07 {ctype='unsigned short', label='Item', fn=item}, -- 08 {ctype='unsigned short[8]', label='Lost Item', fn=item}, -- 0A - {ctype='unsigned char[4]', label='Skill', fn=skill}, -- 1A Unsure about this + {ref=types.synth_skills, count=4}, {ctype='char*', label='Player Name'}, -- 1E Name of the player } -- Unity Start --- Only observed being used for Unity fights. -fields.incoming[0x075] = L{ +-- Only observed being used for Unity fights. Also observed on DynaD, Odyssey for mask//weapon/neck/izzat progression bars, Escutcheons progression and mandragora minigame. +func.incoming[0x075] = {} +fields.incoming[0x075] = function() + local fields = func.incoming[0x075] + + return function(data, type) + return fields.base + (fields[type] or (data:byte(0x025) > 1 and fields.bars) or fields.default) + end +end() + +enums[0x075] = { + [0] = 'No Timer', + [1] = 'Timer', + [2] = 'Bars', + [3] = 'Timer and Bars', +} + +types.bars = L{ + {ctype='unsigned char', label='Bar Progress'}, -- 28 0xFF if inactive + {ctype='data[3]', label='_unknown4'}, -- 29 Observed 0x000000 if active, 0xFFFFF7 if inactive + {ctype='char[16]', label='Bar String'}, -- 2C Bar 1 for mask/izzat | Bar 2 Main slot | Bar 3 Sub slot | Bar 4 Ranged slot | Bar 5 Neck slot +} + +func.incoming[0x075].base = L{ {ctype='unsigned int', label='Fight Designation'}, -- 04 Anything other than 0 makes a timer. 0 deletes the timer. {ctype='unsigned int', label='Timestamp Offset', fn=time}, -- 08 Number of seconds since 15:00:00 GMT 31/12/2002 (0x3C307D70) {ctype='unsigned int', label='Fight Duration', fn=time}, -- 0C - {ctype='byte[12]', label='_unknown1'}, -- 10 This packet clearly needs position information, but it's unclear how these bytes carry it + {ctype='data[12]', label='_unknown1'}, -- 10 This packet clearly needs position information, but it's unclear how these bytes carry it {ctype='unsigned int', label='Battlefield Radius'}, -- 1C Yalms*1000, so a 50 yalm battlefield would have 50,000 for this field {ctype='unsigned int', label='Render Radius'}, -- 20 Yalms*1000, so a fence that renders when you're 25 yalms away would have 25,000 for this field + {ctype='unsigned char', label='Type', fn=e+{0x075}}, -- 24 most likely a bitflag where first bit activates the timer and bit 2 activates the bars +} + +func.incoming[0x075].default = L{ + {ctype='data[135]', label='_junk1'}, -- 28 Seems to be junk +} + +func.incoming[0x075].bars = L{ + {ctype='unsigned char', label='_unknown2'}, -- 25 + {ctype='unsigned short', label='_unknown3'}, -- 26 Value changes constatly + {ref=types.bars, count=5}, -- 28 + {ctype='data[32]', label='_unknown5'}, -- 8C } -- Party status icon update @@ -2947,7 +3304,7 @@ fields.incoming[0x079] = L{ -- Guild Buy Response -- Sent when buying an item from a guild NPC fields.incoming[0x082] = L{ - {ctype='unsigned short', label='Item', fn=item}, -- 08 + {ctype='unsigned short', label='Item', fn=item}, -- 08 {ctype='unsigned char', label='_junk1'}, -- 0A No obvious purpose {ctype='unsigned char', label='Count'}, -- 0B Number you bought } @@ -2960,20 +3317,28 @@ types.guild_entry = L{ } -- Guild Inv List fields.incoming[0x083] = L{ - {ref=types.guild_entry, label='Item', count='*'}, -- 04 + {ref=types.guild_entry, label='Item', count='30'}, -- 04 + {ctype='unsigned char', label='Item Count'}, -- F4 + {ctype='bit[4]', label='Order'}, -- F5 + {ctype='bit[4]', label='_unknown'}, + {ctype='unsigned short', label='_padding'} -- F6 } -- Guild Sell Response -- Sent when selling an item to a guild NPC fields.incoming[0x084] = L{ - {ctype='unsigned short', label='Item', fn=item}, -- 08 + {ctype='unsigned short', label='Item', fn=item}, -- 08 {ctype='unsigned char', label='_junk1'}, -- 0A No obvious purpose {ctype='unsigned char', label='Count'}, -- 0B Number you bought. If 0, the transaction failed. } -- Guild Sale List fields.incoming[0x085] = L{ - {ref=types.guild_entry, label='Item', count='*'}, -- 04 + {ref=types.guild_entry, label='Item', count='30'}, -- 04 + {ctype='unsigned char', label='Item Count'}, -- F4 + {ctype='bit[4]', label='Order'}, -- F5 + {ctype='bit[4]', label='_unknown'}, + {ctype='unsigned short', label='_padding'} -- F6 } -- Guild Open -- Sent to update guild status or open the guild menu. @@ -3028,7 +3393,7 @@ types.alliance_member = L{ {ctype='unsigned short', label='Index', fn=index}, -- 04 {ctype='unsigned short', label='Flags', fn=bin+{2}}, -- 06 {ctype='unsigned short', label='Zone', fn=zone}, -- 08 - {ctype='unsigned short', label='_unknown2'}, -- 0A Always 0? + {ctype='unsigned short', label='_unknown2'}, -- 0A Always 0? } -- Party Map Marker @@ -3044,6 +3409,16 @@ fields.incoming[0x0A0] = L{ --0x0AA, 0x0AC, and 0x0AE are all bitfields where the lsb indicates whether you have index 0 of the related resource. +-- Moblin Maze Mongers information +-- It appears that they anticipated a substantial expansion of the system, +-- but field sizes here are limited to the available items. +fields.incoming[0x0AD] = L{ + {ctype='bit[16]', label='Maze Vouchers'}, + {ctype='data[6]', label='_junk1'}, + {ctype='bit[128]', label='Maze Runes'}, + {ctype='data[0x68]', label="_junk2"}, +} + -- Help Desk submenu open fields.incoming[0x0B5] = L{ {ctype='data[0x14]', label='_unknown1'}, -- 04 @@ -3096,23 +3471,27 @@ func.incoming[0x0C9][0x01] = L{ {ctype='data[3]', label='_junk1'}, -- 0B {ctype='unsigned char', label='Icon Set Subtype'}, -- 0E 0 = Unopened Linkshell?, 1 = Linkshell, 2 = Pearlsack, 3 = Linkpearl, 4 = Ripped Pearlsack (I think), 5 = Broken Linkpearl? {ctype='unsigned char', label='Icon Set ID'}, -- 0F This identifies the icon set, always 2 for linkshells. - {ctype='bit[4]', label='Linkshell Red'}, -- 10 0xGR, 0x-B - {ctype='bit[4]', label='Linkshell Green'}, -- 10 - {ctype='bit[4]', label='Linkshell Blue'}, -- 11 - {ctype='bit[4]', label='_junk1'}, -- 11 - {ctype='unsigned char', label='Main Job', fn=job}, -- 12 - {ctype='unsigned char', label='Sub Job', fn=job}, -- 13 - {ctype='char[16]', label='Linkshell', enc=ls_name_msg}, -- 14 6-bit packed + {ctype='data[16]', label='Linkshell', enc=ls_enc}, -- 10 6-bit packed + {ctype='bit[4]', label='_junk1'}, -- 20 + {ctype='bit[4]', label='Linkshell Red'}, -- 20 0xGR, 0x-B + {ctype='bit[4]', label='Linkshell Green'}, -- 21 + {ctype='bit[4]', label='Linkshell Blue'}, -- 21 + {ctype='unsigned char', label='_unknown1'}, -- 22 + {ctype='unsigned char', label='Sub Job', fn=job}, -- 23 {ctype='unsigned char', label='Main Job Level'}, -- 24 {ctype='unsigned char', label='Sub Job Level'}, -- 25 - {ctype='data[42]', label='_unknown5'}, -- 26 At least the first two bytes and the last twelve bytes are junk, possibly more + {ctype='unsigned char', label='Main Job', fn=job}, -- 26 + {ctype='unsigned char', label='Master Level'}, -- 27 + {ctype='boolbit', label='Master Breaker'}, -- 28 + {ctype='bit[7]', label='_junk2'}, -- 28 + {ctype='data[43]', label='_unknown5'}, -- 29 At least the first two bytes and the last twelve bytes are junk, possibly more } -- Bazaar Message fields.incoming[0x0CA] = L{ {ctype='char[124]', label='Bazaar Message'}, -- 04 Terminated with a vertical tab {ctype='char[16]', label='Player Name'}, -- 80 - {ctype='unsigned short', label='Player Title ID'}, -- 90 + {ctype='unsigned short', label='Player Title ID'}, -- 90 {ctype='unsigned short', label='_unknown4'}, -- 92 00 00 observed. } @@ -3123,7 +3502,7 @@ fields.incoming[0x0CC] = L{ {ctype='unsigned int', label='Timestamp', fn=time}, -- 88 {ctype='char[16]', label='Player Name'}, -- 8C {ctype='unsigned int', label='Permissions'}, -- 98 - {ctype='char[16]', label='Linkshell', enc=ls_name_msg}, -- 9C 6-bit packed + {ctype='data[15]', label='Linkshell', enc=ls_enc}, -- 9C 6-bit packed } -- Found Item @@ -3187,7 +3566,10 @@ fields.incoming[0x0DD] = L{ {ctype='unsigned char', label='Main job level'}, -- 23 {ctype='unsigned char', label='Sub job', fn=job}, -- 24 {ctype='unsigned char', label='Sub job level'}, -- 25 - {ctype='char*', label='Name'}, -- 26 + {ctype='unsigned char', label='Master Level'}, -- 26 + {ctype='boolbit', label='Master Breaker'}, -- 27 + {ctype='bit[7]', label='_junk2'}, -- 27 + {ctype='char*', label='Name'}, -- 28 } -- Unnamed 0xDE packet @@ -3209,11 +3591,16 @@ fields.incoming[0x0DF] = L{ {ctype='unsigned char', label='MPP', fn=percent}, -- 17 {ctype='unsigned short', label='_unknown1'}, -- 18 {ctype='unsigned short', label='_unknown2'}, -- 1A - {ctype='unsigned int', label='_unknown3'}, -- 1C + {ctype='unsigned short', label='Monstrosity Species'}, -- 1C High bit is always set while in monstrosity and determines the display of the third name + {ctype='unsigned char', label='Monstrosity Name 1'}, -- 1E + {ctype='unsigned char', label='Monstrosity Name 2'}, -- 1F {ctype='unsigned char', label='Main job', fn=job}, -- 20 {ctype='unsigned char', label='Main job level'}, -- 21 {ctype='unsigned char', label='Sub job', fn=job}, -- 22 {ctype='unsigned char', label='Sub job level'}, -- 23 + {ctype='unsigned char', label='Master Level'}, -- 24 + {ctype='boolbit', label='Master Breaker'}, -- 25 + {ctype='bit[7]', label='_junk2'}, -- 25 } -- Unknown packet 0x0E0: I still can't make heads or tails of the content. The packet is always 8 bytes long. @@ -3223,13 +3610,14 @@ fields.incoming[0x0DF] = L{ fields.incoming[0x0E0] = L{ {ctype='unsigned char', label='Linkshell Number'}, -- 04 {ctype='unsigned char', label='Inventory Slot'}, -- 05 - {ctype='unsigned short', label='_junk1'}, -- 06 + {ctype='unsigned char', label='Bag'}, -- 06 + {ctype='unsigned char', label='_junk1'}, -- 07 } -- Party Member List fields.incoming[0x0E1] = L{ {ctype='unsigned short', label='Party ID'}, -- 04 For whatever reason, this is always valid ASCII in my captured packets. - {ctype='unsigned short', label='_unknown1', const=0x0080}, -- 06 Likely contains information about the current chat mode and vote count + {ctype='unsigned short', label='_unknown1', const=0x8000}, -- 06 Likely contains information about the current chat mode and vote count } -- Char Info @@ -3251,14 +3639,6 @@ fields.incoming[0x0E2] = L{ {ctype='char*', label='Name'}, -- 22 * Maybe a base stat } --- Toggle Heal -fields.incoming[0x0E8] = L{ - {ctype='unsigned char', label='Movement'}, -- 04 02 if caused by movement - {ctype='unsigned char', label='_unknown2'}, -- 05 00 observed - {ctype='unsigned char', label='_unknown3'}, -- 06 00 observed - {ctype='unsigned char', label='_unknown4'}, -- 07 00 observed -} - -- Widescan Mob fields.incoming[0x0F4] = L{ {ctype='unsigned short', label='Index', fn=index}, -- 04 @@ -3285,12 +3665,17 @@ fields.incoming[0x0F6] = L{ {ctype='unsigned int', label='Type', fn=e+{'ws mark'}}, -- 04 } +enums['reraise'] = { + [0x01] = 'Raise dialogue', + [0x02] = 'Tractor dialogue', +} + -- Reraise Activation fields.incoming[0x0F9] = L{ {ctype='unsigned int', label='ID', fn=id}, -- 04 {ctype='unsigned short', label='Index', fn=index}, -- 08 - {ctype='unsigned char', label='_unknown1'}, -- 0A - {ctype='unsigned char', label='_unknown2'}, -- 0B + {ctype='unsigned char', label='Category', fn=e+{'reraise'}}, -- 0A + {ctype='unsigned char', label='_unknown1'}, -- 0B } -- Furniture Interaction @@ -3366,8 +3751,7 @@ fields.incoming[0x10B] = L{ -- Sparks update packet fields.incoming[0x110] = L{ - {ctype='unsigned short', label='Sparks Total'}, -- 04 - {ctype='unsigned short', label='_unknown1'}, -- 06 Sparks are currently capped at 50,000 + {ctype='unsigned int', label='Sparks Total'}, -- 04 {ctype='unsigned char', label='Unity (Shared) designator'}, -- 08 Unity (Shared) designator (0=A, 1=B, 2=C, etc.) {ctype='unsigned char', label='Unity (Person) designator '}, -- 09 The game does not distinguish these {ctype='char[6]', label='_unknown2'}, -- 0A Currently all 0xFF'd, never seen it change. @@ -3380,16 +3764,19 @@ types.roe_quest = L{ -- Eminence Update fields.incoming[0x111] = L{ - {ref=types.roe_quest, count=16}, -- 04 + {ref=types.roe_quest, count=30}, -- 04 + {ctype='data[132]', label='_junk'}, -- 7C All 0s observed. Likely reserved in case they decide to expand allowed objectives. + {ctype='bit[12]', label='Limited Time RoE Quest ID'}, -- 100 + {ctype='bit[20]', label='Limited Time RoE Quest Progress'}, -- 101 upper 4 } + -- RoE Quest Log fields.incoming[0x112] = L{ {ctype='data[128]', label='RoE Quest Bitfield'}, -- 04 See next line - -- There's probably one bit to indicate that a quest can be undertaken and another - -- that indicates whether it has been completed once. The meaning of the individual - -- bits obviously varies with Order. RoE quests with storyline are in the Packet - -- with Order == 3. Most normal quests are in Order == 0 + -- Bitpacked quest completion flags. The position of the bit is the quest ID. + -- Data regarding available quests and repeatability is handled client side or + -- somewhere else {ctype='unsigned int', label='Order'}, -- 84 0,1,2,3 } @@ -3453,7 +3840,7 @@ fields.incoming[0x113] = L{ {ctype='signed int', label='Therion Ichor'}, -- A0 {ctype='signed int', label='Allied Notes'}, -- A4 {ctype='unsigned short', label='A.M.A.N. Vouchers Stored'}, -- A8 - {ctype='unsigned short', label='Unity Accolades'}, -- AA + {ctype='unsigned short', label="Login Points"}, -- AA {ctype='signed int', label='Cruor'}, -- AC {ctype='signed int', label='Resistance Credits'}, -- B0 {ctype='signed int', label='Dominion Notes'}, -- B4 @@ -3469,6 +3856,29 @@ fields.incoming[0x113] = L{ {ctype='signed int', label='Voidstones'}, -- C4 {ctype='signed int', label='Kupofried\'s Corundums'}, -- C8 {ctype='unsigned char', label='Moblin Pheromone Sacks'}, -- CC + {ctype='data[1]', label='_unknown2'}, -- CD + {ctype='unsigned char', label="Rems Tale Chapter 1"}, -- CE + {ctype='unsigned char', label="Rems Tale Chapter 2"}, -- CF + {ctype='unsigned char', label="Rems Tale Chapter 3"}, -- D0 + {ctype='unsigned char', label="Rems Tale Chapter 4"}, -- D1 + {ctype='unsigned char', label="Rems Tale Chapter 5"}, -- D2 + {ctype='unsigned char', label="Rems Tale Chapter 6"}, -- D3 + {ctype='unsigned char', label="Rems Tale Chapter 7"}, -- D4 + {ctype='unsigned char', label="Rems Tale Chapter 8"}, -- D5 + {ctype='unsigned char', label="Rems Tale Chapter 9"}, -- D6 + {ctype='unsigned char', label="Rems Tale Chapter 10"}, -- D7 + {ctype='data[8]', label="_unknown3"}, -- D8 + {ctype='signed int', label="Reclamation Marks"}, -- E0 + {ctype='signed int', label='Unity Accolades'}, -- E4 + {ctype='unsigned short', label="Fire Crystals"}, -- E8 + {ctype='unsigned short', label="Ice Crystals"}, -- EA + {ctype='unsigned short', label="Wind Crystals"}, -- EC + {ctype='unsigned short', label="Earth Crystals"}, -- EE + {ctype='unsigned short', label="Lightning Crystals"}, -- E0 + {ctype='unsigned short', label="Water Crystals"}, -- F2 + {ctype='unsigned short', label="Light Crystals"}, -- F4 + {ctype='unsigned short', label="Dark Crystals"}, -- F6 + {ctype='signed int', label="Deeds"}, -- F8 } -- Fish Bite Info @@ -3511,7 +3921,7 @@ fields.incoming[0x118] = L{ {ctype='signed int', label='Bayld'}, -- 04 {ctype='unsigned short', label='Kinetic Units'}, -- 08 {ctype='unsigned char', label='Coalition Imprimaturs'}, -- 0A - {ctype='unsigned char', label='_unknown1'}, -- 0B Currently holds no value + {ctype='unsigned char', label='Mystical Canteens'}, -- 0B {ctype='signed int', label='Obsidian Fragments'}, -- 0C {ctype='unsigned short', label='Lebondopt Wings Stored'}, -- 10 {ctype='unsigned short', label='Pulchridopt Wings Stored'}, -- 12 @@ -3549,7 +3959,60 @@ fields.incoming[0x118] = L{ {ctype='unsigned char', label='Leaforb Stones Stored'}, -- 36 {ctype='unsigned char', label='Leaforb Stones +1 Stored'}, -- 37 {ctype='unsigned char', label='Leaforb Stones +2 Stored'}, -- 38 - {ctype='data[0x0F]', label='_unknown2'}, -- 39 Room for future additions, currently holds no value + {ctype='unsigned char', label='Duskslit Stones Stored'}, -- 39 + {ctype='unsigned char', label='Duskslit Stones +1 Stored'}, -- 3A + {ctype='unsigned char', label='Duskslit Stones +2 Stored'}, -- 3B + {ctype='unsigned char', label='Dusktip Stones Stored'}, -- 3C + {ctype='unsigned char', label='Dusktip Stones +1 Stored'}, -- 3D + {ctype='unsigned char', label='Dusktip Stones +2 Stored'}, -- 3E + {ctype='unsigned char', label='Duskdim Stones Stored'}, -- 3F + {ctype='unsigned char', label='Duskdim Stones +1 Stored'}, -- 40 + {ctype='unsigned char', label='Duskdim Stones +2 Stored'}, -- 41 + {ctype='unsigned char', label='Duskorb Stones Stored'}, -- 42 + {ctype='unsigned char', label='Duskorb Stones +1 Stored'}, -- 43 + {ctype='unsigned char', label='Duskorb Stones +2 Stored'}, -- 44 + {ctype='unsigned char', label='Pellucid Stones Stored'}, -- 45 + {ctype='unsigned char', label='Fern Stones Stored'}, -- 46 + {ctype='unsigned char', label='Taupe Stones Stored'}, -- 47 + {ctype='unsigned short', label='Mellidopt Wings Stored'}, -- 48 + {ctype='unsigned short', label='Escha Beads'}, -- 4A + {ctype='signed int', label='Escha Silt'}, -- 4C + {ctype='signed int', label='Potpourri'}, -- 50 + {ctype='signed int', label='Hallmarks'}, -- 54 + {ctype='signed int', label='Total Hallmarks'}, -- 58 + {ctype='signed int', label='Badges of Gallantry'}, -- 5C + {ctype='signed int', label='Crafter Points'}, -- 60 + {ctype='unsigned char', label='Fire Crystals Set'}, -- 64 + {ctype='unsigned char', label='Ice Crystals Set'}, -- 65 + {ctype='unsigned char', label='Wind Crystals Set'}, -- 66 + {ctype='unsigned char', label='Earth Crystals Set'}, -- 67 + {ctype='unsigned char', label='Lightning Crystals Set'}, -- 68 + {ctype='unsigned char', label='Water Crystals Set'}, -- 69 + {ctype='unsigned char', label='Light Crystals Set'}, -- 6A + {ctype='unsigned char', label='Dark Crystals Set'}, -- 6B + {ctype='unsigned char', label='MC-S-SR01s Set'}, -- 6C + {ctype='unsigned char', label='MC-S-SR02s Set'}, -- 6D + {ctype='unsigned char', label='MC-S-SR03s Set'}, -- 6E + {ctype='unsigned char', label='Liquefaction Spheres Set'}, -- 6F + {ctype='unsigned char', label='Induration Spheres Set'}, -- 70 + {ctype='unsigned char', label='Detonation Spheres Set'}, -- 71 + {ctype='unsigned char', label='Scission Spheres Set'}, -- 72 + {ctype='unsigned char', label='Impaction Spheres Set'}, -- 73 + {ctype='unsigned char', label='Reverberation Spheres Set'}, -- 74 + {ctype='unsigned char', label='Transfixion Spheres Set'}, -- 75 + {ctype='unsigned char', label='Compression Spheres Set'}, -- 76 + {ctype='unsigned char', label='Fusion Spheres Set'}, -- 77 + {ctype='unsigned char', label='Distortion Spheres Set'}, -- 78 + {ctype='unsigned char', label='Fragmentation Spheres Set'}, -- 79 + {ctype='unsigned char', label='Gravitation Spheres Set'}, -- 7A + {ctype='unsigned char', label='Light Spheres Set'}, -- 7B + {ctype='unsigned char', label='Darkness Spheres Set'}, -- 7C + {ctype='data[0x03]', label='_unknown1'}, -- 7D Presumably Unused Padding + {ctype='signed int', label='Silver A.M.A.N. Vouchers Stored'}, -- 80 + {ctype='signed int', label='Domain Points'}, -- 84 + {ctype='signed int', label='Domain Points Earned Today'}, -- 88 + {ctype='signed int', label='Mog Segments'}, -- 8C + {ctype='signed int', label='Gallimaufry'}, -- 90 } types.ability_recast = L{ @@ -3578,3 +4041,4 @@ Redistribution and use in source and binary forms, with or without modification, 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 Windower 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. ]] + diff --git a/addons/libs/queues.lua b/addons/libs/queues.lua index df07940691..4b92370459 100644 --- a/addons/libs/queues.lua +++ b/addons/libs/queues.lua @@ -3,14 +3,18 @@ ]] _libs = _libs or {} -_libs.queues = true -_libs.tables = _libs.tables or require('tables') -_raw = _raw or {} -_raw.table = _raw.table or {} +require('tables') + +local table = _libs.tables local queue = {} +_libs.queues = queue + +_raw = _raw or {} +_raw.table = _raw.table or {} + _meta = _meta or {} _meta.Q = {} _meta.Q.__index = function(q, k) @@ -148,7 +152,7 @@ end _meta.Q.__tostring = queue.tostring --[[ -Copyright (c) 2013, Windower +Copyright © 2013, Windower All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/addons/libs/resources.lua b/addons/libs/resources.lua index b79b1860ee..a33b9cf463 100644 --- a/addons/libs/resources.lua +++ b/addons/libs/resources.lua @@ -3,12 +3,14 @@ ]] _libs = _libs or {} -_libs.resources = true -_libs.functions = _libs.functions or require('functions') -_libs.tables = _libs.tables or require('tables') -_libs.strings = _libs.strings or require('strings') -_libs.files = _libs.files or require('files') -_libs.xml = _libs.xml or require('xml') + +require('functions') +require('tables') +require('strings') + +local functions, table, string = _libs.functions, _libs.tables, _libs.strings +local files = require('files') +local xml = require('xml') local fns = {} @@ -29,6 +31,8 @@ local resources = setmetatable({}, {__index = function(t, k) end end}) +_libs.resources = resources + local redict = { name = language_string, name_log = language_string_log, diff --git a/addons/libs/sets.lua b/addons/libs/sets.lua index e6f6cfd527..01656891e4 100644 --- a/addons/libs/sets.lua +++ b/addons/libs/sets.lua @@ -3,12 +3,18 @@ A library providing sets as a data structure. ]] _libs = _libs or {} -_libs.sets = true -_libs.tables = _libs.tables or require('tables') -_libs.functions = _libs.functions or require('functions') + +require('tables') +require('functions') + +local table, functions = _libs.tables, _libs.functions set = {} +local set = set + +_libs.sets = set + _meta = _meta or {} _meta.S = {} _meta.S.__index = function(s, k) return rawget(set, k) or rawget(table, k) end diff --git a/addons/libs/slips.lua b/addons/libs/slips.lua index bdd9a838e4..81963981ae 100644 --- a/addons/libs/slips.lua +++ b/addons/libs/slips.lua @@ -1,15 +1,21 @@ _libs = _libs or {} -_libs.slips = true -_libs.lists = _libs.lists or require 'lists' + +require('lists') + +local list = _libs.lists +local math = require('math') local slips = {} -slips.default_storages = {'inventory', 'safe', 'storage', 'locker', 'satchel', 'sack', 'case', 'wardrobe', 'safe2'} -slips.storages = L{29312, 29313, 29314, 29315, 29316, 29317, 29318, 29319, 29320, 29321, 29322, 29323, 29324, 29325, 29326, 29327, 29328, 29329, 29330, 29331, 29332, 29333, 29334, 29335, 29336,} +_libs.slips = slips + + +slips.default_storages = {'inventory', 'safe', 'storage', 'locker', 'satchel', 'sack', 'case', 'wardrobe', 'safe2', 'wardrobe2', 'wardrobe3', 'wardrobe4', 'wardrobe5', 'wardrobe6', 'wardrobe7', 'wardrobe8'} +slips.storages = L{29312, 29313, 29314, 29315, 29316, 29317, 29318, 29319, 29320, 29321, 29322, 29323, 29324, 29325, 29326, 29327, 29328, 29329, 29330, 29331, 29332, 29333, 29334, 29335, 29336, 29337, 29338, 29339, 29340, 29341} slips.items = { [slips.storages[1]] = L{16084, 14546, 14961, 15625, 15711, 16085, 14547, 14962, 15626, 15712, 16086, 14548, 14963, 15627, 15713, 16087, 14549, 14964, 15628, 15714, 16088, 14550, 14965, 15629, 15715, 16089, 14551, 14966, 15630, 15716, 16090, 14552, 14967, 15631, 15717, 16091, 14553, 14968, 15632, 15718, 16092, 14554, 14969, 15633, 15719, 16093, 14555, 14970, 15634, 15720, 16094, 14556, 14971, 15635, 15721, 16095, 14557, 14972, 15636, 15722, 16096, 14558, 14973, 15637, 15723, 16097, 14559, 14974, 15638, 15724, 16098, 14560, 14975, 15639, 15725, 16099, 14561, 14976, 15640, 15726, 16100, 14562, 14977, 15641, 15727, 16101, 14563, 14978, 15642, 15728, 16102, 14564, 14979, 15643, 15729, 16103, 14565, 14980, 15644, 15730, 16106, 14568, 14983, 15647, 15733, 16107, 14569, 14984, 15648, 15734, 16108, 14570, 14985, 15649, 15735, 16602, 17741, 18425, 18491, 18588, 18717, 18718, 18850, 18943, 16069, 14530, 14940, 15609, 15695, 16062, 14525, 14933, 15604, 15688, 16064, 14527, 14935, 15606, 15690, 18685, 18065, 17851, 18686, 18025, 18435, 18113, 17951, 17715, 18485, 18408, 18365, 18583, 18417, 18388, 16267, 16268, 16269, 16228, 16229, 15911, 15799, 15800, 15990, 17745, 18121, 16117, 14577, 17857}, -- 168 - [slips.storages[2]] = L{12421, 12549, 12677, 12805, 12933, 13911, 14370, 14061, 14283, 14163, 12429, 12557, 12685, 12813, 12941, 13924, 14371, 14816, 14296, 14175, 13934, 14387, 14821, 14303, 14184, 13935, 14388, 14822, 14304, 14185, 13876, 13787, 14006, 14247, 14123, 13877, 13788, 14007, 14248, 14124, 13908, 14367, 14058, 14280, 14160, 13909, 14368, 14059, 14281, 14161, 16113, 14573, 14995, 15655, 15740, 16115, 14575, 14997, 15657, 15742, 16114, 14574, 14996, 15656, 15741, 16116, 14576, 14998, 15658, 15743, 12818, 18198, 12946, 18043, 12690, 17659, 12296, 12434, 15471, 15472, 15473, 15508, 15509, 15510, 15511, 15512, 15513, 15514, 17710, 17595, 18397, 18360, 18222, 17948, 18100, 15475, 15476, 15477, 15488, 15961, 14815, 14812, 14813, 15244, 15240, 14488, 14905, 15576, 15661, 15241, 14489, 14906, 15577, 15662, 13927, 14378, 14076, 14308, 14180, 13928, 14379, 14077, 14309, 14181, 10438, 10276, 10320, 10326, 10367, 10439, 10277, 10321, 10327, 10368, 10440, 10278, 10322, 10328, 10369, 10441, 10279, 10323, 10329, 10370}, -- 144 - [slips.storages[3]] = L{16155, 11282, 15021, 16341, 11376, 16156, 11283, 15022, 16342, 11377, 16157, 11284, 15023, 16343, 11378, 16148, 14590, 15011, 16317, 15757, 16143, 14591, 15012, 16318, 15758, 16146, 14588, 15009, 16315, 15755, 16147, 14589, 15010, 16316, 15756, 15966, 15967, 19041, 17684, 17685, 11636, 15844, 15934, 16258, 18735, 18734, 16291, 16292, 19042, 15935, 16293, 16294, 15936, 18618, 11588, 11545, 16158, 16159, 16160, 16149, 14583, 15007, 16314, 15751, 16141, 14581, 15005, 16312, 15749, 16142, 14582, 15006, 16313, 15750, 10876, 10450, 10500, 11969, 10600, 10877, 10451, 10501, 11970, 10601, 10878, 10452, 10502, 11971, 10602, 19132, 18551, 11798, 11362, 11363, 11625, 15959, 16259}, -- 97 + [slips.storages[2]] = L{12421, 12549, 12677, 12805, 12933, 13911, 14370, 14061, 14283, 14163, 12429, 12557, 12685, 12813, 12941, 13924, 14371, 14816, 14296, 14175, 13934, 14387, 14821, 14303, 14184, 13935, 14388, 14822, 14304, 14185, 13876, 13787, 14006, 14247, 14123, 13877, 13788, 14007, 14248, 14124, 13908, 14367, 14058, 14280, 14160, 13909, 14368, 14059, 14281, 14161, 16113, 14573, 14995, 15655, 15740, 16115, 14575, 14997, 15657, 15742, 16114, 14574, 14996, 15656, 15741, 16116, 14576, 14998, 15658, 15743, 12818, 18198, 12946, 18043, 12690, 17659, 12296, 12434, 15471, 15472, 15473, 15508, 15509, 15510, 15511, 15512, 15513, 15514, 17710, 17595, 18397, 18360, 18222, 17948, 18100, 15475, 15476, 15477, 15488, 15961, 14815, 14812, 14813, 15244, 15240, 14488, 14905, 15576, 15661, 15241, 14489, 14906, 15577, 15662, 13927, 14378, 14076, 14308, 14180, 13928, 14379, 14077, 14309, 14181, 10438, 10276, 10320, 10326, 10367, 10439, 10277, 10321, 10327, 10368, 10440, 10278, 10322, 10328, 10369, 10441, 10279, 10323, 10329, 10370, 25734, 25735, 25736, 25737, 25738, 25739, 25740, 25741, 25742, 25743, 25744}, -- 155 + [slips.storages[3]] = L{16155, 11282, 15021, 16341, 11376, 16156, 11283, 15022, 16342, 11377, 16157, 11284, 15023, 16343, 11378, 16148, 14590, 15011, 16317, 15757, 16143, 14591, 15012, 16318, 15758, 16146, 14588, 15009, 16315, 15755, 16147, 14589, 15010, 16316, 15756, 15966, 15967, 19041, 17684, 17685, 11636, 15844, 15934, 16258, 18735, 18734, 16291, 16292, 19042, 15935, 16293, 16294, 15936, 18618, 11588, 11545, 16158, 16159, 16160, 16149, 14583, 15007, 16314, 15751, 16141, 14581, 15005, 16312, 15749, 16142, 14582, 15006, 16313, 15750, 10876, 10450, 10500, 11969, 10600, 10877, 10451, 10501, 11970, 10601, 10878, 10452, 10502, 11971, 10602, 19132, 18551, 11798, 11362, 11363, 11625, 15959, 16259, 22299, 26414, 21623, 26219, 21886, 23792, 23793, 23794, 23795, 23796, 22032, 22043, 21530, 22044, 26273, 25415, 25416, 25414, 22050, 22302, 26365}, -- 118 [slips.storages[4]] = L{12511, 12638, 13961, 14214, 14089, 12512, 12639, 13962, 14215, 14090, 13855, 12640, 13963, 14216, 14091, 13856, 12641, 13964, 14217, 14092, 12513, 12642, 13965, 14218, 14093, 12514, 12643, 13966, 14219, 14094, 12515, 12644, 13967, 14220, 14095, 12516, 12645, 13968, 14221, 14096, 12517, 12646, 13969, 14222, 14097, 13857, 12647, 13970, 14223, 14098, 12518, 12648, 13971, 14099, 14224, 13868, 13781, 13972, 14225, 14100, 13869, 13782, 13973, 14226, 14101, 12519, 12649, 13974, 14227, 14102, 12520, 12650, 13975, 14228, 14103, 15265, 14521, 14928, 15600, 15684, 15266, 14522, 14929, 15601, 15685, 15267, 14523, 14930, 15602, 15686, 16138, 14578, 15002, 15659, 15746, 16139, 14579, 15003, 15660, 15747, 16140, 14580, 15004, 16311, 15748, 16678, 17478, 17422, 17423, 16829, 16764, 17643, 16798, 16680, 16766, 17188, 17812, 17771, 17772, 16887, 17532, 17717, 18702, 17858, 19203, 21461, 21124, 20776, 27786, 27926, 28066, 28206, 28346, 27787, 27927, 28067, 28207, 28347}, -- 138 [slips.storages[5]] = L{15225, 14473, 14890, 15561, 15352, 15226, 14474, 14891, 15562, 15353, 15227, 14475, 14892, 15563, 15354, 15228, 14476, 14893, 15564, 15355, 15229, 14477, 14894, 15565, 15356, 15230, 14478, 14895, 15566, 15357, 15231, 14479, 14896, 15567, 15358, 15232, 14480, 14897, 15568, 15359, 15233, 14481, 14898, 15569, 15360, 15234, 14482, 14899, 15570, 15361, 15235, 14483, 14900, 15362, 15571, 15236, 14484, 14901, 15572, 15363, 15237, 14485, 14902, 15573, 15364, 15238, 14486, 14903, 15574, 15365, 15239, 14487, 14904, 15575, 15366, 11464, 11291, 15024, 16345, 11381, 11467, 11294, 15027, 16348, 11384, 11470, 11297, 15030, 16351, 11387, 11475, 11302, 15035, 16357, 11393, 11476, 11303, 15036, 16358, 11394, 11477, 11304, 15037, 16359, 11395}, -- 105 [slips.storages[6]] = L{15072, 15087, 15102, 15117, 15132, 15871, 15073, 15088, 15103, 15118, 15133, 15478, 15074, 15089, 15104, 15119, 15134, 15872, 15075, 15090, 15105, 15120, 15135, 15874, 15076, 15091, 15106, 15121, 15136, 15873, 15077, 15092, 15107, 15122, 15137, 15480, 15078, 15093, 15108, 15123, 15138, 15481, 15079, 15094, 15109, 15124, 15139, 15479, 15080, 15095, 15110, 15125, 15140, 15875, 15081, 15096, 15111, 15126, 15141, 15482, 15082, 15097, 15112, 15127, 15142, 15876, 15083, 15098, 15113, 15128, 15143, 15879, 15084, 15099, 15114, 15129, 15144, 15877, 15085, 15100, 15115, 15130, 15145, 15878, 15086, 15101, 15116, 15131, 15146, 15484, 11465, 11292, 15025, 16346, 11382, 16244, 11468, 11295, 15028, 16349, 11385, 15920, 11471, 11298, 15031, 16352, 11388, 16245, 11478, 11305, 15038, 16360, 11396, 16248, 11480, 11307, 15040, 16362, 11398, 15925}, -- 120 @@ -20,18 +26,23 @@ slips.items = { [slips.storages[11]] = L{15297, 15298, 15299, 15919, 15929, 15921, 18871, 16273, 18166, 18167, 18256, 13216, 13217, 13218, 15455, 15456, 181, 182, 183, 184, 129, 11499, 18502, 18855, 19274, 18763, 19110, 15008, 17764, 19101, 365, 366, 367, 15860, 272, 273, 274, 275, 276, 11853, 11956, 11854, 11957, 11811, 11812, 11861, 11862, 3676, 18879, 3647, 3648, 3649, 3677, 18880, 18863, 18864, 15178, 14519, 10382, 11965, 11967, 15752, 15179, 14520, 10383, 11966, 11968, 15753, 10875, 3619, 3620, 3621, 3650, 3652, 10430, 10251, 10593, 10431, 10252, 10594, 10432, 10253, 10595, 10433, 10254, 10596, 10429, 10250, 17031, 17032, 10807, 18881, 10256, 10330, 10257, 10331, 10258, 10332, 10259, 10333, 10260, 10334, 10261, 10335, 10262, 10336, 10263, 10337, 10264, 10338, 10265, 10339, 10266, 10340, 10267, 10341, 10268, 10342, 10269, 10343, 10270, 10344, 10271, 10345, 10446, 10447, 426, 10808, 3654, 265, 266, 267, 269, 270, 271, 18464, 18545, 18563, 18912, 18913, 10293, 10809, 10810, 10811, 10812, 27803, 28086, 27804, 28087, 27805, 28088, 27806, 28089, 27765, 27911, 27760, 27906, 27759, 28661, 286, 27757, 27758, 287, 27899, 28185, 28324, 27898, 28655, 27756, 28511, 21118, 27902, 100, 21117, 87, 20953, 21280, 28652, 28650, 27726, 28509, 28651, 27727, 28510, 27872, 21113, 27873, 21114, 20532, 20533, 27717, 27718}, -- 192 [slips.storages[12]] = L{2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2718, 2719, 2720, 2721, 2722, 2723, 2724, 2725, 2726, 2727}, -- 100 [slips.storages[13]] = L{10650, 10670, 10690, 10710, 10730, 10651, 10671, 10691, 10711, 10731, 10652, 10672, 10692, 10712, 10732, 10653, 10673, 10693, 10713, 10733, 10654, 10674, 10694, 10714, 10734, 10655, 10675, 10695, 10715, 10735, 10656, 10676, 10696, 10716, 10736, 10657, 10677, 10697, 10717, 10737, 10658, 10678, 10698, 10718, 10738, 10659, 10679, 10699, 10719, 10739, 10660, 10680, 10700, 10720, 10740, 10661, 10681, 10701, 10721, 10741, 10662, 10682, 10702, 10722, 10742, 10663, 10683, 10703, 10723, 10743, 10664, 10684, 10704, 10724, 10744, 10665, 10685, 10705, 10725, 10745, 10666, 10686, 10706, 10726, 10746, 10667, 10687, 10707, 10727, 10747, 10668, 10688, 10708, 10728, 10748, 10669, 10689, 10709, 10729, 10749}, -- 100 - [slips.storages[14]] = L{10901, 10474, 10523, 10554, 10620, 10906, 10479, 10528, 10559, 10625, 10911, 10484, 10533, 10564, 10630, 19799, 18916, 10442, 10280, 16084, 27788, 27928, 28071, 28208, 27649, 27789, 27929, 28072, 28209, 27650, 27790, 27930, 28073, 28210, 27651, 27791, 27931, 28074, 28211, 27652, 27792, 27932, 28075, 28212, 27653, 27793, 27933, 28076, 28213, 27654, 27794, 27934, 28077, 28214, 27655, 27795, 27935, 28078, 28215, 27656, 27796, 27936, 28079, 28216, 27657, 27797, 27937, 28080, 28217, 27658, 27798, 27938, 28081, 28218, 27659, 27799, 27939, 28082, 28219, 27660, 27800, 27940, 28083, 28220, 27661, 27801, 27941, 28084, 28221, 27662, 27802, 27942, 28085, 28222}, -- 94 + [slips.storages[14]] = L{10901, 10474, 10523, 10554, 10620, 10906, 10479, 10528, 10559, 10625, 10911, 10484, 10533, 10564, 10630, 19799, 18916, 10442, 10280, 16084, 27788, 27928, 28071, 28208, 27649, 27789, 27929, 28072, 28209, 27650, 27790, 27930, 28073, 28210, 27651, 27791, 27931, 28074, 28211, 27652, 27792, 27932, 28075, 28212, 27653, 27793, 27933, 28076, 28213, 27654, 27794, 27934, 28077, 28214, 27655, 27795, 27935, 28078, 28215, 27656, 27796, 27936, 28079, 28216, 27657, 27797, 27937, 28080, 28217, 27658, 27798, 27938, 28081, 28218, 27659, 27799, 27939, 28082, 28219, 27660, 27800, 27940, 28083, 28220, 27661, 27801, 27941, 28084, 28221, 27662, 27802, 27942, 28085, 28222, 21510, 21566, 21622, 21665, 21712, 21769, 21822, 21864, 21912, 21976, 22006, 22088, 22133, 22144, 22219, 26413, 23738, 23741, 23744, 23747, 23750, 23739, 23742, 23745, 23748, 23751, 23740, 23743, 23746, 23749, 23752}, -- 125 [slips.storages[15]] = L{27663, 27807, 27943, 28090, 28223, 27664, 27808, 27944, 28091, 28224, 27665, 27809, 27945, 28092, 28225, 27666, 27810, 27946, 28093, 28226, 27667, 27811, 27947, 28094, 28227, 27668, 27812, 27948, 28095, 28228, 27669, 27813, 27949, 28096, 28229, 27670, 27814, 27950, 28097, 28230, 27671, 27815, 27951, 28098, 28231, 27672, 27816, 27952, 28099, 28232, 27673, 27817, 27953, 28100, 28233, 27674, 27818, 27954, 28101, 28234, 27675, 27819, 27955, 28102, 28235, 27676, 27820, 27956, 28103, 28236, 27677, 27821, 27957, 28104, 28237, 27678, 27822, 27958, 28105, 28238, 27679, 27823, 27959, 28106, 28239, 27680, 27824, 27960, 28107, 28240, 27681, 27825, 27961, 28108, 28241, 27682, 27826, 27962, 28109, 28242, 27683, 27827, 27963, 28110, 28243}, -- 105 - [slips.storages[16]] = L{27684, 27828, 27964, 28111, 28244, 27685, 27829, 27965, 28112, 28245, 27686, 27830, 27966, 28113, 28246, 28246, 27831, 27967, 28114, 28247, 27688, 27832, 27968, 28115, 28248, 27689, 27833, 27969, 28116, 28249, 27690, 27834, 27970, 28117, 28250, 27691, 27835, 27971, 28118, 28251, 27692, 27836, 27972, 28119, 28252, 27693, 27837, 27973, 28120, 28253, 27694, 27838, 27974, 28121, 28254, 27695, 27839, 27975, 28122, 28255, 27696, 27840, 27976, 28123, 28256, 27697, 27841, 27977, 28124, 28257, 27698, 27842, 27978, 28125, 28258, 27699, 27843, 27979, 28126, 28259, 27700, 27844, 27980, 28127, 28260, 27701, 27845, 27981, 28128, 28261, 27702, 27846, 27982, 28129, 28262, 27703, 27847, 27983, 28130, 28263, 27704, 27848, 27984, 28131, 28264, 27705, 27849, 27985, 28132, 28265, 27706, 27850, 27986, 28133, 28266}, -- 115 + [slips.storages[16]] = L{27684, 27828, 27964, 28111, 28244, 27685, 27829, 27965, 28112, 28245, 27686, 27830, 27966, 28113, 28246, 27687, 27831, 27967, 28114, 28247, 27688, 27832, 27968, 28115, 28248, 27689, 27833, 27969, 28116, 28249, 27690, 27834, 27970, 28117, 28250, 27691, 27835, 27971, 28118, 28251, 27692, 27836, 27972, 28119, 28252, 27693, 27837, 27973, 28120, 28253, 27694, 27838, 27974, 28121, 28254, 27695, 27839, 27975, 28122, 28255, 27696, 27840, 27976, 28123, 28256, 27697, 27841, 27977, 28124, 28257, 27698, 27842, 27978, 28125, 28258, 27699, 27843, 27979, 28126, 28259, 27700, 27844, 27980, 28127, 28260, 27701, 27845, 27981, 28128, 28261, 27702, 27846, 27982, 28129, 28262, 27703, 27847, 27983, 28130, 28263, 27704, 27848, 27984, 28131, 28264, 27705, 27849, 27985, 28132, 28265, 27706, 27850, 27986, 28133, 28266}, -- 115 [slips.storages[17]] = L{26624, 26800, 26976, 27152, 27328, 26626, 26802, 26978, 27154, 27330, 26628, 26804, 26980, 27156, 27332, 26630, 26806, 26982, 27158, 27334, 26632, 26808, 26984, 27160, 27336, 26634, 26810, 26986, 27162, 27338, 26636, 26812, 26988, 27164, 27340, 26638, 26814, 26990, 27166, 27342, 26640, 26816, 26992, 27168, 27344, 26642, 26818, 26994, 27170, 27346, 26644, 26820, 26996, 27172, 27348, 26646, 26822, 26998, 27174, 27350, 26648, 26824, 27000, 27176, 27352, 26650, 26826, 27002, 27178, 27354, 26652, 26828, 27004, 27180, 27356, 26654, 26830, 27006, 27182, 27358, 26656, 26832, 27008, 27184, 27360, 26658, 26834, 27010, 27186, 27362, 26660, 26836, 27012, 27188, 27364, 26662, 26838, 27014, 27190, 27366, 26664, 26840, 27016, 27192, 27368, 26666, 26842, 27018, 27194, 27370}, -- 110 [slips.storages[18]] = L{26625, 26801, 26977, 27153, 27329, 26627, 26803, 26979, 27155, 27331, 26629, 26805, 26981, 27157, 27333, 26631, 26807, 26983, 27159, 27335, 26633, 26809, 26985, 27161, 27337, 26635, 26811, 26987, 27163, 27339, 26637, 26813, 26989, 27165, 27341, 26639, 26815, 26991, 27167, 27343, 26641, 26817, 26993, 27169, 27345, 26643, 26819, 26995, 27171, 27347, 26645, 26821, 26997, 27173, 27349, 26647, 26823, 26999, 27175, 27351, 26649, 26825, 27001, 27177, 27353, 26651, 26827, 27003, 27179, 27355, 26653, 26829, 27005, 27181, 27357, 26655, 26831, 27007, 27183, 27359, 26657, 26833, 27009, 27185, 27361, 26659, 26835, 27011, 27187, 27363, 26661, 26837, 27013, 27189, 27365, 26663, 26839, 27015, 27191, 27367, 26665, 26841, 27017, 27193, 27369, 26667, 26843, 27019, 27195, 27371}, -- 110 - [slips.storages[19]] = L{27715, 27866, 27716, 27867, 278, 281, 284, 3680, 3681, 27859, 28149, 27860, 28150, 21107, 21108, 27625, 27626, 26693, 26694, 26707, 26708, 27631, 27632, 26705, 26706, 27854, 27855, 26703, 26704, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3695, 21097, 21098, 26717, 26718, 26728,26719,26720,26889,26890, 21095, 21096, 26738, 26739, 26729, 26730, 26788, 26946, 27281, 27455, 26789, 3698, 20713, 20714, 26798, 26954, 26799, 26955, 3706, 26956, 26957, 3705, 26964, 26965, 27291, 26967, 27293, 26966, 27292, 26968, 27294, 21153, 21154, 21086, 21087, 25606, 26974, 27111, 27296, 27467, 25607, 26975, 27112, 27297, 27468, 14195, 14830, 14831, 13945, 13946, 14832, 13947, 17058, 13948, 14400, 14392, 14393, 14394, 14395, 14396, 14397, 14398, 14399, 11337, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 15819, 15820, 15821, 15822, 15823, 15824, 15825, 15826, 3670, 3672, 3661, 3595, 3665, 3668, 3663, 3674, 3667, 191, 28, 153, 151, 198, 202, 142, 134, 137, 340, 341, 334, 335, 337, 339, 336, 342, 338, 3631, 3632, 3625, 3626, 3628, 3630, 3627, 3633, 3629, 25632, 25633, 25604, 25713, 27325, 25714, 27326, 3651, 25711, 25712, 10925, 10948, 10949, 10950, 10951, 10952, 10953, 10954, 10955, 25657, 25756, 25658, 25757}, -- 191 - [slips.storages[20]] = L{26740, 26898, 27052, 27237, 27411, 26742, 26900, 27054, 27239, 27413, 26744, 26902, 27056, 27241, 27415, 26746, 26904, 27058, 27243, 27417, 26748, 26906, 27060, 27245, 27419, 26750, 26908, 27062, 27247, 27421, 26752, 26910, 27064, 27249, 27423, 26754, 26912, 27066, 27251, 27425, 26756, 26914, 27068, 27253, 27427, 26758, 26916, 27070, 27255, 27429, 26760, 26918, 27072, 27257, 27431, 26762, 26920, 27074, 27259, 27433, 26764, 26922, 27076, 27261, 27435, 26766, 26924, 27078, 27263, 27437, 26768, 26926, 27080, 27265, 27439, 26770, 26928, 27082, 27267, 27441, 26772, 26930, 27084, 27269, 27443, 26774, 26932, 27086, 27271, 27445, 26776, 26934, 27088, 27273, 27447, 26778, 26936, 27090, 27275, 27449, 26780, 26938, 27092, 27277, 27451, 26782, 26940, 27094, 27279, 27453,}, -- 110 - [slips.storages[21]] = L{26741, 26899, 27053, 27238, 27412, 26743, 26901, 27055, 27240, 27414, 26745, 26903, 27057, 27242, 27416, 26747, 26905, 27059, 27244, 27418, 26749, 26907, 27061, 27246, 27420, 26751, 26909, 27063, 27248, 27422, 26753, 26911, 27065, 27250, 27424, 26755, 26913, 27067, 27252, 27426, 26757, 26915, 27069, 27254, 27428, 26759, 26917, 27071, 27256, 27430, 26761, 26919, 27073, 27258, 27432, 26763, 26921, 27075, 27260, 27434, 26765, 26923, 27077, 27262, 27436, 26767, 26925, 27079, 27264, 27438, 26769, 26927, 27081, 27266, 27440, 26771, 26929, 27083, 27268, 27442, 26773, 26931, 27085, 27270, 27444, 26775, 26933, 27087, 27272, 27446, 26777, 26935, 27089, 27274, 27448, 26779, 26937, 27091, 27276, 27450, 26781, 26939, 27093, 27278, 27452, 26783, 26941, 27095, 27280, 27454,}, -- 110 - [slips.storages[22]] = L{25639, 25715, 25638, 3707, 3708, 21074, 26406, 25645, 25726, 25648, 25649, 25650, 25758, 25759, 25672, 25673, 282, 279, 280, 268, 25670, 25671, 26520, 25652, 25669, 22017, 22018, 25586, 25587, 10384, 10385, 22019, 22020, 25722, 25585, 25776, 25677, 25678}, -- 38 - [slips.storages[23]] = L{25659, 25745, 25800, 25858, 25925, 25660, 25746, 25801, 25859, 25926, 25663, 25749, 25804, 25862, 25929, 25664, 25750, 25805, 25863, 25930, 25665, 25751, 25806, 25865, 25931, 25666, 25752, 25807, 25866, 25932, 25661, 25747, 25802, 25860, 25927, 25662, 25748, 25803, 25861, 25928, 25667, 25753, 25808, 25867, 25933, 25668, 25754, 25809, 25868, 25934, 25579, 25779, 25818, 25873, 25940,25580,25780,25819,25874,25941, 25590, 25764, 25812, 25871, 25937, 25591, 25765, 25813, 25872, 25938, 25581, 25781, 25820, 25875, 25942, 25582, 25782, 25821, 25876, 25943, 25588, 25589, 25762, 25763, 25810, 25811, 25869, 25870, 25935, 25936, 25583, 25783, 25822, 25877, 25944, 25584, 25784, 25823, 25878, 25945, }, --100 - [slips.storages[24]] = L{23040, 23107, 23174, 23241, 23308, 23041, 23108, 23175, 23241, 23309, 23042, 23109, 23176, 23241, 23310, 23043, 23110, 23177, 23241, 23311, 23044, 23111, 23178, 23241, 23312, 23045, 23112, 23179, 23241, 23313, 23046, 23113, 23180, 23241, 23314, 23047, 23114, 23181, 23241, 23315, 23048, 23115, 23182, 23241, 23316, 23049, 23116, 23183, 23241, 23317, 23050, 23117, 23184, 23241, 23318, 23051, 23118, 23185, 23241, 23319, 23052, 23119, 23186, 23241, 23320, 23053, 23120, 23187, 23241, 23321, 23054, 23121, 23188, 23241, 23322, 23055, 23122, 23189, 23241, 23323, 23056, 23123, 23190, 23241, 23324, 23057, 23124, 23191, 23241, 23325, 23058, 23125, 23192, 23241, 23326, 23059, 23126, 23193, 23241, 23327, 23060, 23127, 23194, 23241, 23328, 23061, 23128, 23195, 23241, 23329, 23062, 23129, 23196, 23241, 23330,}, --115 - [slips.storages[25]] = L{23375, 23442, 23509, 23576, 23643, 23376, 23443, 23510, 23577, 23644, 23377, 23444, 23511, 23578, 23645, 23378, 23445, 23512, 23579, 23646, 23379, 23446, 23513, 23580, 23647, 23380, 23447, 23514, 23581, 23648, 23381, 23448, 23515, 23582, 23649, 23382, 23449, 23516, 23583, 23650, 23383, 23450, 23517, 23584, 23651, 23384, 23451, 23518, 23585, 23652, 23385, 23452, 23519, 23586, 23653, 23386, 23453, 23520, 23587, 23654, 23387, 23454, 23521, 23588, 23655, 23388, 23455, 23522, 23589, 23656, 23389, 23456, 23523, 23590, 23657, 23390, 23457, 23524, 23591, 23658, 23391, 23458, 23525, 23592, 23659, 23392, 23459, 23526, 23593, 23660, 23393, 23460, 23527, 23594, 23661, 23394, 23461, 23528, 23595, 23662, 23395, 23462, 23529, 23596, 23663, 23396, 23463, 23530, 23597, 23664, 23397, 23464, 23531, 23598, 23665,}, --115 + [slips.storages[19]] = L{27715, 27866, 27716, 27867, 278, 281, 284, 3680, 3681, 27859, 28149, 27860, 28150, 21107, 21108, 27625, 27626, 26693, 26694, 26707, 26708, 27631, 27632, 26705, 26706, 27854, 27855, 26703, 26704, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3695, 21097, 21098, 26717, 26718, 26728,26719,26720,26889,26890, 21095, 21096, 26738, 26739, 26729, 26730, 26788, 26946, 27281, 27455, 26789, 3698, 20713, 20714, 26798, 26954, 26799, 26955, 3706, 26956, 26957, 3705, 26964, 26965, 27291, 26967, 27293, 26966, 27292, 26968, 27294, 21153, 21154, 21086, 21087, 25606, 26974, 27111, 27296, 27467, 25607, 26975, 27112, 27297, 27468, 14195, 14830, 14831, 13945, 13946, 14832, 13947, 17058, 13948, 14400, 14392, 14393, 14394, 14395, 14396, 14397, 14398, 14399, 11337, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 15819, 15820, 15821, 15822, 15823, 15824, 15825, 15826, 3670, 3672, 3661, 3595, 3665, 3668, 3663, 3674, 3667, 191, 28, 153, 151, 198, 202, 142, 134, 137, 340, 341, 334, 335, 337, 339, 336, 342, 338, 3631, 3632, 3625, 3626, 3628, 3630, 3627, 3633, 3629, 25632, 25633, 25604, 25713, 27325, 25714, 27326, 3651, 25711, 25712, 10925, 10948, 10949, 10950, 10951, 10952, 10953, 10954, 10955, 25657, 25756, 25658, 25757, 25909}, -- 192 + [slips.storages[20]] = L{26740, 26898, 27052, 27237, 27411, 26742, 26900, 27054, 27239, 27413, 26744, 26902, 27056, 27241, 27415, 26746, 26904, 27058, 27243, 27417, 26748, 26906, 27060, 27245, 27419, 26750, 26908, 27062, 27247, 27421, 26752, 26910, 27064, 27249, 27423, 26754, 26912, 27066, 27251, 27425, 26756, 26914, 27068, 27253, 27427, 26758, 26916, 27070, 27255, 27429, 26760, 26918, 27072, 27257, 27431, 26762, 26920, 27074, 27259, 27433, 26764, 26922, 27076, 27261, 27435, 26766, 26924, 27078, 27263, 27437, 26768, 26926, 27080, 27265, 27439, 26770, 26928, 27082, 27267, 27441, 26772, 26930, 27084, 27269, 27443, 26774, 26932, 27086, 27271, 27445, 26776, 26934, 27088, 27273, 27447, 26778, 26936, 27090, 27275, 27449, 26780, 26938, 27092, 27277, 27451, 26782, 26940, 27094, 27279, 27453}, -- 110 + [slips.storages[21]] = L{26741, 26899, 27053, 27238, 27412, 26743, 26901, 27055, 27240, 27414, 26745, 26903, 27057, 27242, 27416, 26747, 26905, 27059, 27244, 27418, 26749, 26907, 27061, 27246, 27420, 26751, 26909, 27063, 27248, 27422, 26753, 26911, 27065, 27250, 27424, 26755, 26913, 27067, 27252, 27426, 26757, 26915, 27069, 27254, 27428, 26759, 26917, 27071, 27256, 27430, 26761, 26919, 27073, 27258, 27432, 26763, 26921, 27075, 27260, 27434, 26765, 26923, 27077, 27262, 27436, 26767, 26925, 27079, 27264, 27438, 26769, 26927, 27081, 27266, 27440, 26771, 26929, 27083, 27268, 27442, 26773, 26931, 27085, 27270, 27444, 26775, 26933, 27087, 27272, 27446, 26777, 26935, 27089, 27274, 27448, 26779, 26937, 27091, 27276, 27450, 26781, 26939, 27093, 27278, 27452, 26783, 26941, 27095, 27280, 27454}, -- 110 + [slips.storages[22]] = L{25639, 25715, 25638, 3707, 3708, 21074, 26406, 25645, 25726, 25648, 25649, 25650, 25758, 25759, 25672, 25673, 282, 279, 280, 268, 25670, 25671, 26520, 25652, 25669, 22017, 22018, 25586, 25587, 10384, 10385, 22019, 22020, 25722, 25585, 25776, 25677, 25678, 25675, 25679, 20668, 20669, 22069, 25755, 3722, 21608, 3713, 3714, 3715, 3717, 3727, 3728, 20577, 3726, 20666, 20667, 21741, 21609, 3723, 26410, 26411, 25850, 21509, 3725, 3720, 21658, 26524, 20665, 26412, 21965, 21966, 21967, 25774, 25838, 25775, 25839, 3724, 3721, 21682, 22072, 21820, 21821, 23731, 26517, 23730, 20573, 20674, 21742, 21860, 22065, 22039, 22124, 22132, 3719, 3738, 26518, 27623, 21867, 21868, 22283, 26516, 20933, 20578, 20568, 3739, 20569, 20570, 22288, 26352, 23737, 22282, 3740, 0, 26545, 21977, 21978, 3742, 26519, 26514, 26515, 3743, 21636, 23753, 23754, 54, 25910, 20571, 23790, 23791, 26489, 22153, 22154, 20574, 20675, 21743, 21861, 22066, 3748, 21638, 23800, 23801, 3749, 3750, 22045, 22046, 3751, 26490, 26546, 22047, 22048, 22049, 23803, 23804, 22051, 22052, 3752, 23805, 25911, 25912, 3753, 23806, 3754, 23810, 23811, 3755}, -- 164 SE Skipped an index hence the 0 as one of the items + [slips.storages[23]] = L{25659, 25745, 25800, 25858, 25925, 25660, 25746, 25801, 25859, 25926, 25663, 25749, 25804, 25862, 25929, 25664, 25750, 25805, 25863, 25930, 25665, 25751, 25806, 25865, 25931, 25666, 25752, 25807, 25866, 25932, 25661, 25747, 25802, 25860, 25927, 25662, 25748, 25803, 25861, 25928, 25667, 25753, 25808, 25867, 25933, 25668, 25754, 25809, 25868, 25934, 25579, 25779, 25818, 25873, 25940, 25580, 25780, 25819, 25874, 25941, 25590, 25764, 25812, 25871, 25937, 25591, 25765, 25813, 25872, 25938, 25581, 25781, 25820, 25875, 25942, 25582, 25782, 25821, 25876, 25943, 25588, 25762, 25810, 25869, 25935, 25589, 25763, 25811, 25870, 25936, 25583, 25783, 25822, 25877, 25944, 25584, 25784, 25823, 25878, 25945, 25574, 25790, 25828, 25879, 25946, 25575, 25791, 25829, 25880, 25947, 25576, 25792, 25830, 25881, 25948, 25577, 25793, 25831, 25882, 25949, 25578, 25794, 25832, 25883, 25950, 26204, 26205, 26206, 26207, 26208, 25569, 25797, 25835, 25886, 25953, 25573, 25796, 25834, 25885, 25952, 25570, 25798, 25836, 25887, 25954, 25572, 25795, 25833, 25884, 25951, 25571, 25799, 25837, 25888, 25955, 26211, 26210, 26212, 26209, 26213, 21863, 22004, 21744, 21272, 20576, 21761, 26409, 22070, 21681, 22005, 21745, 22068, 21759, 21770, 22067, 21680, 22071}, -- 177 + [slips.storages[24]] = L{23040, 23107, 23174, 23241, 23308, 23041, 23108, 23175, 23242, 23309, 23042, 23109, 23176, 23243, 23310, 23043, 23110, 23177, 23244, 23311, 23044, 23111, 23178, 23245, 23312, 23045, 23112, 23179, 23246, 23313, 23046, 23113, 23180, 23247, 23314, 23047, 23114, 23181, 23248, 23315, 23048, 23115, 23182, 23249, 23316, 23049, 23116, 23183, 23250, 23317, 23050, 23117, 23184, 23251, 23318, 23051, 23118, 23185, 23252, 23319, 23052, 23119, 23186, 23253, 23320, 23053, 23120, 23187, 23254, 23321, 23054, 23121, 23188, 23255, 23322, 23055, 23122, 23189, 23256, 23323, 23056, 23123, 23190, 23257, 23324, 23057, 23124, 23191, 23258, 23325, 23058, 23125, 23192, 23259, 23326, 23059, 23126, 23193, 23260, 23327, 23060, 23127, 23194, 23261, 23328, 23061, 23128, 23195, 23262, 23329, 23062, 23129, 23196, 23263, 23330}, -- 115 + [slips.storages[25]] = L{23375, 23442, 23509, 23576, 23643, 23376, 23443, 23510, 23577, 23644, 23377, 23444, 23511, 23578, 23645, 23378, 23445, 23512, 23579, 23646, 23379, 23446, 23513, 23580, 23647, 23380, 23447, 23514, 23581, 23648, 23381, 23448, 23515, 23582, 23649, 23382, 23449, 23516, 23583, 23650, 23383, 23450, 23517, 23584, 23651, 23384, 23451, 23518, 23585, 23652, 23385, 23452, 23519, 23586, 23653, 23386, 23453, 23520, 23587, 23654, 23387, 23454, 23521, 23588, 23655, 23388, 23455, 23522, 23589, 23656, 23389, 23456, 23523, 23590, 23657, 23390, 23457, 23524, 23591, 23658, 23391, 23458, 23525, 23592, 23659, 23392, 23459, 23526, 23593, 23660, 23393, 23460, 23527, 23594, 23661, 23394, 23461, 23528, 23595, 23662, 23395, 23462, 23529, 23596, 23663, 23396, 23463, 23530, 23597, 23664, 23397, 23464, 23531, 23598, 23665}, -- 115 + [slips.storages[26]] = L{23063, 23130, 23197, 23264, 23331, 23064, 23131, 23198, 23265, 23332, 23065, 23132, 23199, 23266, 23333, 23066, 23133, 23200, 23267, 23334, 23067, 23134, 23201, 23268, 23335, 23068, 23135, 23202, 23269, 23336, 23069, 23136, 23203, 23270, 23337, 23070, 23137, 23204, 23271, 23338, 23071, 23138, 23205, 23272, 23339, 23072, 23139, 23206, 23273, 23340, 23073, 23140, 23207, 23274, 23341, 23074, 23141, 23208, 23275, 23342, 23075, 23142, 23209, 23276, 23343, 23076, 23143, 23210, 23277, 23344, 23077, 23144, 23211, 23278, 23345, 23078, 23145, 23212, 23279, 23346, 23079, 23146, 23213, 23280, 23347, 23080, 23147, 23214, 23281, 23348, 23081, 23148, 23215, 23282, 23349, 23082, 23149, 23216, 23283, 23350, 23083, 23150, 23217, 23284, 23351, 23084, 23151, 23218, 23285, 23352}, -- 110 + [slips.storages[27]] = L{23398, 23465, 23532, 23599, 23666, 23399, 23466, 23533, 23600, 23667, 23400, 23467, 23534, 23601, 23668, 23401, 23468, 23535, 23602, 23669, 23402, 23469, 23536, 23603, 23670, 23403, 23470, 23537, 23604, 23671, 23404, 23471, 23538, 23605, 23672, 23405, 23472, 23539, 23606, 23673, 23406, 23473, 23540, 23607, 23674, 23407, 23474, 23541, 23608, 23675, 23408, 23475, 23542, 23609, 23676, 23409, 23476, 23543, 23610, 23677, 23410, 23477, 23544, 23611, 23678, 23411, 23478, 23545, 23612, 23679, 23412, 23479, 23546, 23613, 23680, 23413, 23480, 23547, 23614, 23681, 23414, 23481, 23548, 23615, 23682, 23415, 23482, 23549, 23616, 23683, 23416, 23483, 23550, 23617, 23684, 23417, 23484, 23551, 23618, 23685, 23418, 23485, 23552, 23619, 23686, 23419, 23486, 23553, 23620, 23687}, -- 110 + [slips.storages[28]] = L{21515, 21561, 21617, 21670, 21718, 21775, 21826, 21879, 21918, 21971, 22027, 22082, 22108, 22214, 21516, 21562, 21618, 21671, 21719, 21776, 21827, 21880, 21919, 21972, 22028, 22083, 22109, 22215, 21517, 21563, 21619, 21672, 21720, 21777, 21828, 21881, 21920, 21973, 22029, 22084, 22110, 22216, 21518, 21564, 21620, 21673, 21721, 21778, 21829, 21882, 21921, 21974, 22030, 22085, 22111, 22217, 21519, 21565, 21621, 21674, 21722, 21779, 21830, 21883, 21922, 21975, 22031, 22086, 22107, 22218, 22089}, --71 + [slips.storages[29]] = L{23085, 23152, 23219, 23286, 23353, 23086, 23153, 23220, 23287, 23354, 23087, 23154, 23221, 23288, 23355, 23088, 23155, 23222, 23289, 23356, 23089, 23156, 23223, 23290, 23357, 23090, 23157, 23224, 23291, 23358, 23091, 23158, 23225, 23292, 23359, 23092, 23159, 23226, 23293, 23360, 23093, 23160, 23227, 23294, 23361, 23094, 23161, 23228, 23295, 23362, 23095, 23162, 23229, 23296, 23363, 23096, 23163, 23230, 23297, 23364, 23097, 23164, 23231, 23298, 23365, 23098, 23165, 23232, 23299, 23366, 23099, 23166, 23233, 23300, 23367, 23100, 23167, 23234, 23301, 23368, 23101, 23168, 23235, 23302, 23369, 23102, 23169, 23236, 23303, 23370, 23103, 23170, 23237, 23304, 23371, 23104, 23171, 23238, 23305, 23372, 23105, 23172, 23239, 23306, 23373, 23106, 23173, 23240, 23307, 23374}, -- 110 + [slips.storages[30]] = L{23420, 23487, 23554, 23621, 23688, 23421, 23488, 23555, 23622, 23689, 23422, 23489, 23556, 23623, 23690, 23423, 23490, 23557, 23624, 23691, 23424, 23491, 23558, 23625, 23692, 23425, 23492, 23559, 23626, 23693, 23426, 23493, 23560, 23627, 23694, 23427, 23494, 23561, 23628, 23695, 23428, 23495, 23562, 23629, 23696, 23429, 23496, 23563, 23630, 23697, 23430, 23497, 23564, 23631, 23698, 23431, 23498, 23565, 23632, 23699, 23432, 23499, 23566, 23633, 23700, 23433, 23500, 23567, 23634, 23701, 23434, 23501, 23568, 23635, 23702, 23435, 23502, 23569, 23636, 23703, 23436, 23503, 23570, 23637, 23704, 23437, 23504, 23571, 23638, 23705, 23438, 23505, 23572, 23639, 23706, 23439, 23506, 23573, 23640, 23707, 23440, 23507, 23574, 23641, 23708, 23441, 23508, 23575, 23642, 23709}, -- 110 } function slips.get_slip_id(n) diff --git a/addons/libs/ssl.lua b/addons/libs/ssl.lua new file mode 100644 index 0000000000..c71ac27af9 --- /dev/null +++ b/addons/libs/ssl.lua @@ -0,0 +1,286 @@ +------------------------------------------------------------------------------ +-- LuaSec 1.0.2 +-- +-- Copyright (C) 2006-2021 Bruno Silvestre +-- +------------------------------------------------------------------------------ + +local core = require("ssl.core") +local context = require("ssl.context") +local x509 = require("ssl.x509") +local config = require("ssl.config") + +local unpack = table.unpack or unpack + +-- We must prevent the contexts to be collected before the connections, +-- otherwise the C registry will be cleared. +local registry = setmetatable({}, {__mode="k"}) + +-- +-- +-- +local function optexec(func, param, ctx) + if param then + if type(param) == "table" then + return func(ctx, unpack(param)) + else + return func(ctx, param) + end + end + return true +end + +-- +-- Convert an array of strings to wire-format +-- +local function array2wireformat(array) + local str = "" + for k, v in ipairs(array) do + if type(v) ~= "string" then return nil end + local len = #v + if len == 0 then + return nil, "invalid ALPN name (empty string)" + elseif len > 255 then + return nil, "invalid ALPN name (length > 255)" + end + str = str .. string.char(len) .. v + end + if str == "" then return nil, "invalid ALPN list (empty)" end + return str +end + +-- +-- Convert wire-string format to array +-- +local function wireformat2array(str) + local i = 1 + local array = {} + while i < #str do + local len = str:byte(i) + array[#array + 1] = str:sub(i + 1, i + len) + i = i + len + 1 + end + return array +end + +-- +-- +-- +local function newcontext(cfg) + local succ, msg, ctx + -- Create the context + ctx, msg = context.create(cfg.protocol) + if not ctx then return nil, msg end + -- Mode + succ, msg = context.setmode(ctx, cfg.mode) + if not succ then return nil, msg end + local certificates = cfg.certificates + if not certificates then + certificates = { + { certificate = cfg.certificate, key = cfg.key, password = cfg.password } + } + end + for _, certificate in ipairs(certificates) do + -- Load the key + if certificate.key then + if certificate.password and + type(certificate.password) ~= "function" and + type(certificate.password) ~= "string" + then + return nil, "invalid password type" + end + succ, msg = context.loadkey(ctx, certificate.key, certificate.password) + if not succ then return nil, msg end + end + -- Load the certificate(s) + if certificate.certificate then + succ, msg = context.loadcert(ctx, certificate.certificate) + if not succ then return nil, msg end + if certificate.key and context.checkkey then + succ = context.checkkey(ctx) + if not succ then return nil, "private key does not match public key" end + end + end + end + -- Load the CA certificates + if cfg.cafile or cfg.capath then + succ, msg = context.locations(ctx, cfg.cafile, cfg.capath) + if not succ then return nil, msg end + end + -- Set SSL ciphers + if cfg.ciphers then + succ, msg = context.setcipher(ctx, cfg.ciphers) + if not succ then return nil, msg end + end + -- Set SSL cipher suites + if cfg.ciphersuites then + succ, msg = context.setciphersuites(ctx, cfg.ciphersuites) + if not succ then return nil, msg end + end + -- Set the verification options + succ, msg = optexec(context.setverify, cfg.verify, ctx) + if not succ then return nil, msg end + -- Set SSL options + succ, msg = optexec(context.setoptions, cfg.options, ctx) + if not succ then return nil, msg end + -- Set the depth for certificate verification + if cfg.depth then + succ, msg = context.setdepth(ctx, cfg.depth) + if not succ then return nil, msg end + end + + -- NOTE: Setting DH parameters and elliptic curves needs to come after + -- setoptions(), in case the user has specified the single_{dh,ecdh}_use + -- options. + + -- Set DH parameters + if cfg.dhparam then + if type(cfg.dhparam) ~= "function" then + return nil, "invalid DH parameter type" + end + context.setdhparam(ctx, cfg.dhparam) + end + + -- Set elliptic curves + if (not config.algorithms.ec) and (cfg.curve or cfg.curveslist) then + return false, "elliptic curves not supported" + end + if config.capabilities.curves_list and cfg.curveslist then + succ, msg = context.setcurveslist(ctx, cfg.curveslist) + if not succ then return nil, msg end + elseif cfg.curve then + succ, msg = context.setcurve(ctx, cfg.curve) + if not succ then return nil, msg end + end + + -- Set extra verification options + if cfg.verifyext and ctx.setverifyext then + succ, msg = optexec(ctx.setverifyext, cfg.verifyext, ctx) + if not succ then return nil, msg end + end + + -- ALPN + if cfg.mode == "server" and cfg.alpn then + if type(cfg.alpn) == "function" then + local alpncb = cfg.alpn + -- This callback function has to return one value only + succ, msg = context.setalpncb(ctx, function(str) + local protocols = alpncb(wireformat2array(str)) + if type(protocols) == "string" then + protocols = { protocols } + elseif type(protocols) ~= "table" then + return nil + end + return (array2wireformat(protocols)) -- use "()" to drop error message + end) + if not succ then return nil, msg end + elseif type(cfg.alpn) == "table" then + local protocols = cfg.alpn + -- check if array is valid before use it + succ, msg = array2wireformat(protocols) + if not succ then return nil, msg end + -- This callback function has to return one value only + succ, msg = context.setalpncb(ctx, function() + return (array2wireformat(protocols)) -- use "()" to drop error message + end) + if not succ then return nil, msg end + else + return nil, "invalid ALPN parameter" + end + elseif cfg.mode == "client" and cfg.alpn then + local alpn + if type(cfg.alpn) == "string" then + alpn, msg = array2wireformat({ cfg.alpn }) + elseif type(cfg.alpn) == "table" then + alpn, msg = array2wireformat(cfg.alpn) + else + return nil, "invalid ALPN parameter" + end + if not alpn then return nil, msg end + succ, msg = context.setalpn(ctx, alpn) + if not succ then return nil, msg end + end + + if config.capabilities.dane and cfg.dane then + if type(cfg.dane) == "table" then + context.setdane(ctx, unpack(cfg.dane)) + else + context.setdane(ctx) + end + end + + return ctx +end + +-- +-- +-- +local function wrap(sock, cfg) + local ctx, msg + if type(cfg) == "table" then + ctx, msg = newcontext(cfg) + if not ctx then return nil, msg end + else + ctx = cfg + end + local s, msg = core.create(ctx) + if s then + core.setfd(s, sock:getfd()) + sock:setfd(core.SOCKET_INVALID) + registry[s] = ctx + return s + end + return nil, msg +end + +-- +-- Extract connection information. +-- +local function info(ssl, field) + local str, comp, err, protocol + comp, err = core.compression(ssl) + if err then + return comp, err + end + -- Avoid parser + if field == "compression" then + return comp + end + local info = {compression = comp} + str, info.bits, info.algbits, protocol = core.info(ssl) + if str then + info.cipher, info.protocol, info.key, + info.authentication, info.encryption, info.mac = + string.match(str, + "^(%S+)%s+(%S+)%s+Kx=(%S+)%s+Au=(%S+)%s+Enc=(%S+)%s+Mac=(%S+)") + info.export = (string.match(str, "%sexport%s*$") ~= nil) + end + if protocol then + info.protocol = protocol + end + if field then + return info[field] + end + -- Empty? + return ( (next(info)) and info ) +end + +-- +-- Set method for SSL connections. +-- +core.setmethod("info", info) + +-------------------------------------------------------------------------------- +-- Export module +-- + +local _M = { + _VERSION = "1.0.2", + _COPYRIGHT = core.copyright(), + config = config, + loadcertificate = x509.load, + newcontext = newcontext, + wrap = wrap, +} + +return _M diff --git a/addons/libs/ssl/https.lua b/addons/libs/ssl/https.lua new file mode 100644 index 0000000000..21bf530bfd --- /dev/null +++ b/addons/libs/ssl/https.lua @@ -0,0 +1,146 @@ +---------------------------------------------------------------------------- +-- LuaSec 1.0.2 +-- Copyright (C) 2009-2021 PUC-Rio +-- +-- Author: Pablo Musa +-- Author: Tomas Guisasola +--------------------------------------------------------------------------- + +local socket = require("socket") +local ssl = require("ssl") +local ltn12 = require("ltn12") +local http = require("socket.http") +local url = require("socket.url") + +local try = socket.try + +-- +-- Module +-- +local _M = { + _VERSION = "1.0.2", + _COPYRIGHT = "LuaSec 1.0.2 - Copyright (C) 2009-2021 PUC-Rio", + PORT = 443, + TIMEOUT = 60 +} + +-- TLS configuration +local cfg = { + protocol = "any", + options = {"all", "no_sslv2", "no_sslv3", "no_tlsv1"}, + verify = "none", +} + +-------------------------------------------------------------------- +-- Auxiliar Functions +-------------------------------------------------------------------- + +-- Insert default HTTPS port. +local function default_https_port(u) + return url.build(url.parse(u, {port = _M.PORT})) +end + +-- Convert an URL to a table according to Luasocket needs. +local function urlstring_totable(url, body, result_table) + url = { + url = default_https_port(url), + method = body and "POST" or "GET", + sink = ltn12.sink.table(result_table) + } + if body then + url.source = ltn12.source.string(body) + url.headers = { + ["content-length"] = #body, + ["content-type"] = "application/x-www-form-urlencoded", + } + end + return url +end + +-- Forward calls to the real connection object. +local function reg(conn) + local mt = getmetatable(conn.sock).__index + for name, method in pairs(mt) do + if type(method) == "function" then + conn[name] = function (self, ...) + return method(self.sock, ...) + end + end + end +end + +-- Return a function which performs the SSL/TLS connection. +local function tcp(params) + params = params or {} + -- Default settings + for k, v in pairs(cfg) do + params[k] = params[k] or v + end + -- Force client mode + params.mode = "client" + -- 'create' function for LuaSocket + return function () + local conn = {} + conn.sock = try(socket.tcp()) + local st = getmetatable(conn.sock).__index.settimeout + function conn:settimeout(...) + return st(self.sock, _M.TIMEOUT) + end + -- Replace TCP's connection function + function conn:connect(host, port) + try(self.sock:connect(host, port)) + self.sock = try(ssl.wrap(self.sock, params)) + self.sock:sni(host) + self.sock:settimeout(_M.TIMEOUT) + try(self.sock:dohandshake()) + reg(self, getmetatable(self.sock)) + return 1 + end + return conn + end +end + +-------------------------------------------------------------------- +-- Main Function +-------------------------------------------------------------------- + +-- Make a HTTP request over secure connection. This function receives +-- the same parameters of LuaSocket's HTTP module (except 'proxy' and +-- 'redirect') plus LuaSec parameters. +-- +-- @param url mandatory (string or table) +-- @param body optional (string) +-- @return (string if url == string or 1), code, headers, status +-- +local function request(url, body) + local result_table = {} + local stringrequest = type(url) == "string" + if stringrequest then + url = urlstring_totable(url, body, result_table) + else + url.url = default_https_port(url.url) + end + if http.PROXY or url.proxy then + return nil, "proxy not supported" + elseif url.redirect then + return nil, "redirect not supported" + elseif url.create then + return nil, "create function not permitted" + end + -- New 'create' function to establish a secure connection + url.create = tcp(url) + local res, code, headers, status = http.request(url) + if res and stringrequest then + return table.concat(result_table), code, headers, status + end + return res, code, headers, status +end + +-------------------------------------------------------------------------------- +-- Export module +-- + +_M.request = request +_M.tcp = tcp + +return _M diff --git a/addons/libs/strings.lua b/addons/libs/strings.lua index 61ea0ea9aa..cd7ac1e202 100644 --- a/addons/libs/strings.lua +++ b/addons/libs/strings.lua @@ -3,9 +3,16 @@ ]] _libs = _libs or {} -_libs.strings = true -_libs.functions = _libs.functions or require('functions') -_libs.math = _libs.math or require('maths') + +require('functions') +require('maths') + +local functions, math = _libs.functions, _libs.maths +local table = require('table') + +local string = require('string') + +_libs.strings = string _meta = _meta or {} @@ -34,8 +41,7 @@ function string.psplit(str, sep, maxsplit, include) return str:split(sep, maxsplit, include, false) end --- Splits a string into a table by a separator string. -function string.split(str, sep, maxsplit, include, raw) +local rawsplit = function(str, sep, maxsplit, include, raw) if not sep or sep == '' then local res = {} local key = 0 @@ -44,12 +50,7 @@ function string.split(str, sep, maxsplit, include, raw) res[key] = c end - if _meta.L then - res.n = key - return setmetatable(res, _meta.L) - end - - return setmetatable(res, _meta.T and _meta.T or nil) + return res, key end maxsplit = maxsplit or 0 @@ -91,12 +92,23 @@ function string.split(str, sep, maxsplit, include, raw) end end + return res, key +end + +-- Splits a string into a table by a separator string. +function string.split(str, sep, maxsplit, include, raw) + local res, key = rawsplit(str, sep, maxsplit, include, raw) + if _meta.L then res.n = key return setmetatable(res, _meta.L) end - return setmetatable(res, _meta.T and _meta.T or nil) + if _meta.T then + return setmetatable(res, _meta.T) + end + + return res end -- Alias to string.sub, with some syntactic sugar. @@ -182,12 +194,12 @@ function string.capitalize(str) return table.concat(res, ' ') end --- Takes a padding character pad and pads the string str to the left of it, until len is reached. pad defaults to a space. +-- Takes a padding character pad and pads the string str to the left of it, until len is reached. function string.lpad(str, pad, len) return (pad:rep(len) .. str):sub(-(len > #str and len or #str)) end --- Takes a padding character pad and pads the string str to the right of it, until len is reached. pad defaults to a space. +-- Takes a padding character pad and pads the string str to the right of it, until len is reached. function string.rpad(str, pad, len) return (str .. pad:rep(len)):sub(1, len > #str and len or #str) end @@ -418,22 +430,19 @@ function string.chunks(str, size) end end --- Returns a string decoded given the appropriate information. -string.decode = (function() - local chunk_size = function(t) - local e, f = math.frexp(#t) - return f + math.ceil(e - 1.5) - end +-- Returns a string decoded given the appropriate encoding. +string.decode = function(str, encoding) + return (str:binary():chunks(encoding.bits):map(table.get+{encoding.charset} .. tonumber-{2}):concat():gsub('%z.*$', '')) +end - return function(str, charset) - if type(charset) == 'string' then - local tmp = charset - charset = charset:sub(2):split() - charset[0] = charset:sub(1, 1) - end - return str:binary():chunks(chunk_size(charset)):map(table.get+{charset} .. tonumber-{2}):concat():gsub('%z+$', '') +-- Returns a string encoded given the appropriate encoding. +string.encode = function(str, encoding) + local binary = str:map(string.zfill-{encoding.bits} .. math.binary .. table.find+{encoding.charset}) + if encoding.terminator then + binary = binary .. encoding.terminator(str) end -end)() + return binary:rpad('0', (#binary / 8):ceil() * 8):parse_binary() +end -- Returns a plural version of a string, if the provided table contains more than one element. -- Defaults to appending an s, but accepts an option string as second argument which it will the string with. diff --git a/addons/libs/tables.lua b/addons/libs/tables.lua index 2df3115df0..644b33cb26 100644 --- a/addons/libs/tables.lua +++ b/addons/libs/tables.lua @@ -7,9 +7,15 @@ ]] _libs = _libs or {} -_libs.tables = true -_libs.maths = _libs.maths or require('maths') -_libs.functions = _libs.functions or require('functions') + +require('maths') +require('functions') + +local math, functions = _libs.maths, _libs.functions + +local table = require('table') + +_libs.tables = table _raw = _raw or {} _raw.table = setmetatable(_raw.table or {}, {__index = table}) @@ -140,10 +146,10 @@ end -- Appends an array table to the end of another array table. function table.extend(t, t_extend) if type(t_extend) ~= 'table' then - return t:append(t_extend) + return table.append(t, t_extend) end for _, val in ipairs(t_extend) do - t:append(val) + table.append(t, val) end return t @@ -262,7 +268,7 @@ function table.flatten(t, recursive) local res = {} local key = 1 local flat = {} - for key, val in ipairs(t) do + for _, val in ipairs(t) do if type(val) == 'table' then if recursive then flat = table.flatten(val, recursive) @@ -468,6 +474,10 @@ function table.unpack(t, ...) return unpack(temp) end +function table.pack(...) + return {...} +end + -- Returns the values of the table, extracted into an argument list. Like unpack, but works on dictionaries as well. function table.extract(t) local res = {} @@ -557,8 +567,8 @@ function table.concat(t, delim, from, to) end -- Concatenates all elements with a whitespace in between. -function table.sconcat(t) - return table.concat(t, ' ') +function table.sconcat(t, ...) + return table.concat(t, ' ', ...) end -- Check if table is empty. @@ -577,7 +587,7 @@ function table.empty(t, rec) end end end - + return true end diff --git a/addons/libs/texts.lua b/addons/libs/texts.lua index 9fe56ab87f..d040b63804 100644 --- a/addons/libs/texts.lua +++ b/addons/libs/texts.lua @@ -2,6 +2,9 @@ A library to facilitate text primitive creation and manipulation. ]] +local table = require('table') +local math = require('math') + local texts = {} local meta = {} @@ -570,6 +573,14 @@ function texts.stroke_alpha(t, alpha) meta[t].settings.text.stroke.alpha = alpha end +function texts.draggable(t, draggable) + if draggable == nil then + return meta[t].settings.flags.draggable + end + + meta[t].settings.flags.draggable = draggable +end + -- Returns true if the coordinates are currently over the text object function texts.hover(t, x, y) if not t:visible() then diff --git a/addons/libs/timeit.lua b/addons/libs/timeit.lua index 4602941055..096510a8dc 100644 --- a/addons/libs/timeit.lua +++ b/addons/libs/timeit.lua @@ -2,9 +2,18 @@ A library providing a timing feature. ]] +_libs = _libs or {} + +require('functions') +require('tables') + +local functions, table = _libs.functions, _libs.tables +local string = require('string') +local math = require('math') +local logger = require('logger') + local timeit = {} -_libs = _libs or {} _libs.timeit = timeit -- Creates a new timer object. @@ -39,10 +48,6 @@ end -- Returns the normalized time in seconds it took to perform the provided functions rep number of times, with the specified arguments. function timeit.benchmark(rep, ...) - _libs.functions = _libs.functions or require 'functions' - _libs.tables = _libs.tables or require 'tables' - _libs.logger = _libs.logger or require 'logger' - local args = T{...} if type(rep) == 'function' then args:insert(1, rep) @@ -103,7 +108,7 @@ end return timeit --[[ -Copyright (c) 2013, Windower +Copyright © 2013, Windower All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/addons/libs/vectors.lua b/addons/libs/vectors.lua index 7198192624..db19dcb508 100644 --- a/addons/libs/vectors.lua +++ b/addons/libs/vectors.lua @@ -3,12 +3,16 @@ Vectors for operations in a d-dimensional space. ]] _libs = _libs or {} -_libs.vectors = true -_libs.tables = _libs.tables or require('tables') -_libs.maths = _libs.maths or require('maths') + +require('tables') +require('maths') + +local table, math = _libs.tables, _libs.maths vector = {} +_libs.vectors = vector + _meta = _meta or {} _meta.V = {} _meta.V.__index = vector diff --git a/addons/libs/xml.lua b/addons/libs/xml.lua index 6c91b48541..fc5c9bc45f 100644 --- a/addons/libs/xml.lua +++ b/addons/libs/xml.lua @@ -2,15 +2,19 @@ Small implementation of a fully-featured XML reader. ]] +_libs = _libs or {} + +require('tables') +require('lists') +require('sets') +require('strings') + +local table, list, set, string = _libs.tables, _libs.lists, _libs.sets, _libs.strings +local files = require('files') + local xml = {} -_libs = _libs or {} _libs.xml = xml -_libs.tables = _libs.tables or require('tables') -_libs.lists = _libs.lists or require('lists') -_libs.sets = _libs.sets or require('sets') -_libs.strings = _libs.strings or require('strings') -_libs.files = _libs.files or require('files') -- Local functions local entity_unescape @@ -36,7 +40,7 @@ local escapes = T{ ['&'] = 'amp', ['>'] = 'gt', ['<'] = 'lt', - ['"'] = 'quote', + ['"'] = 'quot', ['\''] = 'apos' } @@ -563,7 +567,7 @@ function table.to_xml(t, indentlevel) end if type(val) == 'table' and next(val) then str = str..indent..'<'..key..'>\n' - str = str..table.to_xml(val, indentlevel + 1)..'\n' + str = str..table.to_xml(val, indentlevel + 1) str = str..indent..'\n' else if type(val) == 'table' then @@ -579,7 +583,7 @@ end return xml --[[ -Copyright (c) 2013, Windower +Copyright © 2013, Windower All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/addons/linker/linker.lua b/addons/linker/linker.lua index e274cc2311..13e6d407e4 100644 --- a/addons/linker/linker.lua +++ b/addons/linker/linker.lua @@ -1,4 +1,5 @@ require('luau') +local url = require('socket.url') _addon.name = 'Linker' _addon.author = 'Arcon' @@ -39,7 +40,7 @@ defaults.search.db = 'http://ffxidb.com/search?q=${query}' defaults.search.ah = 'http://ffxiah.com/search/item?q=${query}' defaults.search.bg = 'http://wiki.bluegartr.com/index.php?title=Special:Search&search=${query}' defaults.search.ge = 'http://ffxi.gamerescape.com/wiki/Special:Search?search=${query}' -defaults.search.wikia = 'http://wiki.ffxiclopedia.org/wiki/index.php?search=${query}&fulltext=Search' +defaults.search.wikia = 'https://ffxiclopedia.fandom.com/wiki/Special:Search?query=${query}' -- Miscallenous sites defaults.search.g = 'http://google.com/?q=${query}' @@ -53,7 +54,9 @@ windower.register_event('addon command', function(command, ...) if not ... or not settings.search[command] and settings.raw[command] then windower.open_url(settings.raw[command]) elseif settings.search[command] then - windower.open_url((settings.search[command]:gsub('${query}', L{...}:concat(' ')))) + local query_string = url.escape(L{...}:concat(' ')) + local adjusted_query_string = query_string:gsub('%%', '%%%%') + windower.open_url((settings.search[command]:gsub('${query}', adjusted_query_string))) else error('Command "' .. command .. '" not found.') end diff --git a/addons/linuxfix/linuxfix.lua b/addons/linuxfix/linuxfix.lua new file mode 100644 index 0000000000..bc29feeded --- /dev/null +++ b/addons/linuxfix/linuxfix.lua @@ -0,0 +1,143 @@ +_addon.name = 'linuxfix' +_addon.version = '0.5.0' +_addon.author = 'Rubenator,Surik,BeYoNDLiFe' + +--[[ + Do not bother using this if you are on Windows. + + This addon will need to be autoloaded via your init. + + This code has only been tested with fairly standard en-US keyboards. + + This addon restores full keyboard functionality in Windower with newer versions of Wine and bypasses the need to build your own version of Wine with a specific commit reverted. + It also remaps Windows key bindings and makes them functional again with the exception of bindings with multiple modifiers such as %^!1 (Ctrl+Super+Alt+1). The listbinds command is only capable of returning a single modifier and thus they cannot be remapped correctly. + It reads and parses the content of the 'listbinds' command anytime it runs and forwards the keys as appropriate to the client. It also hides the output of this command to avoid console spam. + It's not a fix since it doesn't actually repair the original issue of the keybinds using raw keyboard input but it does work nicely as a workaround. + + When there are a left and right version of a key such as lctrl and rctrl windower sends the lctrl dik even when the right key has been pressed. This also applies to enter and numpadenter. + While the correct keys are in the table below, windower will just use the left version. + + For lack of a better method of keeping the keybinds up to date, the list is refreshed every time you press a key. This was done because Gearswap files frequently rebind keys between jobs. + Since this caused significant lag, a limit was placed so it could not run more than once per second. This limit can be modified using the 'check_rate' variable. + The binds are also now added to a table and don't have to be parsed everytime you press a key which has reduced overhead as well. + + Big shoutout and thanks to Rubenator, he took the awful code Surik and BeYoNDLiFe gave him and made it so much better. +]]-- + +check_rate = 1 + +require('luau') +mods = S{} +keybinds = {} +last_state = T{} +local dik_lookup = T{[-1]='sysrq', [1]='escape', [2]='1', [3]='2', [4]='3', [5]='4', [6]='5', [7]='6', [8]='7', [9]='8', [10]='9', [11]='0', [12]='-', [13]='=', [14]='backspace', [15]='tab', [16]='q', [17]='w', [18]='e', [19]='r', [20]='t', [21]='y', [22]='u', [23]='i', [24]='o', [25]='p', [26]='[', [27]=']', [28]='enter', [30]='a', [31]='s', [32]='d', [33]='f', [34]='g', [35]='h', [36]='j', [37]='k', [38]='l', [39]="\\;", [40]="'", [41]='`', [43]='\\\\', [44]='z', [45]='x', [46]='c', [47]='v', [48]='b', [49]='n', [50]='m', [51]=',', [52]='.', [53]='/', [54]='rshift', [55]='numpad*', [57]='space', [58]='capslock', [59]='f1', [60]='f2', [61]='f3', [62]='f4', [63]='f5', [64]='f6', [65]='f7', [66]='f8', [67]='f9', [68]='f10', [69]='numlock', [70]='scrolllock', [71]='numpad7', [72]='numpad8', [73]='numpad9', [74]='numpad-', [75]='numpad4', [76]='numpad5', [77]='numpad6', [78]='numpad+', [79]='numpad1', [80]='numpad2', [81]='numpad3', [82]='numpad0', [83]='numpad.', [86]='oem_102', [87]='f11', [88]='f12', [100]='f13', [101]='f14', [102]='f15', [112]='kana', [115]='abnt_c1', [121]='convert', [123]='noconvert', [125]='yen', [126]='abnt_c2', [141]='numpadequals', [145]='at', [146]='colon', [147]='underline', [148]='kanji', [149]='stop', [150]='ax', [151]='unlabeled', [153]='nexttrack', [156]='numpadenter', [157]='rctrl', [160]='mute', [161]='calculator', [162]='playpause', [164]='mediastop', [174]='volumedown', [176]='volumeup', [178]='webhome', [179]='numpadcomma', [181]='numpad/', [183]='sysrq', [184]='rmenu', [197]='pause', [199]='home', [200]='up', [201]='pageup', [203]='left', [205]='right', [207]='end', [208]='down', [209]='pagedown', [210]='insert', [211]='delete', [220]='rwin', [222]='power', [223]='sleep', [227]='wake', [229]='websearch', [230]='webfavorites', [231]='webrefresh', [232]='webstop', [233]='', [234]='webback', [235]='mycomputer', [236]='mail', [237]='mediaselect'} +local mod_lookup = T{[29]='Ctrl', [42]='Shift', [56]='Alt', [219]='Win', [221]='Apps'} +key_lookup = T{} +name_lookup = T{} +last_update = nil +do + key_lookup:update(dik_lookup:map(function(name) return {name=name} end)) + key_lookup:update(mod_lookup:map(function(name) return {name=name, mod=true} end)) + for dik, data in pairs(key_lookup) do + name_lookup[data.name] = {mod=data.mod, dik=dik} + end +end + +windower.register_event('keyboard',function(dik,pressed) + if pressed == last_state[dik] then return end + last_state[dik] = pressed + local key_data = key_lookup[dik] + if not key_data then return end + if key_data.mod then + if pressed then + mods:add(key_data.name) + else + mods:remove(key_data.name) + end + send_key_state(key_data, pressed) + elseif pressed then + if not last_update or os.clock() - last_update > check_rate then + windower.send_command('listbinds') + end + local command = check_bind(key_data) + if command then + windower.send_command(command) + else + send_key_state(key_data, pressed) + end + else + send_key_state(key_data, pressed) + end +end) + +function check_bind(key_data) + local binds = keybinds[key_data.name] + if not binds then return false end + local info = windower.ffxi.get_info() + local chat_open = info and info.chat_open + --if chat_open == nil then return false end + binds = binds:filter(function(bind) + return (bind.chat_state == nil or chat_open and bind.chat_state == 'ChatOnly' or not chat_open) and (bind.mods:length() == bind.mods:intersection(mods):length()) + end) + local number_of_binds = binds:length() + if number_of_binds == 0 then + return false + else + return binds:first().command + end +end + +function send_key_state(key_data, pressed) + windower.send_command('setkey %s %s':format(key_data.name, pressed and "down" or "up")) +end + +windower.register_event('incoming text', function(original, modified, color, color_m, blocked) + if color ~= 141 then return end + if ListBinds then + if original == '===== Done Listing Currently Bound Keys =====' then + ListBinds = false + for _,binds in pairs(new_keybinds) do + binds:sort(function(a,b) return a.mods:length() > b.mods:length() end) + end + keybinds = new_keybinds + else + add_bind(original) + end + return true + elseif original == '===== Listing Currently Bound Keys =====' then + last_update = os.clock() + new_keybinds = {} + ListBinds = true + return true + end +end) + +local chat_states = {['(NoChat)']='NoChat', ['(ChatOnly)']='ChatOnly'} +function add_bind(original) + local bind, command = original:match('^([^:]*): (.*)$') + if not bind or not command then return end + bind = bind:gsub('^%-', 'minus'):gsub('%-%-', '-minus') + parts = bind:split('-'):map(string.gsub-{'minus', '-'}) + local chat_state, key + local mods = S{} + for _,part in pairs(parts) do + if chat_states[part] then + chat_state = chat_states[part] + elseif part ~= '' then + local key_data = name_lookup[part] + if key_data then + if key_data.mod then + mods:add(part) + else + key = part + end + end + end + end + if not new_keybinds[key] then + new_keybinds[key] = L{} + end + new_keybinds[key]:append({key=key, mods=mods, chat_state=chat_state, command=command}) +end + +windower.send_command('listbinds') diff --git a/addons/macrochanger/macrochanger.lua b/addons/macrochanger/macrochanger.lua index 727f592dd3..1d9aac7bc4 100644 --- a/addons/macrochanger/macrochanger.lua +++ b/addons/macrochanger/macrochanger.lua @@ -30,139 +30,139 @@ _addon.version = '1.0.0.1' _addon.commands = {'mc','macrochanger'} require('strings') +require('logger') windower.register_event('load', function() - globaldisable = 0 - macros = { - WAR = {Book = '', Page = ''}, - MNK = {Book = '', Page = ''}, - WHM = {Book = '', Page = ''}, - BLM = {Book = '', Page = ''}, - RDM = {Book = '', Page = ''}, - THF = {Book = '', Page = ''}, - PLD = {Book = '', Page = ''}, - DRK = {Book = '', Page = ''}, - BST = {Book = '', Page = ''}, - BRD = {Book = '', Page = ''}, - RNG = {Book = '', Page = ''}, - SAM = {Book = '', Page = ''}, - NIN = {Book = '', Page = ''}, - DRG = {Book = '', Page = ''}, - SMN = {Book = '', Page = ''}, - BLU = {Book = '', Page = ''}, - COR = {Book = '', Page = ''}, - PUP = {Book = '', Page = ''}, - DNC = {Book = '', Page = ''}, - SCH = {Book = '', Page = ''}, - GEO = {Book = '', Page = ''}, - RUN = {Book = '', Page = ''}, - } - options_load() + globaldisable = 0 + macros = { + WAR = {Book = '', Page = ''}, + MNK = {Book = '', Page = ''}, + WHM = {Book = '', Page = ''}, + BLM = {Book = '', Page = ''}, + RDM = {Book = '', Page = ''}, + THF = {Book = '', Page = ''}, + PLD = {Book = '', Page = ''}, + DRK = {Book = '', Page = ''}, + BST = {Book = '', Page = ''}, + BRD = {Book = '', Page = ''}, + RNG = {Book = '', Page = ''}, + SAM = {Book = '', Page = ''}, + NIN = {Book = '', Page = ''}, + DRG = {Book = '', Page = ''}, + SMN = {Book = '', Page = ''}, + BLU = {Book = '', Page = ''}, + COR = {Book = '', Page = ''}, + PUP = {Book = '', Page = ''}, + DNC = {Book = '', Page = ''}, + SCH = {Book = '', Page = ''}, + GEO = {Book = '', Page = ''}, + RUN = {Book = '', Page = ''}, + } + options_load() end) function options_load() - local f = io.open(windower.addon_path..'data/settings.txt', "r") - if f == nil then - local g = io.open(windower.addon_path..'data/settings.txt', "w") - g:write('Release Date: 9:00 PM, 4-01-13\46\n') - g:write('Author Comment: This document is whitespace sensitive, which means that you need the same number of spaces between things as exist in this initial settings file\46\n') - g:write('Author Comment: It looks at the first two words separated by spaces and then takes anything as the value in question if the first two words are relevant\46\n') - g:write('Author Comment: If you ever mess it up so that it does not work, you can just delete it and MacroChanger will regenerate it upon reload\46\n') - g:write('Author Comment: For the output customization lines, simply place the book and page number that you would like to change to upon a job change.\46\n') - g:write('Author Comment: If 2 jobs share a book, you can place the same book number for each job, then put their individual pages.\46\n') - g:write('Author Comment: Example: BLM and SCH both use Macro Book 2: BLM uses page 3. SCH uses page 1.\46\n') - g:write('Author Comment: Put BLM Book: 2, BLM Page: 3, SCH Book: 2, SCH Page: 1.\46\n') - g:write('Author Comment: If you wish to disable auto-macro Changing for a specific job, type "disabled" instead of a book number. (e.g. BLM Book: disabled)\n') - g:write('Author Comment: The design of the settings file is credited to Byrthnoth as well as the creation of the settings file.\n\n\n') - g:write('File Settings: Fill in below\n') - g:write('Disable All: 0\n') - g:write('WAR Book: 1\nWAR Page: 1\nMNK Book: 2\nMNK Page: 1\nWHM Book: 3\nWHM Page: 1\nBLM Book: 4\nBLM Page: 1\nRDM Book: 5\nRDM Page: 1\nTHF Book: 6\nTHF Page: 1\n') - g:write('PLD Book: 7\nPLD Page: 1\nDRK Book: 8\nDRK Page: 1\nBST Book: 9\nBST Page: 1\nBRD Book: 10\nBRD Page: 1\nRNG Book: 11\nRNG Page: 1\nSAM Book: 12\nSAM Page: 1\n') - g:write('NIN Book: 13\nNIN Page: 1\nDRG Book: 14\nDRG Page: 1\nSMN Book: 15\nSMN Page: 1\nBLU Book: 16\nBLU Page: 1\nCOR Book: 17\nCOR Page: 1\nPUP Book: 18\nPUP Page: 1\n') - g:write('DNC Book: 19\nDNC Page: 1\nSCH Book: 20\nSCH Page: 1\nGEO Book: 20\nGEO Page: 1\nRUN Book: 20\nRUN Page: 1\n') - g:close() - DisableAll = 0 - macros = { - WAR = {Book = '1', Page = '1'}, - MNK = {Book = '2', Page = '1'}, - WHM = {Book = '3', Page = '1'}, - BLM = {Book = '4', Page = '1'}, - RDM = {Book = '5', Page = '1'}, - THF = {Book = '6', Page = '1'}, - PLD = {Book = '7', Page = '1'}, - DRK = {Book = '8', Page = '1'}, - BST = {Book = '9', Page = '1'}, - BRD = {Book = '10', Page = '1'}, - RNG = {Book = '11', Page = '1'}, - SAM = {Book = '12', Page = '1'}, - NIN = {Book = '13', Page = '1'}, - DRG = {Book = '14', Page = '1'}, - SMN = {Book = '15', Page = '1'}, - BLU = {Book = '16', Page = '1'}, - COR = {Book = '17', Page = '1'}, - PUP = {Book = '18', Page = '1'}, - DNC = {Book = '19', Page = '1'}, - SCH = {Book = '20', Page = '1'}, - GEO = {Book = '20', Page = '1'}, - RUN = {Book = '20', Page = '1'}, - } - print('Default settings file created') - windower.add_to_chat(12,'MacroChanger created a settings file and loaded!') - else - f:close() - for curline in io.lines(windower.addon_path..'data/settings.txt') do - local splat = curline:gsub(':',''):split(' ') - local cmd = '' - if splat[1] and macros[splat[1]:upper()] and splat[2] ~=nil and (splat[2]:lower() == 'book' or splat[2]:lower() == 'page') and splat[3] then - macros[splat[1]:upper()][splat[2]:ucfirst()] = splat[3] -- Instead of a number, this can also be 'disabled' - elseif splat[1] and splat[2] and (splat[1]..' '..splat[2]) == 'disable all' and tonumber(splat[3]) then - globaldisable = tonumber(splat[3]) - end - end - windower.add_to_chat(12,'MacroChanger read from a settings file and loaded!') - end + local f = io.open(windower.addon_path..'data/settings.txt', "r") + if f == nil then + local g = io.open(windower.addon_path..'data/settings.txt', "w") + g:write('Release Date: 9:00 PM, 4-01-13\46\n') + g:write('Author Comment: This document is whitespace sensitive, which means that you need the same number of spaces between things as exist in this initial settings file\46\n') + g:write('Author Comment: It looks at the first two words separated by spaces and then takes anything as the value in question if the first two words are relevant\46\n') + g:write('Author Comment: If you ever mess it up so that it does not work, you can just delete it and MacroChanger will regenerate it upon reload\46\n') + g:write('Author Comment: For the output customization lines, simply place the book and page number that you would like to change to upon a job change.\46\n') + g:write('Author Comment: If 2 jobs share a book, you can place the same book number for each job, then put their individual pages.\46\n') + g:write('Author Comment: Example: BLM and SCH both use Macro Book 2: BLM uses page 3. SCH uses page 1.\46\n') + g:write('Author Comment: Put BLM Book: 2, BLM Page: 3, SCH Book: 2, SCH Page: 1.\46\n') + g:write('Author Comment: If you wish to disable auto-macro Changing for a specific job, type "disabled" instead of a book number. (e.g. BLM Book: disabled)\n') + g:write('Author Comment: The design of the settings file is credited to Byrthnoth as well as the creation of the settings file.\n\n\n') + g:write('File Settings: Fill in below\n') + g:write('Disable All: 0\n') + g:write('WAR Book: 1\nWAR Page: 1\nMNK Book: 2\nMNK Page: 1\nWHM Book: 3\nWHM Page: 1\nBLM Book: 4\nBLM Page: 1\nRDM Book: 5\nRDM Page: 1\nTHF Book: 6\nTHF Page: 1\n') + g:write('PLD Book: 7\nPLD Page: 1\nDRK Book: 8\nDRK Page: 1\nBST Book: 9\nBST Page: 1\nBRD Book: 10\nBRD Page: 1\nRNG Book: 11\nRNG Page: 1\nSAM Book: 12\nSAM Page: 1\n') + g:write('NIN Book: 13\nNIN Page: 1\nDRG Book: 14\nDRG Page: 1\nSMN Book: 15\nSMN Page: 1\nBLU Book: 16\nBLU Page: 1\nCOR Book: 17\nCOR Page: 1\nPUP Book: 18\nPUP Page: 1\n') + g:write('DNC Book: 19\nDNC Page: 1\nSCH Book: 20\nSCH Page: 1\nGEO Book: 20\nGEO Page: 1\nRUN Book: 20\nRUN Page: 1\n') + g:close() + DisableAll = 0 + macros = { + WAR = {Book = '1', Page = '1'}, + MNK = {Book = '2', Page = '1'}, + WHM = {Book = '3', Page = '1'}, + BLM = {Book = '4', Page = '1'}, + RDM = {Book = '5', Page = '1'}, + THF = {Book = '6', Page = '1'}, + PLD = {Book = '7', Page = '1'}, + DRK = {Book = '8', Page = '1'}, + BST = {Book = '9', Page = '1'}, + BRD = {Book = '10', Page = '1'}, + RNG = {Book = '11', Page = '1'}, + SAM = {Book = '12', Page = '1'}, + NIN = {Book = '13', Page = '1'}, + DRG = {Book = '14', Page = '1'}, + SMN = {Book = '15', Page = '1'}, + BLU = {Book = '16', Page = '1'}, + COR = {Book = '17', Page = '1'}, + PUP = {Book = '18', Page = '1'}, + DNC = {Book = '19', Page = '1'}, + SCH = {Book = '20', Page = '1'}, + GEO = {Book = '20', Page = '1'}, + RUN = {Book = '20', Page = '1'}, + } + print('Default settings file created') + notice('MacroChanger created a settings file and loaded!') + else + f:close() + for curline in io.lines(windower.addon_path..'data/settings.txt') do + local splat = curline:gsub(':',''):split(' ') + local cmd = '' + if splat[1] and macros[splat[1]:upper()] and splat[2] ~=nil and (splat[2]:lower() == 'book' or splat[2]:lower() == 'page') and splat[3] then + macros[splat[1]:upper()][splat[2]:ucfirst()] = splat[3] -- Instead of a number, this can also be 'disabled' + elseif splat[1] and splat[2] and (splat[1]..' '..splat[2]) == 'disable all' and tonumber(splat[3]) then + globaldisable = tonumber(splat[3]) + end + end + notice('MacroChanger read from a settings file and loaded!') + end end windower.register_event('job change',function () -- Could use the job ID passed into this function, but the addon would have to include the resources library - local job = windower.ffxi.get_player().main_job - local book = '' - local page = '' - if globaldisable == 0 then + local job = windower.ffxi.get_player().main_job + local book = '' + local page = '' + if globaldisable == 0 then if job and macros[job] then - book = macros[job].Book - page = macros[job].Page - end - - if ((book == 'disabled') or (page == 'disabled')) then - windower.add_to_chat(17, ' Auto Macro Switching Disabled for ' .. job ..'.') - else - windower.add_to_chat(17, ' Changing macros to Book: ' .. book .. ' and Page: ' .. page .. '. Job Changed to ' .. job) - windower.send_command('input /macro book '..book..';wait 0.2;input /macro set '..page..';') - end - elseif globaldisable == 1 then - - windower.add_to_chat(17, ' Auto Macro Switching Disabled for All Jobs.') - - end + book = macros[job].Book + page = macros[job].Page + end + if ((book == 'disabled') or (page == 'disabled')) then + notice('Auto Macro Switching Disabled for ' .. job ..'.') + else + log('Job changed to ' .. job .. ' - switched to Book: ' .. book .. ' and Page: ' .. page) + windower.chat.input('/macro book ' .. book) + coroutine.sleep(1.2) + windower.chat.input('/macro set ' .. page) + end + elseif globaldisable == 1 then + notice('Auto Macro Switching Disabled for All Jobs.') + end end) windower.register_event('addon command', function(...) local args = {...} - local mjob = windower.ffxi.get_player().main_job - if args[1] == 'disableall' then - if args[2] == 'on' then - globaldisable = 1 - windower.add_to_chat(17, 'All automated macro switching disabled.') - elseif args[2] == 'off' then - globaldisable = 0 - windower.add_to_chat(17, 'Automated macro switching enabled.') - end - elseif args[1]:lower() == 'help' then - windower.add_to_chat(17, 'MacroChanger Commands:') - windower.add_to_chat(17, 'disableall [on|off]') - windower.add_to_chat(17, ' on - Disables all automated macro switching') - windower.add_to_chat(17, ' off - Enables all automated macro switching not disabled individually') - windower.add_to_chat(17, ' Resets to what is stored in settings upon unloading of addon. To Permanently change, please change the option in the settings file.') - end + local mjob = windower.ffxi.get_player().main_job + if args[1] == 'disableall' then + if args[2] == 'on' then + globaldisable = 1 + notice('All automated macro switching disabled.') + elseif args[2] == 'off' then + globaldisable = 0 + notice('Automated macro switching enabled.') + end + elseif args[1]:lower() == 'help' then + log('MacroChanger Commands:') + log('disableall [on|off]') + log(' on - Disables all automated macro switching') + log(' off - Enables all automated macro switching not disabled individually') + log('Resets to what is stored in settings upon unloading of addon. To Permanently change, please change the option in the settings file.') + end end) diff --git a/addons/ohShi/ohShi.lua b/addons/ohShi/ohShi.lua index 567b15fe62..ad7cfcaddf 100644 --- a/addons/ohShi/ohShi.lua +++ b/addons/ohShi/ohShi.lua @@ -208,7 +208,7 @@ windower.register_event('action', function(act) local player = T(windower.ffxi.get_player()) if not settings.staggeronly then - if settings.showrolls and curact.category == 6 and res.job_abilities[extparam].type == 'CorsairRoll' then + if settings.showrolls and curact.category == 6 and res.job_abilities[extparam] and res.job_abilities[extparam].type == 'CorsairRoll' then local allyroller = false local selfroll = false for pt,member in pairs(party) do diff --git a/addons/organizer/items.lua b/addons/organizer/items.lua index 9fe25746f9..56d591a813 100644 --- a/addons/organizer/items.lua +++ b/addons/organizer/items.lua @@ -29,10 +29,76 @@ local items = {} local bags = {} local item_tab = {} +do + local names = {'Nomad Moogle','Pilgrim Moogle'} + local moogles = {} + local poked = false + local block_menu = false + + clear_moogles = function() + moogles = {} + poked = false + end + + local poke_moogle = function(npc) + local p = packets.new('outgoing', 0x1a, { + ["Target"] = npc.id, + ["Target Index"] = npc.index, + }) + poked = true + block_menu = true + packets.inject(p) + repeat + coroutine.sleep(0.4) + until not block_menu + end + + nomad_moogle = function() + if #moogles == 0 then + for _,name in ipairs(names) do + local npcs = windower.ffxi.get_mob_list(name) + for index in pairs(npcs) do + table.insert(moogles,index) + end + end + end + + local player = windower.ffxi.get_mob_by_target('me') + for _, moo_index in ipairs(moogles) do + local moo = windower.ffxi.get_mob_by_index(moo_index) + if moo and (moo.x - player.x)^2 + (moo.y - player.y)^2 < 36 then + if not poked then + poke_moogle(moo) + end + return moo.name + end + end + return false + end + + windower.register_event('incoming chunk',function(id) + if id == 0x02E and block_menu then + block_menu = false + return true + end + end) +end + +windower.register_event('zone change',function() + clear_moogles() +end) + local function validate_bag(bag_table) - if (bag_table.access == 'Everywhere' or (bag_table.access == 'Mog House' and windower.ffxi.get_info().mog_house)) and - windower.ffxi.get_bag_info(bag_table.id) then - return true + if type(bag_table) == 'table' and windower.ffxi.get_bag_info(bag_table.id) then + if bag_table.access == 'Everywhere' then + return true + elseif bag_table.access == 'Mog House' then + if windower.ffxi.get_info().mog_house then + return true + elseif nomad_moogle() and bag_table.english ~= 'Storage' then -- Storage is not available at Nomad Moogles + return true + end + end end return false end @@ -42,7 +108,7 @@ local function validate_id(id) end local function wardrobecheck(bag_id,id) - return bag_id~=8 or (bag_id == 8 and res.items[id] and (res.items[id].type == 4 or res.items[id].type == 5) ) + return _static.wardrobe_ids[bag_id]==nil or ( res.items[id] and (res.items[id].type == 4 or res.items[id].type == 5) ) end function Items.new(loc_items,bool) @@ -351,7 +417,7 @@ end function item_tab:put_away(usable_bags) org_debug("move", "Putting away "..res.items[self.id].english) local current_items = self._parent._parent - usable_bags = usable_bags or {1,9,4,2,5,6,7,8} + usable_bags = usable_bags or _static.usable_bags local bag_free for _,v in ipairs(usable_bags) do local bag_max = windower.ffxi.get_bag_info(v).max diff --git a/addons/organizer/organizer.lua b/addons/organizer/organizer.lua index d5590b3407..d85c2cf377 100644 --- a/addons/organizer/organizer.lua +++ b/addons/organizer/organizer.lua @@ -24,20 +24,22 @@ --(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -res = require 'resources' -files = require 'files' -require 'pack' -Items = require 'items' -extdata = require 'extdata' -logger = require 'logger' -require 'tables' -require 'lists' -require 'functions' -config = require 'config' +res = require('resources') +files = require('files') +require('pack') +Items = require('items') +extdata = require('extdata') +logger = require('logger') +require('tables') +require('lists') +require('functions') +config = require('config') +slips = require('slips') +packets = require('packets') _addon.name = 'Organizer' _addon.author = 'Byrth, maintainer: Rooks' -_addon.version = 0.20150923 +_addon.version = 0.20211226 _addon.commands = {'organizer','org'} _static = { @@ -51,8 +53,17 @@ _static = { sack=6, case=7, wardrobe=8, - safe2=9 - } + safe2=9, + wardrobe2=10, + wardrobe3=11, + wardrobe4=12, + wardrobe5=13, + wardrobe6=14, + wardrobe7=15, + wardrobe8=16, + }, + wardrobe_ids = {[8]=true,[10]=true,[11]=true,[12]=true,[13]=true,[14]=true,[15]=true,[16]=true}, + usable_bags = {1,9,4,2,5,6,7,8,10,11,12,13,14,15,16} } _global = { @@ -67,14 +78,14 @@ _valid_dump = {} default_settings = { dump_bags = {['Safe']=1,['Safe2']=2,['Locker']=3,['Storage']=4}, - bag_priority = {['Safe']=1,['Safe2']=2,['Locker']=3,['Storage']=4,['Satchel']=5,['Sack']=6,['Case']=7,['Inventory']=8,['Wardrobe']=9}, + bag_priority = {['Safe']=1,['Safe2']=2,['Locker']=3,['Storage']=4,['Satchel']=5,['Sack']=6,['Case']=7,['Inventory']=8,['Wardrobe']=9,['Wardrobe2']=10,['Wardrobe3']=11,['Wardrobe4']=12,['Wardrobe5']=13,['Wardrobe6']=14,['Wardrobe7']=15,['Wardrobe8']=16}, item_delay = 0, ignore = {}, retain = { ["moogle_slip_gear"]=false, ["seals"]=false, ["items"]=false, - ["slips"]=false + ["slips"]=false, }, auto_heal = false, default_file='default.lua', @@ -180,8 +191,10 @@ function options_load( ) slip_lists = require('slips') for slip_id,slip_list in pairs(slip_lists.items) do for item_id in slip_list:it() do - _retain[item_id] = "moogle slip" - org_debug("settings", "Adding ("..res.items[item_id].english..') to slip retain list') + if item_id ~= 0 then + _retain[item_id] = "moogle slip" + org_debug("settings", "Adding ("..res.items[item_id].english..') to slip retain list') + end end end end @@ -201,8 +214,7 @@ function options_load( ) if(settings.retain.slips == true) then org_verbose("Slips set to retain") - slips = {29312,29313,29314,29315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,29330,29331,29332,29333,29334,29335,29336} - for _,slips_id in pairs(slips) do + for _,slips_id in pairs(slips.storages) do _retain[slips_id] = "slips" org_debug("settings", "Adding ("..res.items[slips_id].english..') to slip retain list') end @@ -214,6 +226,12 @@ function options_load( ) _valid_pull[0] = 1 _valid_dump[8] = 1 _valid_pull[8] = 1 + _valid_dump[10] = 1 + _valid_pull[10] = 1 + _valid_dump[11] = 1 + _valid_pull[11] = 1 + _valid_dump[12] = 1 + _valid_pull[12] = 1 end @@ -230,6 +248,11 @@ windower.register_event('addon command',function(...) return end + local moogle = nomad_moogle() + if moogle then + org_debug("command", "Using '" .. moogle .. "' for Mog House interaction") + end + local bag = 'all' if inp[1] and (_static.bag_ids[inp[1]:lower()] or inp[1]:lower() == 'all') then bag = table.remove(inp,1):lower() @@ -286,6 +309,11 @@ windower.register_event('addon command',function(...) windower.send_command('input /heal') end + if moogle then + clear_moogles() + org_debug("command", "Clearing '" .. moogle .. "' status") + end + org_debug("command", "Organizer complete") end) @@ -531,7 +559,11 @@ function get_dump_bags() local dump_bags = {} for i,v in pairs(settings.dump_bags) do if i and s_to_bag(i) then - dump_bags[tonumber(v)] = s_to_bag(i) + if windower.ffxi.get_info().mog_house then + dump_bags[tonumber(v)] = s_to_bag(i) + elseif s_to_bag(i) ~= 2 then -- Storage is not available at Nomad Moogles + dump_bags[tonumber(v)] = s_to_bag(i) + end elseif i then org_error('The bag name ("'..tostring(i)..'") in dump_bags entry #'..tostring(v)..' in the ../addons/organizer/data/settings.xml file is not valid.\nValid options are '..tostring(res.bags)) return diff --git a/addons/plugin_manager/README.md b/addons/plugin_manager/README.md index 0aae29e543..f6822552da 100644 --- a/addons/plugin_manager/README.md +++ b/addons/plugin_manager/README.md @@ -1,26 +1,29 @@ -Author: Byrth +**Author:** Byrth -Version: 1.0 +**Version:** 1.0 -Date: 15/11/13 +**Date:** 15/11/13 -Plugin Manager +# Plugin Manager -Abbreviation: None +**Abbreviation:** None -Commands: None +**Commands:** None -Purpose: To allow player-customizable plugin management. +**Purpose:** To allow player-customizable plugin management. -Installation Instructions (from the Windower 4 Launcher): +## Installation -* 1 Start your copy of Windower 4 and select the "Addons" menu up top in the Launcher. -* 2 Click the icon next to "plugin_manager" -* 3 Log in to the game! -* 4 Alter the settings as you wish. (An example file has been included) -* 5 "//lua r plugin_manager" will reload and give you the new settings. +1. Start your copy of Windower 4 and select the "Addons" menu up top in the Launcher. +1. Click the icon next to "plugin_manager" +1. Log in to the game! +1. Alter the settings as you wish. (An example file has been included) +1. `//lua r plugin_manager` will reload and give you the new settings. -Settings Files: -The settings file for pluginmanager is one xml file with a format similar to the settings files for plugins. XML files can be opened with Notepad, edited, and closed saved safely. If you are going to "Save As..." an xml from Notepad, be sure to change "Text Documents (.txt)" to "All Files" file type and make sure the file ends in ".xml" +> **Note:** Plugin Manager will *not* automatically disable or unload any plugins or addons that you have enabled in the Windower launcher. Anything enabled in the launcher will be loaded for all characters, regardless of how you have configured your Plugin Manager settings. +> If you want Plugin Manager to handle a plugin or addon, be sure to disable it in the launcher. -* data/settings.xml - contains plugins and addons specific to each character. is loaded if there is not a set of plugins/addons inside tags that are a case-sensitive match to the player's name. \ No newline at end of file +## Settings Files +The settings file for Plugin Manager are found in a single XML file with a format similar to the settings files for plugins. + +* `data/settings.xml` - contains plugins and addons specific to each character. \ is loaded if there is not a set of plugins/addons inside tags that are a case-sensitive match to the player's name. diff --git a/addons/pointwatch/FIXING POINTWATCH.txt b/addons/pointwatch/FIXING POINTWATCH.txt deleted file mode 100644 index 61bb39cdaf..0000000000 --- a/addons/pointwatch/FIXING POINTWATCH.txt +++ /dev/null @@ -1,35 +0,0 @@ -Updating Message IDs: A guide - - Pointwatch relies on zone-based message IDs for some of its features. -These IDs change on a regular basis. Fortunately, their positions relative -to one another rarely change, which means that most of the time you only -have to change one number and the entire zone will work again. - -I have written this guide to explain how to change those numbers in the -hopes that members of the community will maintain pointwatch's message- -dependent features. - -Method 1 - POLUtils -1) Download POLUtils (if you don't already have it) from the google code site -2) Install it and run it -3) Click "FFXI Data Browser" -4) Go to the "Dialog Tables" menu and select the zone you are interested in -5) Wait for it to load, then export the entire table as xml -6) Open the xml file up in a text editor, like Notepad or Notepad++. -7) Control-F for the key phrase. -8) The associated message ID is the offset value for that zone. - -Method 2 - message_printing -1) Load Pointwatch (//lua l pointwatch) -2) Enable message printing (//pw message_printing) -3) Generate the key message (for instance, by resting in Abyssea) -4) This will print message IDs to your windower console. They appear in the - order they were generated. Select the one that you want (for instance, - the second one when you rest in Abyssea). -5) That value is your offset. -6) Disable message printing (//pw message_printing) - -Both methods: -* Open message_ids.lua -* Find the zone and replace the zone.offset value with the correct value. -* Submit your file to Github, so that everyone can have a working copy! diff --git a/addons/pointwatch/ReadMe.txt b/addons/pointwatch/ReadMe.txt index b3f1964d22..2143b47d8f 100644 --- a/addons/pointwatch/ReadMe.txt +++ b/addons/pointwatch/ReadMe.txt @@ -14,10 +14,6 @@ Text Box Commands: * bg_transparency - Changes the background transparency. Number should be between 0 and 1 ** pos_x, pos_y, pad, transparency, alpha, and bg_alpha are also valid commands and are documented in the texts library. -Other Commands: -* message_printing - See FIXING POINTWATCH.txt in this directory for a full explanation. - - Strings Options: The two strings options in settings.xml are loaded as Lua code and run accordingly, @@ -30,9 +26,15 @@ Here are the available values: * xp.tnl = Number of Experience Points in your current level (number from 500 to 56,000) * xp.rate = Current XP gain rate per hour. This is calculated over a 10 minute window and requires at least two gains within the window. * xp.total = Total Experience Points gained since the last time the addon was loaded (number) +* xp.job = Your current main job. +* xp.job_abbr = The three-letter abbreviation of your current main job. +* xp.job_level = Level of your current job. +* xp.sub_job = Your current subjob. +* xp.sub_job_abbr = The three-letter abbreviation of your current subjob. +* xp.sub_job_level = Level of your current support job. * lp.current = Current Experience Points (number from 0 to 55,999 XP) -* lp.tnl = Similar to a "To Next Level", but this value is always 10,000 because that's always the number of Limit Points per merit point. +* lp.tnm = Similar to a "To Next Level", but this value is always 10,000 because that's always the number of Limit Points per merit point. * lp.number_of_merits = Number of merit points you have. * lp.maximum_merits = Maximum number of merits you can store. @@ -42,11 +44,16 @@ Here are the available values: * cp.tnjp = Similar to a "To Next Level", but this value is always 30,000 because that's always the number of CPs per job point. * cp.number_of_job_points = Number of job points you currently have on your current job. -* sparks.current = Current number of RoE Sparks (number between 0 and 50,000) -* sparks.maximum = Maximum number of RoE Sparks (always 50,000) +* ep.current = Current Exemplar Points +* ep.rate = Current Exemplar Points gain rate per hour. This is calculated over a 10 minute window and requires at least two gains within the window. +* ep.tnml = Required Exemplar Points for your next Master Level +* ep.master_level = Master Level of your current job. -- Will be incorrect during Level Sync. + +* sparks.current = Current number of RoE Sparks (number between 0 and 99,999) +* sparks.maximum = Maximum number of RoE Sparks (always 99,999) -* accolades.current = Current number of Unity Accolades (number between 0 and 50,000) -* accolades.maximum = Maximum number of Unity Accolades (always 50,000) +* accolades.current = Current number of Unity Accolades (number between 0 and 99,999) +* accolades.maximum = Maximum number of Unity Accolades (always 99,999) * dynamis.KIs = Series of Xs and Os indicating whether or not you have the 5 KIs. * dynamis.entry_time = Your Dynamis entry time, in seconds. -- If the addon is loaded in dynamis, this will be the time of addon load. @@ -67,6 +74,7 @@ Here are the available values: Version History: +0.211112 - Added ep.current, ep.rate, and ep.tnml. 0.150811 - Changed job_points from a char to a short. 0.150201 - Added Unity Accolades. 0.141111 - Adjusted Pointwatch to account for a recent packet change. diff --git a/addons/pointwatch/message_ids.lua b/addons/pointwatch/message_ids.lua index 300dc2bd12..de950c313f 100644 --- a/addons/pointwatch/message_ids.lua +++ b/addons/pointwatch/message_ids.lua @@ -33,7 +33,7 @@ local messages = { z15 = { name = 'Abyssea - Konschtat', - offset = 7305, + offset = 7315, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -50,7 +50,7 @@ local messages = { }, z132 = { name = 'Abyssea - La Theine', - offset = 7305, + offset = 7315, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -67,7 +67,7 @@ local messages = { }, z45 = { name = 'Abyssea - Tahrongi', - offset = 7305, + offset = 7315, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -84,7 +84,7 @@ local messages = { }, z215 = { name = 'Abyssea - Attohwa', - offset = 7210, + offset = 7215, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -101,7 +101,7 @@ local messages = { }, z216 = { name = 'Abyssea - Misareaux', - offset = 7305, + offset = 7315, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -118,7 +118,7 @@ local messages = { }, z217 = { name = 'Abyssea - Vunkerl', - offset = 7305, + offset = 7315, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -135,7 +135,7 @@ local messages = { }, z218 = { name = 'Abyssea - Altepa', - offset = 7305, + offset = 7315, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -152,7 +152,7 @@ local messages = { }, z254 = { name = 'Abyssea - Grauberg', - offset = 7305, + offset = 7315, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -169,7 +169,7 @@ local messages = { }, z253 = { name = 'Abyssea - Uleguerand', - offset = 7210, + offset = 7215, pearl_ebon_gold_silvery = 0, azure_ruby_amber = 1, visitant_status_update = 9, @@ -183,7 +183,45 @@ local messages = { azure_light = 187, ruby_light = 188, amber_light = 189, - }, + } } +local function update_offset(zone_id) + local z_string = 'z' .. tostring(zone_id) + local m = messages[z_string] + if m and m.name then + -- convert dialog entry to dialog ID + local dialog = require('dialog') + local search_phrase = string.char( + 158,133,214,233,243,233,244,225,238,244,160,204,233,231,232, + 244,160,201,238,244,229,238,243,233,244,249,158,129,135,208, + 229,225,242,236,229,243,227,229,238,244,186,160,138,128,160, + 175,160,197,226,239,238,186,160,138,129,135,199,239,236,228, + 229,238,186,160,138,130,160,175,160,211,233,236,246,229,242, + 249,186,160,138,131,255,177,128,135 + ) + local f = dialog.open_dat_by_zone_id(zone_id, 'english') + local dat = f:read('*a') + f:close() + local res = dialog.get_ids_matching_entry(dat, search_phrase) + if #res ~= 1 then + print('In pointwatch/message_ids.lua: matched multiple or no entries.') + print('Could not update message ID.') + return + end + + m.offset = res[1] + m.name = nil + end +end + +do + local info = windower.ffxi.get_info() + if info.logged_in then + update_offset(info.zone) + end +end +windower.register_event('zone change', update_offset) + return messages + diff --git a/addons/pointwatch/pointwatch.lua b/addons/pointwatch/pointwatch.lua index bc4f181ff0..4fc0ac0dda 100644 --- a/addons/pointwatch/pointwatch.lua +++ b/addons/pointwatch/pointwatch.lua @@ -1,4 +1,4 @@ ---Copyright (c) 2014, Byrthnoth +--Copyright © 2014, Byrthnoth --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -24,17 +24,19 @@ --(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -texts = require 'texts' -config = require 'config' -require 'sets' -res = require 'resources' -require 'statics' -messages = require 'message_ids' -require 'pack' +texts = require('texts') +config = require('config') +require('sets') +res = require('resources') +require('statics') +messages = require('message_ids') +packets = require('packets') +require('pack') +require('chat') _addon.name = 'PointWatch' _addon.author = 'Byrth' -_addon.version = 0.150811 +_addon.version = 0.220327 _addon.command = 'pw' settings = config.load('data\\settings.xml',default_settings) @@ -44,31 +46,32 @@ box = texts.new('${current_string}',settings.text_box_settings,settings) box.current_string = '' box:show() -initialize() +granule_KIs = res.key_items:en(function(x) return x:endswith('granules of time') end):map(function(ki) + return { + id=ki.id, + type=math.floor(ki.id/0x200), + offset=ki.id%0x200, + name=ki.en:match('%w+'):ucfirst(), + } +end) -windower.register_event('incoming chunk',function(id,org,modi,is_injected,is_blocked) - if is_injected then return end - if id == 0x29 then -- Action Message, used in Abyssea for xp - local val = org:unpack('I',0xD) - local msg = org:unpack('H',0x19)%1024 - exp_msg(val,msg) - elseif id == 0x2A then -- Resting message +packet_initiators = L{0x02A,0x055,0x061,0x063,0x110} +packet_handlers = { + [0x029] = function(org) -- Action Message, used in Abyssea for xp + local p = packets.parse('incoming',org) + exp_msg(p['Param 1'],p['Message']) + end, + [0x02A] = function(org) -- Resting message + local p = packets.parse('incoming',org) local zone = 'z'..windower.ffxi.get_info().zone - if settings.options.message_printing then - print('Message ID: '..(org:unpack('H',0x1B)%2^14)) - end - + if messages[zone] then - local msg = org:unpack('H',0x1B)%2^14 + local msg = bit.band(p['Message ID'], 16383) for i,v in pairs(messages[zone]) do - if tonumber(v) and v + messages[zone].offset == msg then - local param_1 = org:unpack('I',0x9) - local param_2 = org:unpack('I',0xD) - local param_3 = org:unpack('I',0x11) - local param_4 = org:unpack('I',0x15) - -- print(param_1,param_2,param_3,param_4) -- DEBUGGING STATEMENT ------------------------- + if tonumber(v) and v + messages[zone].offset == msg then + -- print(p['Param 1'],p['Param 2'],p['Param 3'],p['Param 4']) -- DEBUGGING STATEMENT ------------------------- if zone_message_functions[i] then - zone_message_functions[i](param_1,param_2,param_3,param_4) + zone_message_functions[i](p['Param 1'],p['Param 2'],p['Param 3'],p['Param 4']) end if i:contains("visitant_status_") then abyssea.update_time = os.clock() @@ -76,50 +79,85 @@ windower.register_event('incoming chunk',function(id,org,modi,is_injected,is_blo end end end - elseif id == 0x2D then - local val = org:unpack('I',0x11) - local msg = org:unpack('H',0x19)%1024 - exp_msg(val,msg) - elseif id == 0x55 then - if org:byte(0x85) == 3 then - local dyna_KIs = math.floor((org:byte(6)%64)/2) -- 5 bits (32, 16, 8, 4, and 2 originally -> shifted to 16, 8, 4, 2, and 1) - dynamis._KIs = { - ['Crimson'] = dyna_KIs%2 == 1, - ['Azure'] = math.floor(dyna_KIs/2)%2 == 1, - ['Amber'] = math.floor(dyna_KIs/4)%2 == 1, - ['Alabaster'] = math.floor(dyna_KIs/8)%2 == 1, - ['Obsidian'] = math.floor(dyna_KIs/16) == 1, - } - if dynamis_map[dynamis.zone] then - dynamis.time_limit = 3600 - for KI,TE in pairs(dynamis_map[dynamis.zone]) do - if dynamis._KIs[KI] then - dynamis.time_limit = dynamis.time_limit + TE*60 + end, + [0x02D] = function(org) + local p = packets.parse('incoming',org) + exp_msg(p['Param 1'],p['Message']) + end, + [0x055] = function(org) + local p = packets.parse('incoming',org) + --print(p['Type'],p['Key item available'], p['Key item available']:byte(1),p['Key item available']:byte(2)) + for _,ki in pairs(granule_KIs) do + if p['Type'] == ki.type then + local byte = p['Key item available']:byte(math.floor(ki.offset/8)+1) + local flag = bit.band(bit.rshift(byte, ki.offset % 8), 1) + --print('byte', byte, 'offset', ki.offset % 8, 'flag', flag) + if flag == 1 then + dynamis._KIs[ki.name] = true + if dynamis_map[dynamis.zone] then + dynamis.time_limit = 3600 + for KI,TE in pairs(dynamis_map[dynamis.zone]) do + if dynamis._KIs[KI] then + dynamis.time_limit = dynamis.time_limit + TE*60 + end + end + update_box() end end - update_box() end end - elseif id == 0x61 then - xp.current = org:unpack('H',0x11) - xp.tnl = org:unpack('H',0x13) - accolades.current = math.floor(org:byte(0x5A)/4) + org:byte(0x5B)*2^6 + org:byte(0x5C)*2^14 - elseif id == 0x63 and org:byte(5) == 2 then - lp.current = org:unpack('H',9) - lp.number_of_merits = org:byte(11)%128 - lp.maximum_merits = org:byte(0x0D)%128 - elseif id == 0x63 and org:byte(5) == 5 then - local offset = windower.ffxi.get_player().main_job_id*6+13 -- So WAR (ID==1) starts at byte 19 - cp.current = org:unpack('H',offset) - cp.number_of_job_points = org:unpack('H',offset+2) - elseif id == 0x110 then - sparks.current = org:unpack('I',5) - elseif id == 0xB and box:visible() then + end, + [0x061] = function(org) + local p = packets.parse('incoming',org) + xp.current = p['Current EXP'] + xp.tnl = p['Required EXP'] + xp.job = res.jobs[p['Main Job']].name + xp.job_abbr = res.jobs[p['Main Job']].name_short + xp.job_level = p['Main Job Level'] + xp.sub_job = res.jobs[p['Sub Job']].name + xp.sub_job_abbr = res.jobs[p['Sub Job']].name_short + xp.sub_job_level = p['Sub Job Level'] + accolades.current = p['Unity Points'] + ep.current = p['Current Exemplar Points'] + ep.tnml = p['Required Exemplar Points'] + ep.master_level = p['Master Level'] + end, + [0x063] = function(org) + local p = packets.parse('incoming',org) + if p['Order'] == 2 then + lp.current = p['Limit Points'] + lp.number_of_merits = p['Merit Points'] + lp.maximum_merits = p['Max Merit Points'] + elseif p['Order'] == 5 then + local player = windower.ffxi.get_player() + if player then + local job = player.main_job_full + cp.current = p[job..' Capacity Points'] + cp.number_of_job_points = p[job..' Job Points'] + end + end + end, + [0x110] = function(org) + local p = packets.parse('incoming',org) + sparks.current = p['Sparks Total'] + end, + [0xB] = function(org) zoning_bool = true box:hide() - elseif id == 0xA and zoning_bool then + end, + [0xA] = function(org) zoning_bool = nil box:show() + end, +} + +initialize() + +windower.register_event('incoming chunk',function(id,org,modi,is_injected,is_blocked) + if is_injected or is_blocked then return end + local handler = packet_handlers[id] + if handler then + handler(org,modi) end end) @@ -173,9 +211,6 @@ windower.register_event('addon command',function(...) windower.send_command('lua u pointwatch') elseif first_cmd == 'reset' then initialize() - elseif first_cmd == 'message_printing' then - settings.options.message_printing = not settings.options.message_printing - print('Pointwatch: Message printing is '..tostring(settings.options.message_printing)..'.') elseif first_cmd == 'eval' then assert(loadstring(table.concat(commands, ' ')))() end @@ -195,6 +230,7 @@ function update_box() end cp.rate = analyze_points_table(cp.registry) xp.rate = analyze_points_table(xp.registry) + ep.rate = analyze_points_table(ep.registry) if dynamis.entry_time ~= 0 and dynamis.entry_time+dynamis.time_limit-os.clock() > 0 then dynamis.time_remaining = os.date('!%H:%M:%S',dynamis.entry_time+dynamis.time_limit-os.clock()) dynamis.KIs = X_or_O(dynamis._KIs.Crimson)..X_or_O(dynamis._KIs.Azure)..X_or_O(dynamis._KIs.Amber)..X_or_O(dynamis._KIs.Alabaster)..X_or_O(dynamis._KIs.Obsidian) @@ -315,14 +351,23 @@ function exp_msg(val,msg) elseif msg == 371 or msg == 372 then lp.registry[t] = (lp.registry[t] or 0) + val lp.current = lp.current + val - if lp.current + val >= lp.tnm and lp.number_of_merits ~= lp.maximum_merits then + if lp.current >= lp.tnm and lp.number_of_merits ~= lp.maximum_merits then -- Merit Point gained! - lp.number_of_merits = lp.number_of_merits + math.min(math.floor(lp.current/lp.tnm),lp.maximum_merits) + lp.number_of_merits = math.min(lp.number_of_merits + math.floor(lp.current/lp.tnm),lp.maximum_merits) lp.current = lp.current%lp.tnm else -- If a merit point was not gained, - lp.current = math.min(lp.current+val,lp.tnm-1) + lp.current = math.min(lp.current,lp.tnm-1) + end + elseif msg == 809 or msg == 810 then + ep.registry[t] = (ep.registry[t] or 0) + val + if ep.tnml and ep.current >= ep.tnml then + ep.current = ep.current - ep.tnml end end update_box() end + +function max_color(str,val,max,r,g,b) + return val >= max and tostring(str):text_color(r,g,b) or tostring(str) or "" +end diff --git a/addons/pointwatch/statics.lua b/addons/pointwatch/statics.lua index 902cc46dcf..5afd4af9e0 100644 --- a/addons/pointwatch/statics.lua +++ b/addons/pointwatch/statics.lua @@ -28,9 +28,9 @@ --Default settings file: default_settings = { strings = { - default = "xp.current..'/'..xp.tnl..'XP '..lp.current..'/'..lp.tnm..'LP ['..lp.number_of_merits..'/'..lp.maximum_merits..'] XP/hr:'..string.format('%.1f',math.floor(xp.rate/100)/10)..'k '..cp.current..'/'..cp.tnjp..'CP ['..cp.number_of_job_points..'] CP/hr:'..string.format('%.1f',math.floor(cp.rate/100)/10)..'k'", - dynamis = "xp.current..'/'..xp.tnl..'XP '..lp.current..'/'..lp.tnm..'LP ['..lp.number_of_merits..'/'..lp.maximum_merits..'] XP/hr:'..string.format('%.1f',math.floor(xp.rate/100)/10)..'k '..cp.current..'/'..cp.tnjp..'CP ['..cp.number_of_job_points..'] '..dynamis.KIs..' '..dynamis.time_remaining", - abyssea = "xp.current..'/'..xp.tnl..'XP '..lp.current..'/'..lp.tnm..'LP ['..lp.number_of_merits..'/'..lp.maximum_merits..'] XP/hr:'..string.format('%.1f',math.floor(xp.rate/100)/10)..'k Amber:'..(abyssea.amber or 0)..'/Azure:'..(abyssea.azure or 0)..'/Ruby:'..(abyssea.ruby or 0)..'/Pearlescent:'..(abyssea.pearlescent or 0)..'/Ebon:'..(abyssea.ebon or 0)..'/Silvery:'..(abyssea.silvery or 0)..'/Golden:'..(abyssea.golden or 0)..'/Time Remaining:'..(abyssea.time_remaining or 0)" + default = "string.format('%d/%dXP %sMerits XP/hr:%.1fk %sJP CP/hr:%.1fk %d/%dEP EP/hr:%.1fk',xp.current,xp.tnl,max_color('%5.2f':format(math.floor(lp.current/lp.tnm*100)/100+lp.number_of_merits),lp.current/lp.tnm+lp.number_of_merits,lp.maximum_merits,58,147,191),math.floor(xp.rate/100)/10,max_color('%6.2f':format(math.floor(cp.current/cp.tnjp*100)/100+cp.number_of_job_points),cp.current/cp.tnjp+cp.number_of_job_points,500,58,147,191),math.floor(cp.rate/100)/10,ep.current,ep.tnml,math.floor(ep.rate/100)/10)", + dynamis = "string.format('%d/%dXP %sMerits XP/hr:%.1fk %sJP CP/hr:%.1fk %d/%dEP %s %s',xp.current,xp.tnl,max_color('%5.2f':format(math.floor(lp.current/lp.tnm*100)/100+lp.number_of_merits),lp.current/lp.tnm+lp.number_of_merits,lp.maximum_merits,58,147,191),math.floor(xp.rate/100)/10,max_color('%6.2f':format(math.floor(cp.current/cp.tnjp*100)/100+cp.number_of_job_points),cp.current/cp.tnjp+cp.number_of_job_points,500,58,147,191),math.floor(cp.rate/100)/10,ep.current,ep.tnml,dynamis.KIs,dynamis.time_remaining or 0)", + abyssea = "string.format('%d/%dXP %sMerits XP/hr:%.1fk %sJP CP/hr:%.1fk %d/%dEP Amber:%d Azure:%d Ruby:%d Pearl:%d Ebon:%d Silver:%d Gold:%d Time-Remaining:%d',xp.current,xp.tnl,max_color('%5.2f':format(math.floor(lp.current/lp.tnm*100)/100+lp.number_of_merits),lp.current/lp.tnm+lp.number_of_merits,lp.maximum_merits,58,147,191),math.floor(xp.rate/100)/10,max_color('%6.2f':format(math.floor(cp.current/cp.tnjp*100)/100+cp.number_of_job_points),cp.current/cp.tnjp+cp.number_of_job_points,500,58,147,191),math.floor(cp.rate/100)/10,ep.current,ep.tnml,abyssea.amber or 0,abyssea.azure or 0,abyssea.ruby or 0,abyssea.pearlescent or 0,abyssea.ebon or 0,abyssea.silvery or 0,abyssea.golden or 0,abyssea.time_remaining or 0)", }, text_box_settings = { pos = { @@ -60,10 +60,7 @@ default_settings = { green = 255, blue = 255 } - }, - options = { - message_printing = false, - }, + } } -- Approved textbox commands: @@ -81,7 +78,6 @@ other_table = {Crimson=10,Azure=10,Amber=10,Alabaster=10,Obsidian=20} dynamis_map = {[185]=city_table,[186]=city_table,[187]=city_table,[188]=city_table, [134]=other_table,[135]=other_table,[39]=other_table,[40]=other_table,[41]=other_table,[42]=other_table} - -- Not technically static, but sets the initial values for all features: function initialize() cp = { @@ -101,6 +97,12 @@ function initialize() rate = 0, current = 0, tnl = 0, + job = 0, + job_abbr = 0, + job_level = 0, + sub_job = 0, + sub_job_abbr = 0, + sub_job_level = 0, } lp = { @@ -110,6 +112,14 @@ function initialize() number_of_merits = 0, maximum_merits = 30, } + + ep = { + registry = {}, + current = 0, + rate = 0, + tnml = 0, + master_level = 0, + } sparks = { current = 0, @@ -155,5 +165,13 @@ function initialize() cur_func = loadstring("current_string = "..settings.strings.default) setfenv(cur_func,_G) end - + for _,id in ipairs(packet_initiators) do + local handler = packet_handlers[id] + if handler then + local last = windower.packets.last_incoming(id) + if last then + handler(last) + end + end + end end diff --git a/addons/porter/README.md b/addons/porter/README.md index 4cab50a622..4efb5ce2ae 100644 --- a/addons/porter/README.md +++ b/addons/porter/README.md @@ -14,10 +14,17 @@ porter [ []] [owned] * **_slip_:** the number of the slip you want to show. * **_page_:** the page of the slip you want to show. * **owned:** shows only the items you own. - +``` +porter find +``` +Shows storable items found in all inventory bags. ---- ##changelog## +### v1.20200419 +* **add**: New command, porter find. +* **change**: Adjusted resource handling. + ### v1.20130529 * **fix**: Fixed parameters validation. * **change**: Aligned to Windower's addon development guidelines. diff --git a/addons/porter/porter.lua b/addons/porter/porter.lua index 8481599a98..74e12e9525 100644 --- a/addons/porter/porter.lua +++ b/addons/porter/porter.lua @@ -32,63 +32,15 @@ require 'chat' require 'logger' require 'sets' require 'strings' - +res = require 'resources' slips = require 'slips' - -_addon.name = 'porter' -_addon.version = '1.20130529' +_addon.name = 'porter' +_addon.version = '1.20210302' _addon.command = 'porter' _addon.author = 'Zohno' -item_names = T{} -resources = { - ['armor'] = '../../plugins/resources/items_armor.xml', - ['weapons'] = '../../plugins/resources/items_weapons.xml', - ['general'] = '../../plugins/resources/items_general.xml' -} - -function load_resources() - local slips_items_ids = T() - for _, slip in pairs(slips.items) do - slips_items_ids:extend(slip) - end - - slips_items_ids = S(slips_items_ids) - - for kind, resource_path in pairs(resources) do - resource = io.open(windower.addon_path..resource_path, 'r') - - if resource ~= nil then - while true do - local line = resource:read() - - if line == nil then - break - end - - local id, name = line:match('id="(%d+)".+>([^<]+)<') - - if id ~= nil then - id = tonumber(id, 10) - - if slips_items_ids:contains(id) then - item_names[id] = name:lower() - end - end - end - else - error(kind..' resource file not found') - end - - resource:close() - end -end - function show_slip(slip_number, slip_page, owned_only) - if item_names:length() == 0 then - load_resources() - end owned_only = owned_only or false @@ -131,20 +83,40 @@ function show_slip(slip_number, slip_page, owned_only) end for item_position, item_id in ipairs(slip_items) do - local is_contained = player_slip_items:contains(item_id) - - if owned_only == false or owned_only == true and is_contained == true then - windower.add_to_chat( - 55, - ('slip '..printable_slip_number..'/page '..tostring(slip_page and slip_page or math.ceil(item_position / 16)):lpad('0', 2)..':'):color(259)..' '.. - item_names[item_id]:color(is_contained and 258 or 261) - ) - end + if item_id ~= 0 then + local is_contained = player_slip_items:contains(item_id) + + if owned_only == false or owned_only == true and is_contained == true then + windower.add_to_chat( + 55, + ('slip '..printable_slip_number..'/page '..tostring(slip_page and slip_page or math.ceil(item_position / 16)):lpad('0', 2)..':'):color(259)..' '.. + res.items[item_id].name:color(is_contained and 258 or 261) + ) + end + end end end end end +function show_bags() + + local n = 0 + + for _, bag in ipairs(slips.default_storages) do + for _, item in ipairs(windower.ffxi.get_items(bag)) do + local slip_id = slips.get_slip_id_by_item_id(item.id) + + if slip_id and item.id ~= 0 then + n = n + 1 + windower.add_to_chat(207, 'slip %02d: %s %s':format(slips.get_slip_number_by_id(slip_id), bag, res.items[item.id].name:color(258))) + end + end + end + + windower.add_to_chat(207, 'Found %s storable items in all bags':format(n)) +end + windower.register_event('addon command',function (slip_number, slip_page, owned_only) if tonumber(slip_number) == nil then slip_page = nil @@ -152,6 +124,9 @@ windower.register_event('addon command',function (slip_number, slip_page, owned_ if slip_number == 'owned' then slip_number = nil owned_only = true + elseif slip_number == 'find' then + show_bags() + return elseif slip_number ~= nil then error('That\'s not a valid slip number, kupo!') @@ -181,4 +156,4 @@ windower.register_event('addon command',function (slip_number, slip_page, owned_ end show_slip(slip_number, slip_page, owned_only) -end) \ No newline at end of file +end) diff --git a/addons/position_manager/README.md b/addons/position_manager/README.md new file mode 100644 index 0000000000..d695b64bf8 --- /dev/null +++ b/addons/position_manager/README.md @@ -0,0 +1,42 @@ +# Position Manager + +Set and save screen position per-character. Requires the WinControl addon. + +Commands: +`//pm set [name]` +`//pm size [name]` +`//pm size reset [name]` + +`pos_x`, `pos_y`, `width` and `height` are obligatory and must be numbers. +`size reset` will restore the original windows size for that character (as specified in the Windower profile). +`name` is optional. If no name is provided, settings will be saved for the current character. +`:all` is a special name that can be used to set the default position. + +**Note**: Characters are only moved or resized after they're logged in. The `:all` position will be used for the character login screen as well. + +**Note**: On some systems with very fast or very slow disks, it can happen that the `WinControl` addon does not get loaded in time for `position_manager` to send the proper command. In that case, you can use this command: +`//pm delay [name]` +(where `seconds` is obligatory and must be a positive number, and `name` follows the same rules as before), to set a delay that will hopefully let the plugin load in time. + +### Examples: +`//pm set 0 0` +Will set your _current_ character to the position X: 0, Y: 0. + +`//pm set 0 60 :all` +Will set the default positioning for all characters to X: 0 and Y: 60 (the height of the Windows 10 taskbar with 150% UI scaling.), and delete all other character-specific settings. + +`//pm set 1920 0 Yourname` +Will set the default position for the character called "Yourname" to X: 1920 and Y: 0. +This will make the character appear on the secondary screen that is to the right of the main screen - useful for multi-screen setups. + +`//pm set delay 1 all` +`//pm set 0 40 Yourman` +`//pm set 800 40 Youralt` +Will set delay to 1 for all characters, then set the position of your main to X: 0, Y: 40, and your alt to X: 800, Y: 40. +If your laptop screen is 1600px wide, and your instances are both set at 800x600, this will put them side by side. + +**Warning:** the `all` name will delete every other character-specific settings that are already saved! It's best to use it only once after you install the addon, to set default position and delay for non-specified characters. + +IPC is supported. Setting a character's position or size from another character's window, will cause the affected character to update automatically. + +Enjoy. diff --git a/addons/position_manager/position_manager.lua b/addons/position_manager/position_manager.lua new file mode 100644 index 0000000000..4df4123870 --- /dev/null +++ b/addons/position_manager/position_manager.lua @@ -0,0 +1,194 @@ +--Copyright © 2020, Lili +--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 position_manager 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 Lili 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 = 'position_manager' +_addon.author = 'Lili' +_addon.version = '2.0.1' +_addon.command = 'pm' + +if not windower.file_exists(windower.windower_path .. '\\plugins\\WinControl.dll') then + print('position_manager: error - Please install the WinControl plugin in the launcher.') + windower.send_command('lua u position_manager') + return +else + print('position_manager: loading WinControl...') + windower.send_command('load wincontrol') +end + +local config = require('config') + +local default = { + x = 0, + y = 0, + width = -1, + height = -1, + delay = 0, +} + +local settings = config.load(default) + +function get_name(name) + if name ~= nil and type(name) ~= 'string' then + err('invalid name provided') + return false + elseif not name then + return windower.ffxi.get_player().name + elseif name == ':all' then + return 'all' + end + return name +end + +function err(reason) + windower.add_to_chat(207, 'position_manager: ERROR - %s.':format(err)) + show_help() + return +end + +function show_help() + windower.add_to_chat(207, 'position_manager: Commands:') + windower.add_to_chat(207, ' //pm set [name]') + windower.add_to_chat(207, ' //pm size [name]') + windower.add_to_chat(207, ' //pm delay [name]') + windower.add_to_chat(207, 'position_manager: See the readme for details.') +end + +function move(settings) + if settings.delay > 0 then + coroutine.sleep(settings.delay) + end + + windower.send_command('wincontrol move %s %s':format(settings.x, settings.y)) + --print('::wincontrol move %s %s':format(settings.x, settings.y)) +end + +function resize(settings) + if settings.width == -1 and settings.height == -1 then + windower.send_command('wincontrol resize reset') + return + end + + if settings.delay > 0 then + coroutine.sleep(settings.delay) + end + + local width = settings.width == -1 and windower.get_windower_settings().ui_x_res or settings.width + local height = settings.height == -1 and windower.get_windower_settings().ui_y_res or settings.height + + windower.send_command('wincontrol resize %s %s':format(width, height)) + --print('::wincontrol resize %s %s':format(width, height)) +end + +function handle_commands(cmd, ...) + cmd = cmd and cmd:lower() + + if cmd == 'r' then + windower.send_command('lua r position_manager') + return + elseif cmd == 'set' or cmd == 'size' then + local arg = {...} + local name = get_name(arg[3]) + + if not name then + return + end + + arg[1] = arg[1] == 'default' and -1 or tonumber(arg[1]) + arg[2] = arg[2] == 'default' and -1 or tonumber(arg[2]) + + if arg[1] and arg[2] then + if cmd == 'set' then + settings.x = arg[1] + settings.y = arg[2] + + if settings.x and settings.y then + config.save(settings, name) + windower.add_to_chat(207, 'position_manager: Position set to %s, %s for %s.':format(settings.x, settings.y, name)) + else + err('invalid position provided.') + return false + end + elseif cmd == 'size' then + settings.width = arg[1] + settings.height = arg[2] + + if settings.width and settings.height then + config.save(settings, name) + windower.add_to_chat(207, 'position_manager: Window size set to %s, %s for %s.':format(settings.width, settings.height, name)) + else + err('invalid window size provided.') + return false + end + end + else + err('invalid arguments provided.') + return false + end + + if player_name and name:lower() == player_name:lower() then + if cmd == 'set' then + move(settings) + elseif cmd == 'size' then + resize(settings) + end + end + + windower.send_ipc_message(name) + return true + + elseif cmd == 'delay' then + settings.delay = tonumber(arg[2]) + + if settings.delay > 0 then + config.save(settings, name) + windower.add_to_chat(207, 'position_manager: Delay set to %s for %s.':format(settings.delay, name)) + else + err('invalid delay provided') + return false + end + return true + + elseif cmd ~= 'help' then + windower.add_to_chat(207, 'position_manager: %s command not found.':format(cmd)) + end + show_help() +end + +config.register(settings, move) +config.register(settings, resize) + +windower.register_event('addon command', handle_commands) + +windower.register_event('load','login','logout', function(name) + local player = windower.ffxi.get_player() + player_name = player and player.name +end) + +windower.register_event('ipc message', function(msg) + if msg == player_name or msg == 'all' then + config.reload(settings) + end +end) diff --git a/addons/roe/ReadMe.md b/addons/roe/ReadMe.md new file mode 100644 index 0000000000..1cbd1410bb --- /dev/null +++ b/addons/roe/ReadMe.md @@ -0,0 +1,26 @@ +**Author:** Cair
+**Version:** 1.0
+**Date:** Oct. 30, 2017
+ +### 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 : saves the currently set ROE to the named profile +3. set : 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 + - 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 : 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] : blacklists a quest from ever being removed + - I do not currently have a mapping of quest IDs to names diff --git a/addons/roe/roe.lua b/addons/roe/roe.lua new file mode 100644 index 0000000000..49dd52d33e --- /dev/null +++ b/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] ') + end + +end + + +local function help() + notice([[ROE - Command List: +1. help - Displays this help menu. +2. save : saves the currently set ROE to the named profile +3. set : 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 : 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] : 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) diff --git a/addons/rolltracker/readme.md b/addons/rolltracker/readme.md index ba7dbfc67f..d536dc0d24 100644 --- a/addons/rolltracker/readme.md +++ b/addons/rolltracker/readme.md @@ -1 +1,11 @@ -Author: Balloon(Cerberus) Roll Tracker, for COR This addon instantly displays your roll number, it's effect, and whether the roll is lucky or not. (As opposed to the 5 second delay you find with the chatlog. If you have rolled a lucky roll, it will also prompt you and automatically stop you from doubling up on it (which can be bypassed by either doubling up again, or typing //rolltracker autostop Enjoy. +Author: Balloon(Cerberus) + +Roll Tracker, for COR + +This addon instantly displays your roll number, it's effect, and whether the roll is lucky or not. (As opposed to the 5 second delay you find with the chatlog. + +If you have rolled a lucky roll, it will also prompt you and automatically stop you from doubling up on it (which can be bypassed by either doubling up again, or typing //rolltracker autostop. This currently doesn't work if you are also using Gearswap. + +To have the Lucky and Unlucky numbers of a roll displayed once per roll type //rolltracker luckyinfo + +Enjoy. diff --git a/addons/rolltracker/rolltracker.lua b/addons/rolltracker/rolltracker.lua index b7acacfc77..f95a5e2815 100644 --- a/addons/rolltracker/rolltracker.lua +++ b/addons/rolltracker/rolltracker.lua @@ -25,9 +25,9 @@ --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'RollTracker' -_addon.version = '1.5.0.0' +_addon.version = '1.8.0.0' _addon.author = 'Balloon' -_addon.command = 'rolltracker' +_addon.commands = {'rolltracker','rt'} require('luau') chat = require('chat') @@ -35,10 +35,11 @@ chars = require('chat.chars') packets = require('packets') defaults = {} -defaults.autostop = 0 +defaults.autostopper = true defaults.bust = 1 defaults.effected = 1 defaults.fold = 1 +defaults.luckyinfo = true settings = config.load(defaults) @@ -46,29 +47,39 @@ windower.register_event('addon command',function (...) cmd = {...} if cmd[1] ~= nil then if cmd[1]:lower() == "help" then - print('To stop rolltracker stopping rolls type: //rolltracker autostop') - print('To restart rolltracker stopping doubleup type //rolltracker Doubleup') - end - - if cmd[1]:lower() == "autostop" then - override = true - print('Disabled Autostopping Double Up') + log('To toggle rolltracker from allowing/stopping rolls type: //rolltracker autostop') + log('To toggle rolltracker from showing/hiding Lucky Info type: //rolltracker luckyinfo') + elseif cmd[1]:lower() == "autostop" then + if settings.autostopper then + settings.autostopper = false + log('Will no longer stop Double-UP on a Lucky Roll.') + else + settings.autostopper = true + log('Will stop Double-UP on a Lucky Roll.') + end + elseif cmd[1]:lower() == "luckyinfo" then + if settings.luckyinfo then + settings.luckyinfo = false + log('Lucky/Unlucky Info will no longer be displayed.') + else + settings.luckyinfo = true + log('Lucky/Unlucky Info will now be displayed.') + end end - - if cmd[1]:lower() == "doubleup" then - override = false - print('Enable Autostoppping Doubleup') - end + config.save(settings, 'all') end end) --This is done because GearSwap swaps out too fast, and sometimes things aren't reported in memory. --Therefore, we store it within rolltracker so we can do the check locally. -windower.register_event('outgoing chunk', function(id,data) - if id == 0x050 then - local packet = packets.parse('outgoing', data) - local slot = windower.ffxi.get_items(packet['Bag'])[packet['Item Index']] - gearTable[packet['Equip Slot']] = slot ~= nil and slot.id or 0 +windower.register_event('incoming chunk', function(id, data) + if id == 0x050 then + local packet = packets.parse('incoming', data) + local slot = windower.ffxi.get_items(packet['Inventory Bag'])[packet['Inventory Index']] + gearTable[packet['Equipment Slot']] = slot ~= nil and slot.id or 0 + elseif id == 0x0DD then + local packetParty = packets.parse('incoming', data) + end end) @@ -79,7 +90,7 @@ end windower.register_event('load', function() - --We need a gear table, and we need to initialise it when we load + --We need a gear table, and we need to initialise it when we load --So that if someone doesn't swap gear, at least it still works. gearTable = { [0]=getGear('main'),[1]=getGear('sub'),[2]=getGear('range'),[3]=getGear('ammo'), @@ -97,53 +108,51 @@ windower.register_event('load', function() p5 = string.char(0x1E, 6) } local rollInfoTemp = { - -- Okay, this goes 1-11 boost, Bust effect, Effect, Lucky, +1 Phantom Roll Effect, Bonus Equipment and Effect, - ['Chaos'] = {6,8,9,25,11,13,16,3,17,19,31,"-4", '% Attack!', 4, 3}, - ['Fighter\'s'] = {2,2,3,4,12,5,6,7,1,9,18,'-4','% Double-Attack!', 5, 1}, - ['Wizard\'s'] = {4,6,8,10,25,12,14,17,2,20,30, "-10", ' MAB', 5, 2}, - ['Evoker\'s'] = {1,1,1,1,3,2,2,2,1,3,4,'-1', ' Refresh!',5, 1}, - ['Rogue\'s'] = {2,2,3,4,12,5,6,6,1,8,14,'-6', '% Critical Hit Rate!', 5, 1}, - ['Corsair\'s'] = {10, 11, 11, 12, 20, 13, 15, 16, 8, 17, 24, '-6', '% Experience Bonus',5, 2}, - ['Hunter\'s'] = {10,13,15,40,18,20,25,5,27,30,50,'-?', ' Accuracy Bonus',4, 5}, - ['Magus\'s'] = {5,20,6,8,9,3,10,13,14,15,25,'-8',' Magic Defense Bonus',2, 2}, - ['Healer\'s'] = {3,4,12,5,6,7,1,8,9,10,16,'-4','% Cure Potency',3, 1}, - ['Drachen'] = {10,13,15,40,18,20,25,5,28,30,50,'-8',' Pet: Accuracy Bonus',4, 5}, - ['Choral'] = {8,42,11,15,19,4,23,27,31,35,50,'+25', '- Spell Interruption Rate',2, 0}, - ['Monk\'s'] = {8,10,32,12,14,15,4,20,22,24,40,'-?', ' Subtle Blow', 3, 4}, - ['Beast'] = {6,8,9,25,11,13,16,3,17,19,31,'-10', '% Pet: Attack Bonus',4, 3}, - ['Samurai'] = {7,32,10,12,14,4,16,20,22,24,40,'-10',' Store TP Bonus',2, 4}, - ['Warlock\'s'] = {2,3,4,12,5,6,7,1,8,9,15,'-5',' Magic Accuracy Bonus',4, 1}, - ['Puppet'] = {5,8,35,11,14,18,2,22,26,30,40,'-8',' Pet: Magic Attack Bonus',3, 3}, - ['Gallant\'s'] = {4,5,15,6,7,8,3,9,10,11,20,'-10','% Defense Bonus', 3, 2.4}, - ['Dancer\'s'] = {3,4,12,5,6,7,1,8,9,10,16,'-4',' Regen',3, 2}, - ['Bolter\'s'] = {0.3,0.3,0.8,0.4,0.4,0.5,0.5,0.6,0.2,0.7,1.0,'-8','% Movement Speed',3, 0.2}, - ['Caster\'s'] = {6,15,7,8,9,10,5,11,12,13,20,'-10','% Fast Cast',2, 3,{7,11140,10}}, - ['Tactician\'s'] = {10,10,10,10,30,10,10,0,20,20,40,'-10',' Regain',5, 2, {5, 11100, 10}}, - ['Miser\'s'] = {30,50,70,90,200,110,20,130,150,170,250,'0',' Save TP',5, 15}, - ['Ninja'] = {4,5,5,14,6,7,9,2,10,11,18,'-10',' Evasion Bonus',4, 2}, - ['Scholar\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Conserve MP',2, 0}, - ['Allies\''] = {6,7,17,9,11,13,15,17,17,5,17,'?','% Skillchain Damage',3, 1,{6,11120, 5}}, - ['Companion\'s'] = {{4,20},{20, 50},{6,20},{8, 20},{10,30},{12,30},{14,30},{16,40},{18, 40}, {3,10},{30, 70},'-?',' Pet: Regen/Regain',2, {1,5}}, - ['Avenger\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Counter Rate',4, 0}, - ['Blitzer\'s'] = {2,3.4,4.5,11.3,5.3,6.4,7.2,8.3,1.5,10.2,12.1,'-?', '% Attack delay reduction',4, 1, {4,11080, 5}}, - ['Courser\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Snapshot',3, 0}, - ['Runeist\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Magic Evasion',4, 0}, - ['Naturalist\'s'] = {6,7,15,8,9,10,5,11,12,13,20,'-5','% Enhancing Magic Duration',3, 1} + -- Okay, this goes 1-11 boost, Bust effect, Effect, Lucky, Unlucky, +1 Phantom Roll Effect, Job Bonus, Bonus Equipment and Effect, + ['Allies\''] = {6,7,17,9,11,13,15,17,17,5,17,'?','% Skillchain Damage',3,10, 1,{nil,0},{6,11120, 27084, 27085, 5}}, -- Needs Eval + ['Avenger\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Counter Rate',4,8, 0,{nil,0}}, + ['Beast'] = {64,80,96,256,112,128,160,32,176,192,320,'0','% Pet: Attack Bonus',4,8, 32,{'bst',100}}, -- /1024 Confirmed + ['Blitzer\'s'] = {2,3.4,4.5,11.3,5.3,6.4,7.2,8.3,1.5,10.2,12.1,'-3','% Attack delay reduction',4,9, 1,{nil,0},{4,11080, 26772, 26773, 5}}, -- Limited Testing for Bust, Needs more data for sure probably /1024 + ['Bolter\'s'] = {0.3,0.3,0.8,0.4,0.4,0.5,0.5,0.6,0.2,0.7,1.0,'0','% Movement Speed',3,9, 0.2,{nil,0}}, + ['Caster\'s'] = {6,15,7,8,9,10,5,11,12,13,20,'-10','% Fast Cast',2,7, 3,{nil,0},{7, 11140, 27269, 27269, 10}}, + ['Chaos'] = {64,80,96,256,112,128,160,32,176,192,320,"-9.76",'% Attack!', 4,8, 32,{'drk',100}}, -- /1024 Confirmed + ['Choral'] = {8,42,11,15,19,4,23,27,31,35,50,'+25','- Spell Interruption Rate',2,6, 4,{'brd',25}}, -- SE listed Values and hell if I'm testing this + ['Companion\'s'] = {{4,20},{20,50},{6,20},{8,20},{10,30},{12,30},{14,30},{16,40},{18,40},{3,10},{25,60},'0',' Pet: Regen/Regain',2,10, {2,5},{nil,0}}, + ['Corsair\'s'] = {10, 11, 11, 12, 20, 13, 15, 16, 8, 17, 24,'-6','% Experience Bonus',5,9, 2,{'cor',5}}, -- Needs Eval on Bust/Job Bonus + ['Courser\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Snapshot',3,9, 0,{nil,0}}, -- 11160, 27443, 27444 + ['Dancer\'s'] = {3,4,12,5,6,7,1,8,9,10,16,'-4',' Regen',3,7, 2,{'dnc',4}}, -- Confirmed + ['Drachen'] = {10,13,15,40,18,20,25,5,28,30,50,'0',' Pet: Accuracy Bonus',4,8, 5,{'drg',15}}, -- Confirmed + ['Evoker\'s'] = {1,1,1,1,3,2,2,2,1,3,4,'-1',' Refresh!',5,9, 1,{'smn',1}}, -- Confirmed + ['Fighter\'s'] = {2,2,3,4,12,5,6,7,1,9,18,'-4','% Double-Attack!',5,9, 1,{'war',5}}, + ['Gallant\'s'] = {48,60,200,72,88,104,32,120,140,160,240,'-11.72','% Defense Bonus',3,7, 24,{'pld',120}}, -- /1024 Confirmed + ['Healer\'s'] = {3,4,12,5,6,7,1,8,9,10,16,'-4','% Cure Potency Received',3,7, 1,{'whm',4}}, -- Confirmed + ['Hunter\'s'] = {10,13,15,40,18,20,25,5,28,30,50,'-15',' Accuracy Bonus',4,8, 5,{'rng',15}}, -- Confirmed + ['Magus\'s'] = {5,20,6,8,9,3,10,13,14,15,25,'-8',' Magic Defense Bonus',2,6, 2,{'blu',8}}, + ['Miser\'s'] = {30,50,70,90,200,110,20,130,150,170,250,'0',' Save TP',5,7, 15,{nil,0}}, + ['Monk\'s'] = {8,10,32,12,14,15,4,20,22,24,40,'-?',' Subtle Blow', 3,7, 4,{'mnk',10}}, + ['Naturalist\'s'] = {6,7,15,8,9,10,5,11,12,13,20,'-5','% Enhancing Magic Duration',3,7, 1,{'geo',5}}, -- Confirmed + ['Ninja'] = {10,13,15,40,18,20,25,5,28,30,50,'-15',' Evasion Bonus',4,8, 5,{'nin',15}}, -- Confirmed + ['Puppet'] = {5,8,35,11,14,18,2,22,26,30,40,'-8',' Pet: MAB/MAcc',3,7, 3,{'pup',12}}, + ['Rogue\'s'] = {2,2,3,4,12,5,6,6,1,8,14,'-6','% Critical Hit Rate!',5,9, 1,{'thf',5}}, + ['Runeist\'s'] = {10,13,15,40,18,20,25,5,28,30,50,'-15',' Evasion Bonus',4,8, 5,{'run',15}}, -- Needs Eval + ['Samurai'] = {8,32,10,12,14,4,16,20,22,24,40,'-10',' Store TP Bonus',2,6, 4,{'sam',10}}, -- Confirmed 1(Was bad),2,3,4,5,6,7,8,11 (I Wing Test) + ['Scholar\'s'] = {2,10,3,4,4,1,5,6,7,7,12,'-3','% Conserve MP',2,6, 1,{'sch',3}}, --Needs Eval Source ATM: JP Wiki + ['Tactician\'s'] = {10,10,10,10,30,10,10,0,20,20,40,'-10',' Regain',5,8, 2,{nil,0},{5, 11100, 26930, 26931, 10}}, -- Confirmed + ['Warlock\'s'] = {10,13,15,40,18,20,25,5,28,30,50,'-15',' Magic Accuracy Bonus',4,8, 5,{'rdm',15}}, -- + ['Wizard\'s'] = {4,6,8,10,25,12,14,17,2,20,30, "-10",' MAB',5,9, 2,{'blm',10}}, } rollInfo = {} for key, val in pairs(rollInfoTemp) do rollInfo[res.job_abilities:with('english', key .. ' Roll').id] = {key, unpack(val)} end - + settings = config.load(defaults) - --Wanted to change this to true/false in config file, but it wouldn't update to everyone -- This is an inelegant solution. - override = settings.autostop == 1 and true or false end) windower.register_event('load', 'login', function() isLucky = false - ringBonus = false + rollPlusBonus = false lastRoll = 0 player = windower.ffxi.get_player() end) @@ -154,16 +163,11 @@ windower.register_event('incoming text', function(old, new, color) return true end - --Hides normal + --Hides Vanilla if old:match('.* receives the effect of .* Roll.') ~= nil then return true end - --Hides Older Battlemod versions --Antiquated - if old:match('%('..'%w+'..'%).* Roll ') then - new = old - end - return new, color end) @@ -175,11 +179,10 @@ windower.register_event('action', function(act) local rollID = act.param local rollNum = act.targets[1].actions[1].param - -- anonymous function that checks if the player.id is in the targets without wrapping it in another layer of for loops. - if + if function(act) - for i = 1, #act.targets do + for i = 1, #act.targets do if act.targets[i].id == player.id then return true end @@ -192,7 +195,7 @@ windower.register_event('action', function(act) for partyMem in pairs(party) do for effectedTarget = 1, #act.targets do --if mob is nil then the party member is not in zone, will fire an error. - if type(party[partyMem]) == 'table' and party[partyMem].mob and act.targets[effectedTarget].id == party[partyMem].mob.id then + if type(party[partyMem]) == 'table' and party[partyMem].mob and act.targets[effectedTarget].id == party[partyMem].mob.id then rollMembers[effectedTarget] = partyColour[partyMem] .. party[partyMem].name .. chat.controls.reset end end @@ -200,19 +203,23 @@ windower.register_event('action', function(act) local membersHit = table.concat(rollMembers, ', ') --fake 'ternary' assignment. if settings.effected is 1 then it'll show numbers, otherwise it won't. - local amountHit = settings.effected == 1 and '[' .. #rollMembers .. '] ' or '' + local amountHit = settings.effected == 1 and '[' .. #rollMembers .. '] ' or '' local rollBonus = RollEffect(rollID, rollNum+1) local luckChat = '' isLucky = false - if rollNum == rollInfo[rollID][15] or rollNum == 11 then + if rollNum == rollInfo[rollID][15] or rollNum == 11 then isLucky = true + windower.add_to_chat(158,'Lucky roll!') luckChat = string.char(31,158).." (Lucky!)" + elseif rollNum == rollInfo[rollID][16] then + luckChat = string.char(31,167).." (Unlucky!)" end + if rollNum == 12 and #rollMembers > 0 then windower.add_to_chat(1, string.char(31,167)..amountHit..'Bust! '..chat.controls.reset..chars.implies..' '..membersHit..' '..chars.implies..' ('..rollInfo[rollID][rollNum+1]..rollInfo[rollID][14]..')') else - windower.add_to_chat(1, amountHit..membersHit..chat.controls.reset..' '..chars.implies..' '..rollInfo[rollID][1]..' Roll '..chars['circle' .. rollNum]..luckChat..string.char(31,13)..' (+'..rollBonus..')'..BustRate(rollNum, id)) + windower.add_to_chat(1, amountHit..membersHit..chat.controls.reset..' '..chars.implies..' '..rollInfo[rollID][1]..' Roll '..chars['circle' .. rollNum]..luckChat..string.char(31,13)..' (+'..rollBonus..')'..BustRate(rollNum, rollActor)..ReportRollInfo(rollID, rollActor)) end end end @@ -224,84 +231,123 @@ function RollEffect(rollid, rollnum) return end - --There's gotta be a better way to do this. local rollName = rollInfo[rollid][1] local rollVal = rollInfo[rollid][rollnum] - - if lastRoll ~= rollid then + + if lastRoll ~= rollid then lastRoll = rollid - ringBonus = false + rollPlusBonus = false + gearBonus = false + jobBonus = false end - --I'm handling one roll a bit odd, so I need to deal with it seperately. - --Which is stupid, I know, but look at how I've done most of this + --I'm handling one roll a bit odd, so I need to deal with it separately. + --Which is stupid, I know, but look at how I've done most of this. if rollName == "Companion\'s" then local hpVal = rollVal[1] local tpVal = rollVal[2] - if gearTable[9] == 26038 or ringBonus then - hpVal = hpVal + (rollInfo[rollid][16][1]*7) - tpVal = tpVal + (rollInfo[rollid][16][2]*7) - ringBonus = true - elseif gearTable[13] == 28548 or gearTable[14]== 28548 or ringBonus then - hpVal = hpVal + (rollInfo[rollid][16][1]*5) - tpVal = tpVal + (rollInfo[rollid][16][2]*5) - ringBonus = true - elseif gearTable[13] == 28547 or gearTable[14] == 28547 or ringBonus then - hpVal = hpVal + (rollInfo[rollid][16][1]*3) - tpVal = tpVal + (rollInfo[rollid][16][2]*3) - ringBonus = true + if gearTable[9] == 26038 or rollPlusBonus then + hpVal = hpVal + (rollInfo[rollid][17][1]*7) + tpVal = tpVal + (rollInfo[rollid][17][2]*7) + rollPlusBonus = true + elseif gearTable[13] == 28548 or gearTable[14]== 28548 or rollPlusBonus then + hpVal = hpVal + (rollInfo[rollid][17][1]*5) + tpVal = tpVal + (rollInfo[rollid][17][2]*5) + rollPlusBonus = true + elseif gearTable[13] == 28547 or gearTable[14] == 28547 or rollPlusBonus then + hpVal = hpVal + (rollInfo[rollid][17][1]*3) + tpVal = tpVal + (rollInfo[rollid][17][2]*3) + rollPlusBonus = true end - return "Pet:"..hpVal.." Regen".." +"..tpVal.." Regain" + return "Pet:"..hpVal.." Regen".." +"..tpVal.." Regain" end --If there's no Roll Val can't add to it if rollVal ~= '?' then - if gearTable[9] == 26038 or ringBonus then - rollVal = rollVal + (rollInfo[rollid][16]*7) - ringBonus = true - elseif gearTable[13] == 28548 or gearTable[14] == 28548 or ringBonus then - rollVal = rollVal + (rollInfo[rollid][16]*5) - ringBonus = true - elseif gearTable[13] == 28547 or gearTable[14] == 28547 or ringBonus then - rollVal = rollVal + (rollInfo[rollid][16]*3) - ringBonus = true + if gearTable[9] == 26038 or rollPlusBonus then + rollVal = rollVal + (rollInfo[rollid][17]*7) + rollPlusBonus = true + elseif gearTable[13] == 28548 or gearTable[14] == 28548 or rollPlusBonus then + rollVal = rollVal + (rollInfo[rollid][17]*5) + rollPlusBonus = true + elseif gearTable[13] == 28547 or gearTable[14] == 28547 or rollPlusBonus then + rollVal = rollVal + (rollInfo[rollid][17]*3) + rollPlusBonus = true + end + end + + --Handle Job Bonus + if (rollInfo[rollid][18][1] ~= nil) then + --Add Job is in party check + if jobBonus then + rollVal = rollVal + rollInfo[rollid][18][2] + else + jobBonus = true + rollVal = rollVal + rollInfo[rollid][18][2] end end - -- Convert Bolters to Movement Speed based on 5.0 being 100% - if(rollName == "Bolter\'s") then + + --Handle Emp +2, 109 and 119 gear bonus + if (rollInfo[rollid][19] ~= nil) then + local bonusVal = (gearTable[rollInfo[rollid][19][1]] == rollInfo[rollid][19][2] or gearTable[rollInfo[rollid][19][1]] == rollInfo[rollid][19][3] or gearTable[rollInfo[rollid][19][1]] == rollInfo[rollid][19][4]) and rollInfo[rollid][19][5] or 0 + if gearBonus == true then + rollVal = rollVal + rollInfo[rollid][19][5] + else + gearBonus = true + rollVal = rollVal + bonusVal + end + end + + -- Convert Bolter's to Movement Speed based on 5.0 being 100% + if (rollName == "Bolter\'s") then rollVal = '%.0f':format(100*((5+rollVal) / 5 - 1)) end - if(rollInfo[rollid][17] ~= nil) then - local bonusVal = gearTable[rollInfo[rollid][17][1]] == rollInfo[rollid][17][2] and rollInfo[rollid][17][3] or 0 - rollVal = rollVal + bonusVal + --Convert Beast/Chaos/Gallant's to % with 2 decimals + if (rollName == "Chaos") or (rollName == "Gallant\'s") or (rollName == "Beast") then + rollVal = '%.2f':format(rollVal/1024 * 100) end return rollVal..rollInfo[rollid][14] end -function BustRate(num, rollerID) - if num <= 5 or num == 11 or rollerID ~= player.id or settings.bust == 0 then +function BustRate(rollNum, rollActor) + if rollNum <= 5 or rollNum == 11 or rollActor ~= player.id or settings.bust == 0 then + return '' + end + return '\7 [Chance to Bust]: ' .. '%.1f':format((rollNum-5)*16.67) .. '%' +end + +--Display Lucky/Unlucky #s and check if it's already been reported once. +reportedOnce = false +function ReportRollInfo(rollID, rollActor) + if rollActor ~= player.id or not settings.luckyinfo then + return '' + elseif reportedOnce then + reportedOnce = false return '' + else + reportedOnce = true + return '\7 '..rollInfo[rollID][1]..' Roll\'s Lucky #: ' ..rollInfo[rollID][15]..' Unlucky #: '..rollInfo[rollID][16] end - return '\7 [Chance to Bust]: ' .. '%.1f':format((num-5)*16.67) .. '%' end --Checks to see if the below event has ran more than twice to enable busting ranMultiple = false windower.register_event('outgoing text', function(original, modified) + cleaned = windower.convert_auto_trans(original) modified = original - if original:match('/jobability \"Double.*Up') then - if isLucky and not override and rollActor == player.id then + if cleaned:match('/jobability \"?Double.*Up') or cleaned:match('/ja \"?Double.*Up') then + if isLucky and settings.autostopper and rollActor == player.id then windower.add_to_chat(159,'Attempting to Doubleup on a Lucky Roll: Re-double up to continue.') isLucky = false modified = "" end end - - if settings.fold == 1 and original:match('/jobability \"Fold') then + + if settings.fold == 1 and (cleaned:match('/jobability \"?Fold') or cleaned:match('/ja \"?Fold')) then local count = 0 local canBust = false @@ -309,16 +355,16 @@ windower.register_event('outgoing text', function(original, modified) local cor_buffs = S(player.buffs) * buffId canBust = cor_buffs:contains(res.buffs:with('name', 'Bust').id) or cor_buffs:length() > 1 if canBust or ranMultiple then - modified = original + modified = cleaned ranMultiple = false else windower.add_to_chat(159, 'No \'Bust\'. Fold again to continue.') ranMultiple = true modified = "" end - + return modified end return modified - + end) diff --git a/addons/salvage2/data/settings.xml b/addons/salvage2/data/settings.xml deleted file mode 100644 index 08ba0f7f94..0000000000 --- a/addons/salvage2/data/settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - 1000 - 250 - - \ No newline at end of file diff --git a/addons/salvage2/salvage2.lua b/addons/salvage2/salvage2.lua index 4e8fb289ae..1d9eb7cde9 100644 --- a/addons/salvage2/salvage2.lua +++ b/addons/salvage2/salvage2.lua @@ -30,142 +30,146 @@ require('tables') require('strings') require('maths') require('logger') +texts = require ('texts') config = require('config') ----------------------------- -settingtab = config.load() --variables - posx = 1000 - posy = 250 - if settingtab['posx'] ~= nil then - posx = settingtab['posx'] - posy = settingtab['posy'] - end - pathos_ident = {'Main Weapon/Sub-Weapon restriction', 'Ranged Weapon/Ammo restriction', 'Head/Neck equipment restriction', 'Body equipment restriction', 'Hand equipment restriction', 'Earrings/Rings restriction', 'Back/Waist equipment restriction', 'Leg/Foot equipment restriction', 'Support Job restriction', 'Job Abilities restriction', 'Spellcasting restriction', 'Max HP Down', 'Max MP Down', 'STR Down', 'DEX Down', 'AGI Down', 'MND Down', 'INT Down', 'CHR Down', 'VIT Down'} - pathos_short = {'Weapon', 'Ranged', 'Head/Neck', 'Body', 'Hand', 'Earrings/Rings', 'Back/Waist', 'Leg/Foot', 'Support Job', 'Job Abilities', 'Spellcasting', 'Max HP', 'Max MP', 'STR', 'DEX', 'AGI', 'MND', 'INT', 'CHR', 'VIT'} +pathos_ident = {'Main Weapon/Sub-Weapon restriction', 'Ranged Weapon/Ammo restriction', 'Head/Neck equipment restriction', 'Body equipment restriction', 'Hand equipment restriction', 'Earrings/Rings restriction', 'Back/Waist equipment restriction', 'Leg/Foot equipment restriction', 'Support Job restriction', 'Job Abilities restriction', 'Spellcasting restriction', 'Max HP Down', 'Max MP Down', 'STR Down', 'DEX Down', 'AGI Down', 'MND Down', 'INT Down', 'CHR Down', 'VIT Down'} +pathos_short = {'Weapon', 'Ranged', 'Head/Neck', 'Body', 'Hand', 'Earrings/Rings', 'Back/Waist', 'Leg/Foot', 'Support Job', 'Job Abilities', 'Spellcasting', 'MaxHP', 'MaxMP', 'STR', 'DEX', 'AGI', 'MND', 'INT', 'CHR', 'VIT'} +salvage_zones = S{73, 74, 75, 76} -function settings_create() - -- get player's name - player = windower.ffxi.get_player()['name'] - -- set all pathos as needed - for i=1, #pathos_ident do - if pathos_ident[i] ~= nil then - pathos_ident[pathos_ident[i]] = 1 - end - end -end +defaults = {} +defaults.pos = {} +defaults.pos.x = 1000 +defaults.pos.y = 150 +defaults.color = {} +defaults.color.alpha = 200 +defaults.color.red = 200 +defaults.color.green = 200 +defaults.color.blue = 200 +defaults.bg = {} +defaults.bg.alpha = 200 +defaults.bg.red = 30 +defaults.bg.green = 30 +defaults.bg.blue = 30 + +settings = config.load(defaults) +salvage_box2 = texts.new('No pathos', settings) windower.register_event('addon command',function (...) local params = {...}; - if #params < 1 then - return - end - if params[1] then - if params[1]:lower() == "help" then - print('Salvage2 available commands:') - print('s2 help : Shows this help message') - print('s2 pos : Positions the list') - print('s2 [hide/show] : Hides the box') - print('s2 timer [start/stop] : Starts or stops the zone timer') - print('s2 remove : Removes the pathos from the remaining list') - elseif params[1]:lower() == "pos" then - if params[3] then - local posx, posy = tonumber(params[2]), tonumber(params[3]) - windower.text.set_location('salvage_box2', posx, posy) - end - elseif params[1]:lower() == "hide" then - windower.text.set_visibility('salvage_box2', false) - elseif params[1]:lower() == "show" then - windower.text.set_visibility('salvage_box2', true) - elseif params[1]:lower() == "timer" then - if params[2] == "start" then - windower.send_command('timers c Remaining 6000 up') - elseif params[2] == "stop" then - windower.send_command('timers d Remaining') - end - elseif params[1]:lower() == "debug" then - if params[2]:lower() == "start" then - windower.send_command('timers c Remaining 6000 up') - settings_create() - windower.text.set_visibility('salvage_box2', true) - initialize() - elseif params[2]:lower() == "stop" then - windower.send_command('timers d Remaining') - windower.text.set_visibility('salvage_box2', false) - end - elseif params[1]:lower() == "remove" then - for i=1, #pathos_short do - if pathos_short[i]:lower() == params[2]:lower() then - pathos_ident[pathos_ident[i]] = 0 - initialize() - end - end - end - end + if #params < 1 then + return + end + if params[1] then + if params[1]:lower() == "help" then + print('Salvage2 available commands:') + print('s2 help : Shows this help message') + print('s2 pos : Positions the list') + print('s2 [hide/show] : Hides the box') + print('s2 timer [start/stop] : Starts or stops the zone timer') + print('s2 remove : Removes the pathos from the remaining list') + elseif params[1]:lower() == "pos" then + if params[3] then + local posx, posy = tonumber(params[2]), tonumber(params[3]) + windower.text.set_location('salvage_box2', posx, posy) + end + elseif params[1]:lower() == "hide" then + salvage_box2:hide() + elseif params[1]:lower() == "show" then + salvage_box2:show() + elseif params[1]:lower() == "timer" then + if params[2] == "start" then + windower.send_command('timers c Remaining 6000 up') + elseif params[2] == "stop" then + windower.send_command('timers d Remaining') + end + elseif params[1]:lower() == "debug" then + if params[2]:lower() == "start" then + windower.send_command('timers c Remaining 6000 up') + settings_create() + salvage_box2:show() + initialize() + elseif params[2]:lower() == "stop" then + windower.send_command('timers d Remaining') + salvage_box2:hide() + end + elseif params[1]:lower() == "remove" then + for i=1, #pathos_short do + if pathos_short[i]:lower() == params[2]:lower() then + pathos_ident[pathos_ident[i]] = 0 + initialize() + end + end + end + end end) windower.register_event('login', function(name) - player = name + player = name end) -salvage_zones = S{73, 74, 75, 76} +function settings_create() + -- get player's name + player = windower.ffxi.get_player()['name'] + -- set all pathos as needed + for i=1, #pathos_ident do + if pathos_ident[i] ~= nil then + pathos_ident[pathos_ident[i]] = 1 + end + end +end windower.register_event('zone change', function(id) - if salvage_zones:contains(id) then - windower.send_command('timers c Remaining 6000 up') - settings_create() - initialize() - windower.text.set_visibility('salvage_box2', true) - else - windower.send_command('timers d Remaining') - settings_create() - initialize() - windower.text.set_visibility('salvage_box2', false) - end + if salvage_zones:contains(id) then + windower.send_command('timers c Remaining 6000 up') + settings_create() + initialize() + salvage_box2:show() + else + windower.send_command('timers d Remaining') + settings_create() + initialize() + salvage_box2:hide() + end end) windower.register_event('incoming text',function (original, new, color) - - a,b,pathos,name = string.find(original,'..(.*) removed for (%w+)\46') - - if pathos ~= nil then - if name == player then - -- Insert code to remove pathos from list - for i=1, #pathos_ident do - if pathos_ident[i]:lower() == pathos:lower() then - if pathos_ident[pathos_ident[i]] == 1 then - pathos_ident[pathos_ident[i]] = 0 - initialize() - end - end - end - end - return new, color - end + original = original:strip_format() + local pathos, name = original:match('(.*) removed for (%w+)') + if pathos ~= nil then + --print('Pathos found '..pathos) + if name == player then + for i=1, #pathos_ident do + if pathos_ident[i]:lower() == pathos:lower() then + if pathos_ident[pathos_ident[i]] == 1 then + pathos_ident[pathos_ident[i]] = 0 + initialize() + end + end + end + end + return new, color + end end) function initialize() - pathos_remain = (" Pathos Remaining: \n ") - for i=1, #pathos_ident do - if pathos_ident[pathos_ident[i]] == 1 then - item = pathos_short[i] - pathos_remain = (pathos_remain..item..' \n ') - end - end - windower.text.create('salvage_box2') - windower.text.set_bg_color('salvage_box2',200,30,30,30) - windower.text.set_color('salvage_box2',255,200,200,200) - windower.text.set_location('salvage_box2',posx,posy) - windower.text.set_bg_visibility('salvage_box2',1) - windower.text.set_font('salvage_box2','Arial',12) - windower.text.set_text('salvage_box2', pathos_remain) - if pathos_remain == (" Pathos Remaining: \n ") then - windower.text.set_visibility('salvage_box2',false) - end + pathos_remain = (" Pathos Remaining: \n ") + for i=1, #pathos_ident do + if pathos_ident[pathos_ident[i]] == 1 then + item = pathos_short[i] + pathos_remain = (pathos_remain..item..' \n ') + end + end + salvage_box2:text(pathos_remain) + if pathos_remain == (" Pathos Remaining: \n ") then + salvage_box2:hide() + end end windower.register_event('unload',function () - windower.text.delete('salvage_box2') - windower.send_command('timers d Remaining') + windower.text.delete('salvage_box2') + windower.send_command('timers d Remaining') end ) diff --git a/addons/scoreboard/display.lua b/addons/scoreboard/display.lua index 8a750abf92..b2582d68fb 100644 --- a/addons/scoreboard/display.lua +++ b/addons/scoreboard/display.lua @@ -109,7 +109,7 @@ function Display:build_scoreboard_header() if self.db:empty() then labels = '\n' else - labels = '%23s%7s%9s\n':format('Tot', 'Pct', 'DPS') + labels = '%32s%7s%9s\n':format('Tot', 'Pct', 'DPS') end local dps_status @@ -201,7 +201,7 @@ function Display:update() else percent = '(0%)' end - display_table:append('%-16s%7d%8s %7s':format(v[1], v[2], percent, dps)) + display_table:append('%-25s%7d%8s %7s':format(v[1], v[2], percent, dps)) end alli_damage = alli_damage + v[2] -- gather this even for players not displayed player_lines = player_lines + 1 @@ -413,7 +413,7 @@ end return Display --[[ -Copyright 2013-2014, Jerry Hebert +Copyright © 2013-2014, Jerry Hebert All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/addons/scoreboard/scoreboard.lua b/addons/scoreboard/scoreboard.lua index 61260ddd0d..893cefb641 100644 --- a/addons/scoreboard/scoreboard.lua +++ b/addons/scoreboard/scoreboard.lua @@ -2,7 +2,7 @@ _addon.name = 'Scoreboard' _addon.author = 'Suji' -_addon.version = '1.11' +_addon.version = '1.14' _addon.commands = {'sb', 'scoreboard'} require('tables') @@ -69,7 +69,7 @@ end -- Handle addon args windower.register_event('addon command', function() - local chatmodes = S{'s', 'l', 'p', 't', 'say', 'linkshell', 'party', 'tell'} + local chatmodes = S{'s', 'l', 'l2', 'p', 't', 'say', 'linkshell', 'linkshell2', 'party', 'tell', 'echo'} return function(command, ...) if command == 'e' then @@ -87,6 +87,7 @@ windower.register_event('addon command', function() sb_output('sb reset : Reset damage') sb_output('sb report [] : Reports damage. Can take standard chatmode target options.') sb_output('sb reportstat [] [] : Reports the given stat. Can take standard chatmode target options. Ex: //sb rs acc p') + sb_output('Valid chatmode targets are: ' .. chatmodes:concat(', ')) sb_output('sb filter show : Shows current filter settings') sb_output('sb filter add ... : Add mob patterns to the filter (substrings ok)') sb_output('sb filter clear : Clears mob filter') @@ -183,10 +184,14 @@ windower.register_event('addon command', function() if arg then if chatmodes:contains(arg) then - if arg2 and not arg2:match('^[a-zA-Z]+$') then - -- should be a valid player name - error('Invalid argument for report t: ' .. arg2) - return + if arg == 't' or arg == 'tell' then + if not arg2 then + -- should be a valid player name + error('Invalid argument for report t: Please include player target name.') + return + elseif not arg2:match('^[a-zA-Z]+$') then + error('Invalid argument for report t: ' .. arg2) + end end else error('Invalid parameter passed to report: ' .. arg) @@ -432,6 +437,9 @@ function action_handler(raw_actionpacket) dps_db:incr_ws_misses(target:get_name(), create_mob_name(actionpacket)) elseif main.resource and main.resource == 'weapon_skills' and main.conclusion then dps_db:add_ws_damage(target:get_name(), create_mob_name(actionpacket), main.param, main.spell_id) + -- Siren's Hysteric Assault does HP drain and falls under message_id 802 + elseif main.message_id == 802 then + dps_db:add_damage(target:get_name(), create_mob_name(actionpacket), main.param) elseif main.conclusion then if main.conclusion.subject == 'target' and T(main.conclusion.objects):contains('HP') and main.param ~= 0 then dps_db:add_damage(target:get_name(), create_mob_name(actionpacket), (main.conclusion.verb == 'gains' and -1 or 1)*main.param) @@ -444,7 +452,7 @@ function action_handler(raw_actionpacket) 293,294,295,296,297,298,299, 300,301,302,385,386,387,388, 389,390,391,392,393,394,395, - 396,397,398,732}:contains(add.message_id) then + 396,397,398,732,767,768,769,770}:contains(add.message_id) then actor_name = string.format("Skillchain(%s%s)", actor_name:sub(1, 3), actor_name:len() > 3 and '.' or '') end @@ -471,44 +479,46 @@ end ActionPacket.open_listener(action_handler) -function find_pet_owner_name(actionpacket) - local pet = windower.ffxi.get_mob_by_id(actionpacket:get_id()) - local party = windower.ffxi.get_party() - - local name = nil - - for _, member in pairs(party) do - if type(member) == 'table' and member.mob then - if member.mob.pet_index and member.mob.pet_index> 0 and pet.index == member.mob.pet_index then - name = member.mob.name - break + function find_pet_owner_name(actionpacket) + local pet = windower.ffxi.get_mob_by_id(actionpacket:get_id()) + local party = windower.ffxi.get_party() + + local name = nil + + for _, member in pairs(party) do + if type(member) == 'table' and member.mob then + if member.mob.pet_index and member.mob.pet_index> 0 and pet.index == member.mob.pet_index then + name = member.mob.name + break + end end end + return name, pet.name end - return name -end -function create_mob_name(actionpacket) - local actor = actionpacket:get_actor_name() - local result = '' - local owner = find_pet_owner_name(actionpacket) - if owner ~= nil then - if string.len(actor) > 8 then - result = string.sub(actor, 1, 7)..'.' - else - result = actor - end - if settings.combinepets then - result = 'Pets' + function create_mob_name(actionpacket) + local actor = actionpacket:get_actor_name() + local result = '' + local owner, pet = find_pet_owner_name(actionpacket) + if owner ~= nil then + if string.len(actor) > 8 then + result = string.sub(actor, 1, 7)..'.' + else + result = actor + end + if settings.combinepets then + result = '' + else + result = actor + end + if pet then + result = '('..owner..')'..' '..pet + end else - result = actor + return actor end - result = result..' ('..string.sub(owner, 1, 3)..'.)' - else - return actor + return result end - return result -end config.register(settings, function(settings) update_dps_clock:loop(settings.UpdateFrequency) diff --git a/addons/send/readme.md b/addons/send/readme.md new file mode 100644 index 0000000000..e77c79f387 --- /dev/null +++ b/addons/send/readme.md @@ -0,0 +1,28 @@ +## Usage + +``` +//send +``` + +The target can be the receiver's name, `@all` to send to all instances, `@other` to send to all instances excluding the sender or `@` to send to a specific job. The command can be any valid FFXI or Windower command. + +Examples: +``` +//send @all /ma "Blizzard" + +//send @whm /ma "Haste" + +//send Mymule //reload timers +``` + +## Sending entity IDs + +Entity IDs can be sent to the receiver by appending `id` to a target specifier, like `` for the target's ID. This works not just for `` but for all common targets mentioned [here](https://github.com/Windower/Lua/wiki/FFXI-Functions#windowerffxiget_mob_by_targettarget), i.e. ``, ` + +/ta +//send Mymule /ma "Blizzard" +``` diff --git a/addons/send/readme.txt b/addons/send/readme.txt deleted file mode 100644 index 438b330bf3..0000000000 --- a/addons/send/readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -Syntax for the send command is send [playername, @others, @all, @job] [command] - -If you wish to change the color of the text added from aecho. Or any plugin that includes send atc. Near the end of the send.lua you will find the following: - -windower.add_to_chat(55,msg:sub(5)) - -You may change the 55 to any number from 1 to 255 to get a (not always) different color. diff --git a/addons/send/send.lua b/addons/send/send.lua index 89b094ddbf..7289c78f71 100644 --- a/addons/send/send.lua +++ b/addons/send/send.lua @@ -5,102 +5,95 @@ _addon.author = 'Byrth' windower.register_event('addon command',function (...) local term = table.concat({...}, ' ') - local broken_init = split(term, ' ') - local qual = table.remove(broken_init,1) - local player = windower.ffxi.get_player() - if qual:lower()==player['name']:lower() then - if broken_init ~= nil then - relevant_msg(table.concat(broken_init,' ')) - end - elseif qual:lower()=='@all' or qual:lower()=='@'..player.main_job:lower() then - if broken_init ~= nil then - relevant_msg(table.concat(broken_init,' ')) - end - windower.send_ipc_message('send ' .. term) - else - windower.send_ipc_message('send ' .. term) - end + + term = term:gsub('<(%a+)id>', function(target_string) + local entity = windower.ffxi.get_mob_by_target(target_string) + return entity and entity.id or '<' .. target_string .. 'id>' + end) + + local broken_init = split(term, ' ') + local qual = table.remove(broken_init,1) + local player = windower.ffxi.get_player() + + if player and qual:lower()==player['name']:lower() then + if broken_init ~= nil then + relevant_msg(table.concat(broken_init,' ')) + end + elseif qual:lower()=='@all' or qual:lower()=='@'..player.main_job:lower() then + if broken_init ~= nil then + relevant_msg(table.concat(broken_init,' ')) + end + windower.send_ipc_message('send ' .. term) + else + windower.send_ipc_message('send ' .. term) + end end) windower.register_event('ipc message',function (msg) - local broken = split(msg, ' ') + local broken = split(msg, ' ') local command = table.remove(broken, 1) if command ~= 'send' then return end - if #broken < 2 then return end - - local qual = table.remove(broken,1) - local player = windower.ffxi.get_player() - if qual:lower()==player.name:lower() then - relevant_msg(table.concat(broken,' ')) - end - if string.char(qual:byte(1)) == '@' then - local arg = string.char(qual:byte(2, qual:len())) - if arg:upper() == player.main_job:upper() then - if broken ~= nil then - relevant_msg(table.concat(broken,' ')) - end - elseif arg:upper() == 'ALL' then - if broken ~= nil then - relevant_msg(table.concat(broken,' ')) - end - elseif arg:upper() == 'OTHERS' then - if broken ~= nil then - relevant_msg(table.concat(broken,' ')) - end - end - end + if #broken < 2 then return end + + local qual = table.remove(broken,1) + local player = windower.ffxi.get_player() + if player and qual:lower()==player.name:lower() then + relevant_msg(table.concat(broken,' ')) + end + if string.char(qual:byte(1)) == '@' then + local arg = string.char(qual:byte(2, qual:len())) + if player and arg:upper() == player.main_job:upper() then + if broken ~= nil then + relevant_msg(table.concat(broken,' ')) + end + elseif arg:upper() == 'ALL' then + if broken ~= nil then + relevant_msg(table.concat(broken,' ')) + end + elseif arg:upper() == 'OTHERS' then + if broken ~= nil then + relevant_msg(table.concat(broken,' ')) + end + end + end end) function split(msg, match) - if msg == nil then return '' end - local length = msg:len() - local splitarr = {} - local u = 1 - while u <= length do - local nextanch = msg:find(match,u) - if nextanch ~= nil then - splitarr[#splitarr+1] = msg:sub(u,nextanch-match:len()) - if nextanch~=length then - u = nextanch+match:len() - else - u = length - end - else - splitarr[#splitarr+1] = msg:sub(u,length) - u = length+1 - end - end - return splitarr + if msg == nil then return '' end + local length = msg:len() + local splitarr = {} + local u = 1 + while u <= length do + local nextanch = msg:find(match,u) + if nextanch ~= nil then + splitarr[#splitarr+1] = msg:sub(u,nextanch-match:len()) + if nextanch~=length then + u = nextanch+match:len() + else + u = length + end + else + splitarr[#splitarr+1] = msg:sub(u,length) + u = length+1 + end + end + return splitarr end function relevant_msg(msg) - local player = windower.ffxi.get_player() - - msg:gsub("", tostring(player.name)) - msg:gsub("", tostring(player.vitals.hp)) - msg:gsub("", tostring(player.vitals.mp)) - msg:gsub("", tostring(player.vitals.hpp)) - msg:gsub("", tostring(player.vitals.mpp)) - msg:gsub("", tostring(player.vitals.tp)) - msg:gsub("", tostring(player.main_job_full)..'/'..tostring(player.sub_job_full)) - msg:gsub("", tostring(player.main_job_full)) - msg:gsub("", tostring(player.sub_job_full)) - - - - if msg:sub(1,2)=='//' then - windower.send_command(msg:sub(3)) - elseif msg:sub(1,1)=='/' then - windower.send_command('input '..msg) - elseif msg:sub(1,3)=='atc' then - windower.add_to_chat(55,msg:sub(5)) - else - windower.send_command(msg) - end + if msg:sub(1,2)=='//' then + windower.send_command(msg:sub(3)) + elseif msg:sub(1,1)=='/' then + windower.send_command('input '..msg) + elseif msg:sub(1,3)=='atc' then + windower.add_to_chat(55,msg:sub(5)) + else + windower.send_command(msg) + end end diff --git a/addons/setbgm/setbgm.lua b/addons/setbgm/setbgm.lua index 1a246e9213..da8f4648d4 100644 --- a/addons/setbgm/setbgm.lua +++ b/addons/setbgm/setbgm.lua @@ -50,11 +50,13 @@ music_types = { } songs = { + [25]='Voracious Resurgence Unknown 1', [26]='Voracious Resurgence Unknown 2', [27]='Voracious Resurgence Unknown 3', [28]='The Destiny Destroyers', [29]="Devils' Delight", [30]="Odyssey - Bumba", [31]='Voracious Resurgence Unknown 4', [32]='Voracious Resurgence Unknown 5', + [33]='Voracious Resurgence Unknown 6', [34]="We Are Vana'diel", [35]='Goddessspeed', [36]='Sortie - +3 Area', [40]='Cloister of Time and Souls', [41]='Royal Wanderlust', [42]='Snowdrift Waltz', [43]='Troubled Shadows', [44]='Where Lords Rule Not', [45]='Summers Lost', [46]='Goddess Divine', [47]='Echoes of Creation', [48]='Main Theme', [49]='Luck of the Mog', [50]='Feast of the Ladies', [51]='Abyssea - Scarlet Skies, Shadowed Plains', [52]='Melodies Errant', [53]='Shinryu', [54]='Everlasting Bonds', [55]='Provenance Watcher', [56]='Where it All Begins', [57]='Steel Sings, Blades Dance', [58]='A New Direction', [59]='The Pioneers', [60]='Into Lands Primeval - Ulbuka', [61]="Water's Umbral Knell", [62]='Keepers of the Wild', [63]='The Sacred City of Adoulin', [64]='Breaking Ground', [65]='Hades', [66]='Arciela', [67]='Mog Resort', [68]='Worlds Away', [69]="Distant Worlds (Nanaa Mihgo's version)", [70]='Monstrosity', [71]="The Pioneers (Nanaa Mihgo's version)", [72]='The Serpentine Labyrinth', [73]='The Divine', [74]='Clouds Over Ulbuka', [75]='The Price', [76]='Forever Today', [77]='Distant Worlds (Instrumental)', [78]='Forever Today (Instrumental)', [79]='Iroha', - [80]='The Boundless Black', [81]='Isle of the Gods', [82]='Wail of the Void', [83]="Rhapsodies of Vana'diel", [84]="Unknown", [85]="Ambuscade", + [80]='The Boundless Black', [81]='Isle of the Gods', [82]='Wail of the Void', [83]="Rhapsodies of Vana'diel", [84]="Full Speed Ahead!", [85]="Times Grow Tense", [86]="Shadow Lord (Record Keeper Remix)", [87]="For a Friend", [88]="Between Dreams and Reality", [89]="Disjoined One", [90]="Winds of Change", [101]='Battle Theme', [102]='Battle in the Dungeon #2', [103]='Battle Theme #2', [104]='A Road Once Traveled', [105]='Mhaura', [106]='Voyager', [107]="The Kingdom of San d'Oria", [108]="Vana'diel March", [109]='Ronfaure', [110]='The Grand Duchy of Jeuno', [111]='Blackout', [112]='Selbina', [113]='Sarutabaruta', [114]='Batallia Downs', [115]='Battle in the Dungeon', [116]='Gustaberg', [117]="Ru'Lude Gardens", [118]='Rolanberry Fields', [119]='Awakening', [120]="Vana'diel March #2", [121]='Shadow Lord', [122]='One Last Time', [123]='Hopelessness', [124]='Recollection', [125]='Tough Battle', [126]='Mog House', [127]='Anxiety', [128]='Airship', [129]='Hook, Line and Sinker', @@ -103,7 +105,7 @@ end function display_songs() windower.add_to_chat(207, 'Available songs:') - for id=40,900,5 do + for id=25,900,5 do local output = ' ' for i=0,4 do if songs[id+i] then diff --git a/addons/shortcuts/helper_functions.lua b/addons/shortcuts/helper_functions.lua index 081409ed03..092f4cfe69 100644 --- a/addons/shortcuts/helper_functions.lua +++ b/addons/shortcuts/helper_functions.lua @@ -182,7 +182,7 @@ function check_usability(player,resource,id) return true elseif L(windower.ffxi.get_abilities()[resource] or {}):contains(id) then return true - elseif resource == 'monster_abilities' and player.main_job_id == 23 and (res.monstrosity[windower.ffxi.get_mjob_data().species].tp_moves[id] or 0) <= player.main_job_level then + elseif resource == 'monster_skills' and player.main_job_id == 23 and (res.monstrosity[windower.ffxi.get_mjob_data().species].tp_moves[id] or 0) <= player.main_job_level then return true elseif resource == 'mounts' and math.floor((windower.packets.last_incoming(0x0AE):byte(math.floor(id/8)+5)%2^(id%8+1))/2^(id%8)) == 1 then return true diff --git a/addons/shortcuts/shortcuts.lua b/addons/shortcuts/shortcuts.lua index cfd8cb7548..a2f5da526e 100644 --- a/addons/shortcuts/shortcuts.lua +++ b/addons/shortcuts/shortcuts.lua @@ -24,7 +24,7 @@ --(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.version = '2.902' +_addon.version = '2.903' _addon.name = 'Shortcuts' _addon.author = 'Byrth' _addon.commands = {'shortcuts'} @@ -367,9 +367,9 @@ function interp_text(splitline,offset,modified) if num_opts > 0 then -- If there are usable options then prioritize: -- Prefix, if given -> Spells -> Job Abilities -> Weapon Skills -> Monster Skills - r_line = res[(offset == 1 and options[command_list[splitline[1]]] and command_list[splitline[1]]) or (options.spells and 'spells') or (options.job_abilities and 'job_abilities') or (options.weapon_skills and 'weapon_skills') or (options.monster_abilities and 'monster_abilities') or (options.mounts and 'mounts')][options[command_list[splitline[1]]] or options.spells or options.job_abilities or options.weapon_skills or options.monster_abilities or options.mounts] + r_line = res[(offset == 1 and options[command_list[splitline[1]]] and command_list[splitline[1]]) or (options.spells and 'spells') or (options.job_abilities and 'job_abilities') or (options.weapon_skills and 'weapon_skills') or (options.monster_skills and 'monster_skills') or (options.mounts and 'mounts')][options[command_list[splitline[1]]] or options.spells or options.job_abilities or options.weapon_skills or options.monster_skills or options.mounts] elseif num_opts == 0 then - r_line = res[(offset == 1 and nonoptions[command_list[splitline[1]]] and command_list[splitline[1]]) or (nonoptions.spells and 'spells') or (nonoptions.weapon_skills and 'weapon_skills') or (nonoptions.job_abilities and 'job_abilities') or (nonoptions.monster_abilities and 'monster_abilities') or (nonoptions.mounts and 'mounts')][nonoptions[command_list[splitline[1]]] or nonoptions.spells or nonoptions.weapon_skills or nonoptions.job_abilities or nonoptions.monster_abilities or nonoptions.mounts] + r_line = res[(offset == 1 and nonoptions[command_list[splitline[1]]] and command_list[splitline[1]]) or (nonoptions.spells and 'spells') or (nonoptions.weapon_skills and 'weapon_skills') or (nonoptions.job_abilities and 'job_abilities') or (nonoptions.monster_skills and 'monster_skills') or (nonoptions.mounts and 'mounts')][nonoptions[command_list[splitline[1]]] or nonoptions.spells or nonoptions.weapon_skills or nonoptions.job_abilities or nonoptions.monster_skills or nonoptions.mounts] end local targets = table.reassign({},r_line.targets) diff --git a/addons/shortcuts/statics.lua b/addons/shortcuts/statics.lua index 52ae8c601f..50f06af57d 100644 --- a/addons/shortcuts/statics.lua +++ b/addons/shortcuts/statics.lua @@ -36,7 +36,7 @@ validabils = {} -- List of valid prefixes to be interpreted with the resources. The values currently have no use. command_list = {['ja']='job_abilities',['jobability']='job_abilities',['so']='spells',['song']='spells',['ma']='spells',['magic']='spells',['nin']='spells',['ninjutsu']='spells', - ['ra']='Ranged Attack',['range']='Ranged Attack',['throw']='Ranged Attack',['shoot']='Ranged Attack',['monsterskill']='monster_abilities',['ms']='monster_abilities', + ['ra']='Ranged Attack',['range']='Ranged Attack',['throw']='Ranged Attack',['shoot']='Ranged Attack',['monsterskill']='monster_skills',['ms']='monster_skills', ['ws']='weapon_skills',['weaponskill']='weapon_skills',['item']='Ability',['pet']='job_abilities',['mo']='mounts',['mount']='mounts'} in_game_res_commands = {['ja']='/ja',['jobability']='/ja',['pet']='/ja', @@ -123,8 +123,6 @@ command2_list = { ['kneel']=emote_table, ['laugh']=emote_table, ['muted']=emote_table, - ['kneel']=emote_table, - ['laugh']=emote_table, ['no']=emote_table, ['nod']=emote_table, ['yes']=emote_table, @@ -165,17 +163,17 @@ command2_list = { unhandled_list = {['p']=true,['s']=true,['sh']=true,['yell']=true,['echo']=true,['t']=true,['l']=true,['breaklinkshell']=true} -- List of commands to be ignored -ignore_list = {['equip']=true,['raw']=true,['fish']=true,['dig']=true,['range']=true,['map']=true,['hide']=true,['jump']=true,['attackoff']=true,['quest']=true,['recruitlist']=true,['rlist']=true,['statustimer']=true} +ignore_list = {['equip']=true,['raw']=true,['fish']=true,['dig']=true,['range']=true,['map']=true,['hide']=true,['jump']=true,['attackoff']=true,['quest']=true,['recruitlist']=true,['rlist']=true,['statustimer']=true,['recycle']=true} -- Targets to ignore and just pass through pass_through_targs = T{'','','','','','','','','','','','','', - '','','','','','','','','','','','',''} + '','','','','','','','','','','','','',''} st_targs = T{'','','','',''} targ_reps = {t='',me='',ft='',scan='',bt='',lastst='',r='',pet='',p0='',p1='',p2='',p3='',p4='', p5='',a10='',a11='',a12='',a13='',a14='',a15='',a20='',a21='',a22='',a23='',a24='',a25='', - st='',stpc='',stal='',stnpc='',stpt=''} + st='',stpc='',stal='',stnpc='',stpt='',focust=''} language = 'english' -- windower.ffxi.get_info()['language']:lower() @@ -208,5 +206,5 @@ end validabils_it('spells') validabils_it('job_abilities') validabils_it('weapon_skills') -validabils_it('monster_abilities') +validabils_it('monster_skills') validabils_it('mounts') \ No newline at end of file diff --git a/addons/stna/stna.lua b/addons/stna/stna.lua index 2ad76704b5..8401376a5f 100644 --- a/addons/stna/stna.lua +++ b/addons/stna/stna.lua @@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'STNA' -_addon.version = '1.07' +_addon.version = '1.08' _addon.author = 'Nitrous (Shiva)' _addon.command = 'stna' @@ -69,7 +69,7 @@ windower.register_event('addon command', function(...) for i = 1, 9 do if statusTable:contains(priority[i]) then windower.send_command('send @others /ma "'..statSpell[priority[i]]..'" '..player['name']) - if priority[i] == 'Doom' then + if priority[i] == 'doom' then windower.send_command('input /item "Holy Water" '..player['name']) --Auto Holy water for doom end return diff --git a/addons/targetinfo/targetinfo.lua b/addons/targetinfo/targetinfo.lua index 038c641822..e8bbe23736 100644 --- a/addons/targetinfo/targetinfo.lua +++ b/addons/targetinfo/targetinfo.lua @@ -1,6 +1,6 @@ _addon.name = 'TargetInfo' _addon.author = 'Arcon' -_addon.version = '1.0.1.1' +_addon.version = '1.0.1.2' _addon.language = 'English' require('luau') @@ -68,7 +68,7 @@ windower.register_event('prerender', function() local mobclaim = windower.ffxi.get_mob_by_id(mob.claim_id) local target = windower.ffxi.get_mob_by_index(mob.target_index) local info = {} - info.hex = mob.id % 0x1000 + info.hex = mob.index info.full = mob.id local speed = (mob.status == 5 or mob.status == 85) and (100 * (mob.movement_speed / 4)):round(2) or (100 * (mob.movement_speed / 5 - 1)):round(2) info.speed = ( diff --git a/addons/thtracker/thtracker.lua b/addons/thtracker/thtracker.lua index 1a045ccd1a..2f05e046c2 100644 --- a/addons/thtracker/thtracker.lua +++ b/addons/thtracker/thtracker.lua @@ -27,11 +27,12 @@ _addon.name = 'THTracker' _addon.author = 'Krizz' -_addon.version = 1.1 +_addon.version = 1.2 _addon.commands = {'thtracker', 'th'} -config = require 'config' -texts = require 'texts' +config = require ('config') +texts = require ('texts') +packets = require('packets') require('logger') defaults = {} @@ -51,11 +52,13 @@ defaults.bg.blue = 30 settings = config.load(defaults) -th = texts.new('No current mob', settings) +th = texts.new('${th_string}', settings) + +local th_table = {} windower.register_event('addon command', function(command, ...) command = command and command:lower() - local args = {...} + local params = {...} if command == 'pos' then local posx, posy = tonumber(params[2]), tonumber(params[3]) @@ -74,33 +77,49 @@ windower.register_event('addon command', function(command, ...) end end) -windower.register_event('incoming text', function(original, new, color) - original = original:strip_format() - local name, count = original:match('Additional effect: Treasure Hunter effectiveness against[%s%a%a%a]- (.*) increases to (%d+).') - - if name and count then - name = name.gsub(name, "the ", "") - mob = name - th:text(' '..name..'\n TH: '..count); - th:show() - end - - local deadmob = original:match('%w+ defeats[%s%a%a%a]- (.*).') - - if deadmob then - deadmob = deadmob.gsub(deadmob, "the ", "") - end - - if deadmob == mob then - - th:text('No current mob') - th:hide() - mob = nil - end - +windower.register_event('incoming chunk', function(id, data) + if id == 0x028 then + local packet = packets.parse('incoming', data) + if packet.Category == 1 and packet['Target 1 Action 1 Has Added Effect'] and packet['Target 1 Action 1 Added Effect Message'] == 603 then + th_table[packet['Target 1 ID']] = 'TH: '..packet['Target 1 Action 1 Added Effect Param'] + update_text() + elseif packet.Category == 3 and packet['Target 1 Action 1 Message'] == 608 then + th_table[packet['Target 1 ID']] = 'TH: '..packet['Target 1 Action 1 Param'] + update_text() + end + elseif id == 0x038 then + local packet = packets.parse('incoming', data) + if th_table[packet['Mob']] and packet['Type'] == 'kesu' then + th_table[packet['Mob']] = nil + update_text() + end + elseif id == 0x00E then + local packet = packets.parse('incoming', data) + if th_table[packet['NPC']] and packet['Status'] == 0 and packet['HP %'] == 100 then + th_table[packet['NPC']] = nil + update_text() + end + end end) windower.register_event('zone change', function() - th:text('No current mob') - th:hide() -end) \ No newline at end of file + th_table = {} + update_text() +end) + +windower.register_event('target change', function() + update_text() +end) + +function update_text() + local current_string + local target = windower.ffxi.get_mob_by_target('st') or windower.ffxi.get_mob_by_target('t') + if target and th_table[target.id] then + current_string = target.name..'\n '..th_table[target.id] + th:show() + else + current_string = '' + th:hide() + end + th.th_string = current_string +end diff --git a/addons/translate/ReadMe.txt b/addons/translate/ReadMe.txt index d6eab5e0f1..73c120eee0 100644 --- a/addons/translate/ReadMe.txt +++ b/addons/translate/ReadMe.txt @@ -1,4 +1,4 @@ -Last Updated: 01/02/15 +Last Updated: 2022/01/13 Description: Translate is an addon designed to automatically translate chat text and search comments from JP to EN. It creates a dictionary using the windower resources and custom-made dictionaries (../windower/addons/translate/dicts/), and replaces incoming chat lines with the matching translation in order of longest JP phrase to shortest. @@ -10,4 +10,4 @@ This approach is not without its problems, and occasionally phrases will be tran Commands: //trans -* show original - Displays the original text. Known to double-up autotranslated phrases sometimes in search comments. Reason unclear. \ No newline at end of file +* show - Toggles display of the original text. Known to double-up autotranslated phrases sometimes in search comments. Reason unclear. \ No newline at end of file diff --git a/addons/translate/dicts/bgthread_guide.lua b/addons/translate/dicts/bgthread_guide.lua index f49fa126a2..bfc7976908 100644 --- a/addons/translate/dicts/bgthread_guide.lua +++ b/addons/translate/dicts/bgthread_guide.lua @@ -6,7 +6,7 @@ local dict = { {en="Normal",ja="普通"}, {en="Difficult",ja="むず"}, {en="Very Difficult",ja="とてもむず"}, - + {en="Menace",ja="メナス"}, {en="Voidwatch",ja="ヴォッチ"}, {en="Burrows",ja="バローズ"}, @@ -14,20 +14,19 @@ local dict = { {en="Ra'Kaznar Skirmish",ja="カザスカ"}, {en="Ra'Kaznar Skirmish",ja="スカカザ"}, {en="Ra'Kaznar Skirmish",ja="かざすか"}, - + {en="Leveling",ja="レベリング"}, {en="Aby",ja="アビ"}, {en="Altepa",ja="アルテパ"}, {en="Misareaux",ja="セア ミザレオ"}, {en="Doll",ja="ド-ル"}, - + {en="Recruiting",ja="募集"}, {en="Check seacom for jobs",ja="サチコ参照ジョブを添えてテルください"}, {en="Search Comment",ja="サチコ"}, {en="Job doesn't matter",ja="ジョブ不問"}, {en="currently",ja="現在"}, - - + {en="Hennetiel",ja="NTL"}, {en="Morimar",ja="モリマ"}, {en="Kamihr",ja="カミール"}, @@ -37,7 +36,7 @@ local dict = { {en="Foret",ja="水林"}, {en="Ceizak",ja="ケイザ"}, {en="Cirdas",ja="シルダス"}, - + {en="Trial by Fire",ja="火の試練"}, {en="Trial by Lightning",ja="雷の試練"}, {en="Trial by Earth",ja="土の試練"}, @@ -46,34 +45,34 @@ local dict = { {en="Trial by Wind",ja="風の試練"}, {en="Leviathan",ja="リヴァイアサン"}, {en="Levi",ja="リヴァ"}, - + {en="Tenzen",ja="てんぜん"}, {en="Tenzen",ja="テンゼン"}, {en="Warrior's Path",ja="武士道とは"}, - + {en="Return to Delkfutt's Tower",ja="デルクフの塔 再び"}, {en="Return to Delkfutt's Tower",ja="テルクフの塔再び"}, {en="Eald'narche",ja="エルド"}, {en="Kam'lanaut",ja="カムラ"}, {en="Stellar Fulcrum",ja="天輪"}, {en="Celestial Nexus",ja="宿星"}, - + {en="BRD",ja="吟"}, {en="GEO",ja="風"}, - + {en="Wanted (Battle)",ja="ウォンテッド"}, {en="Dragonfly",ja="トンボ"}, {en="Cost",ja="コスト"}, - + {en="Incursion",ja="インカ"}, {en="Tryl",ja="トリル"}, - + {en="*waves*",ja="ノシ"}, {en="Full Alliance",ja="フルアラ"}, - + {en="EIN",ja="エイン"}, {en="Ampuole",ja="アンプル"}, - + -- These are from wiki.ffo.jp: {en="Hugemaw Harold",ja="ひゅーじまうへらるど"}, {en="Bouncing Bertha",ja="ばうんしんぐばーさ"}, @@ -102,8 +101,7 @@ local dict = { {en="Douma Weapon",ja="どうまうぇぽん"}, {en="King Ugoprygid",ja="きんぐうるぴじっど"}, {en="Vedrfolnir",ja="う゛ぇどるふぉるにる"}, - - + {en="Ark Angel",ja="あーくえんじぇる"}, {en="Hume",ja="ひゅーむ"}, {en="Tarutaru",ja="たるたる"}, @@ -148,8 +146,7 @@ local dict = { {en="Diabolos",ja="でぃあぼろす"}, {en="Cait Sith",ja="けっとしー"}, {en="Atomos",ja="あともす"}, - - + {en="Vagary",ja="ベガリ"}, {en="Vagary",ja="ベガリーインスペクター"}, {en="Balamor",ja="バラモア"}, @@ -162,8 +159,11 @@ local dict = { {en="Hades",ja="ハデス"}, {en="upper",ja="上位"}, {en="lower",ja="下位"}, - + {en="Sinister Reign",ja="シニスターレイン"}, + + {en="Ambuscade",ja="アンバス"}, + {en="segments",ja="セグポ"} } return dict \ No newline at end of file diff --git a/addons/translate/dicts/captainhowdy_guide.lua b/addons/translate/dicts/captainhowdy_guide.lua index 60d3ca824f..e5b5855828 100644 --- a/addons/translate/dicts/captainhowdy_guide.lua +++ b/addons/translate/dicts/captainhowdy_guide.lua @@ -23,7 +23,7 @@ local dict = { {en="They are already there",ja="もおむこおにいっています"}, {en="Welcome back",ja="お帰りー"}, {en="What job?",ja="すみません、私のジョブなんですか?"}, - + -- During an event section {en="pop",ja="わかす"}, {en="Go ahead",ja="先にどうぞ"}, @@ -51,7 +51,7 @@ local dict = { {en="When is the ending?",ja="おわりますか"}, {en="You can pop next",ja="つぎわかせていいよ"}, --(You Find Nothing In The Riftworn Pyxis) || Tanakasan wa daikirai desuyo! || (ノ ゜Д゜)ノ三┸┸ - + -- Coming and Going {en="Bad",ja="だめ"}, {en="Cheap",ja="やすい"}, @@ -92,7 +92,7 @@ local dict = { {en="What happened?",ja="何かあった"}, {en="Yes, I'm coming",ja="はい行きます"}, {en="Yes, that's right",ja="はいそうです"}, - + {en="Brb, I'm going to the store",ja="りせき、コンビニで行きます"}, {en="Dont be late",ja="ちこくしないで"}, {en="Don't lie",ja="うそつかないで"}, @@ -239,8 +239,7 @@ local dict = { {en="Wyvern",ja="飛竜"}, {en="Pet",ja="ペット"}, {en="Pet",ja="よぶだす"}, - - + -- Useful words {en="Synergy",ja="相乗効果"}, {en="Carbuncle",ja="カーバンクル"}, @@ -255,8 +254,7 @@ local dict = { {en="Odin",ja="オーディン"}, {en="Alexander",ja="アレキサンダー"}, {en="Cait Sith",ja="ケット・シー"}, - - + {en="Weakness",ja="弱点"}, {en="Trigger",ja="狙って"}, {en="Blue",ja="青"}, @@ -314,8 +312,7 @@ local dict = { {en="Plasm farming",ja="メナポ"}, {en="Falling asleep",ja="寝落ち"}, {en="losing claim",ja="横取り"}, - - + -- 10/4/14 update {en="Dismemberment Brigade",ja="八つ裂き旅団"}, {en="The Worm's Turn",ja="地竜大王"}, diff --git a/addons/translate/katakana_to_romanji.lua b/addons/translate/katakana_to_romanji.lua index 40fcd83dc4..9297deb48a 100644 --- a/addons/translate/katakana_to_romanji.lua +++ b/addons/translate/katakana_to_romanji.lua @@ -47,7 +47,7 @@ katakana_to_romanji = { {en="wi",ja="ヰ"}, {en="we",ja="ヱ"}, {en="wo",ja="ヲ"}, - + {en="ga",ja="ガ"}, {en="gi",ja="ギ"}, {en="gu",ja="グ"}, @@ -73,9 +73,9 @@ katakana_to_romanji = { {en="pu",ja="プ"}, {en="pe",ja="ペ"}, {en="po",ja="ポ"}, - + {en="n",ja="ン"}, - + {en="kya",ja="キャ"}, {en="kyu",ja="キュ"}, {en="kyo",ja="キョ"}, @@ -97,7 +97,7 @@ katakana_to_romanji = { {en="rya",ja="リャ"}, {en="ryu",ja="リュ"}, {en="ryo",ja="リョ"}, - + {en="gya",ja="ギャ"}, {en="gyu",ja="ギュ"}, {en="gyo",ja="ギョ"}, diff --git a/addons/translate/translate.lua b/addons/translate/translate.lua index 22d9ed11fa..78306bc87f 100644 --- a/addons/translate/translate.lua +++ b/addons/translate/translate.lua @@ -1,4 +1,4 @@ ---Copyright (c) 2014~2015, Byrthnoth +--Copyright (c) 2014~2020, Byrthnoth --All rights reserved. --Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _addon.name = 'Translate' -_addon.version = '0.150811' +_addon.version = '2.0.0.0' _addon.author = 'Byrth' _addon.commands = {'trans','translate'} @@ -49,11 +49,15 @@ handled_resources = S{ 'items', 'job_abilities', 'job_traits', + 'job_points', 'jobs', 'key_items', + 'merit_points', 'monster_abilities', + 'monster_skills', 'monstrosity', 'moon_phases', + 'mounts', 'races', 'regions', 'skills', @@ -70,7 +74,7 @@ red_close = string.char(0xEF,0x28) green_col = ''--string.char(0x1E,2) rcol = ''--string.char(0x1E,1) - +local temp_str function to_a_code(num) local first_byte,second_byte = math.floor(num/256),num%256 @@ -196,18 +200,18 @@ trans_list['\.'] = nil windower.register_event('incoming chunk',function(id,orgi,modi,is_injected,is_blocked) if id == 0x17 and not is_injected and not is_blocked then - local out_text = modi:unpack('z',0x19) + local out_text = modi:unpack('z',0x18) out_text = translate_phrase(out_text) if not out_text then return end - if show_original then windower.add_to_chat(8,modi:sub(9,0x18):unpack('z',1)..'[Original]: '..modi:unpack('z',0x19)) end + if show_original then windower.add_to_chat(8,modi:sub(9,0x17):unpack('z',1)..'[Original]: '..modi:unpack('z',0x18)) end while #out_text > 0 do - local boundary = get_boundary_length(out_text,150) - local len = math.ceil((boundary+1+24)/2) -- Make sure there is at least one nul after the string - local out_pack = string.char(0x17,len)..modi:sub(3,0x18)..out_text:sub(1,boundary) - + local boundary = get_boundary_length(out_text,151) + local len = math.ceil((boundary+1+23)/2) -- Make sure there is at least one nul after the string + local out_pack = string.char(0x17,len)..modi:sub(3,0x17)..out_text:sub(1,boundary) + -- zero pad it while #out_pack < len*2 do out_pack = out_pack..string.char(0) @@ -308,84 +312,38 @@ windower.register_event('addon command', function(...) local commands = {...} if not commands[1] then return end if commands[1]:lower() == 'show' then - if commands[2] and commands[2]:lower() == 'original' then - show_original=not show_original - if show_original then - print('Translate: Showing the original text line.') - else - print('Translate: Hiding the original text line.') - end + show_original=not show_original + if show_original then + print('Translate: Showing the original text line.') + else + print('Translate: Hiding the original text line.') end elseif commands[1]:lower() == 'eval' and commands[2] then table.remove(commands,1) assert(loadstring(table.concat(commands, ' ')))() + elseif comamnds[1]:lower() == 'help' then + print('Translate:') + print(' show: toggles whether to show the original text (default: hide)') end end) windower.register_event('incoming text',function(org,mod,ocol,mcol,blk) if not blk and ocol == 204 then - local ret = translate_phrase(org) - if os.clock()-search_comment.ts>0.4 then - search_comment = {ts = os.clock(), reg = L{}, translated = false} - end + local ret = translate_phrase(mod) + temp_str = ret or org if ret then - if not search_comment.reg:contains(ret) then - search_comment.translated = true - search_comment.reg:append(ret) - windower.add_to_chat(204,ret) - coroutine.yield(true) - if show_original then - coroutine.sleep(0.3) - if search_comment.translated then windower.add_to_chat(8,'[Original]: '..org) end - end - end - elseif not search_comment.reg:contains(org) then - search_comment.reg:append(org) - windower.add_to_chat(204,org) - coroutine.yield(true) if show_original then - coroutine.sleep(0.3) - if search_comment.translated then windower.add_to_chat(8,'[Original]: '..org) end + windower.add_to_chat:schedule(0.3, 8,'[Original]: '..org) end - end - end -end) - - -function print_set(set,title) - if not set then - if title then - windower.add_to_chat(123,'GearSwap: print_set error '..title..' set is nil.') - else - windower.add_to_chat(123,'GearSwap: print_set error, set is nil.') - end - return - end - if title then - windower.add_to_chat(1,'------------------------- '..tostring(title)..' -------------------------') - else - windower.add_to_chat(1,'----------------------------------------------------------------') - end - if #set == table.length(set) then - for i,v in ipairs(set) do - if type(v) == 'table' and v.name then - windower.add_to_chat(8,tostring(i)..' '..tostring(v)) - else - windower.add_to_chat(8,tostring(i)..' '..tostring(v)) - end - end - else - for i,v in pairs(set) do - if type(v) == 'table' and v.name then - windower.add_to_chat(8,tostring(i)..' '..tostring(v)) - else - windower.add_to_chat(8,tostring(i)..' '..tostring(v)) + mod = ret + if org == temp_str then + blk = true + temp_str = '' end + return blk and blk or mod end end - windower.add_to_chat(1,'----------------------------------------------------------------') -end - +end) function unescape(str) return (str:gsub('%%([%%%%^%$%*%(%)%.%+%?%-%]%[])','%1')) @@ -442,4 +400,4 @@ function sjis_gsub(str,pattern,rep) end end return ret_str -end \ No newline at end of file +end