Advertisement
Guest User

synthchain.lua

a guest
Feb 19th, 2019
1,163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 31.59 KB | None | 0 0
  1. --[[
  2. Copyright © 2018,
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6.     * Redistributions of source code must retain the above copyright
  7.       notice, this list of conditions and the following disclaimer.
  8.     * Redistributions in binary form must reproduce the above copyright
  9.       notice, this list of conditions and the following disclaimer in the
  10.       documentation and/or other materials provided with the distribution.
  11.     * Neither the name of React nor the
  12.       names of its contributors may be used to endorse or promote products
  13.       derived from this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL Sammeh or Langly BE LIABLE FOR ANY
  18. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. ]]
  25.  
  26. _addon.name = 'SynthChain'
  27. _addon.author = 'Sammeh + Langly, the Indomitable Duo'
  28. _addon.version = '1.14.S'
  29. _addon.date = '9.11.2018'
  30. _addon.commands = {'synthchain'}
  31.  
  32. packets = require('packets')
  33. res = require('resources')
  34. require('tables')
  35. require('logger')
  36. require('pack')
  37. config = require('config')
  38. texts = require('texts')
  39. files = require('files')
  40.  
  41. -- Text Setup
  42. defaults = {}
  43. defaults.display = {}
  44. defaults.display.pos = {}
  45. defaults.display.pos.x = 0
  46. defaults.display.pos.y = 0
  47. defaults.display.bg = {}
  48. defaults.display.bg.red = 0
  49. defaults.display.bg.green = 0
  50. defaults.display.bg.blue = 0
  51. defaults.display.bg.alpha = 150
  52. defaults.display.text = {}
  53. defaults.display.text.font = 'Courier New'
  54. defaults.display.text.red = 255
  55. defaults.display.text.green = 255
  56. defaults.display.text.blue = 255
  57. defaults.display.text.alpha = 255
  58. defaults.display.text.size = 9
  59.  
  60. defaults.synthchainbox = {}
  61. defaults.synthchainbox.pos = {}
  62. defaults.synthchainbox.pos.x = 0
  63. defaults.synthchainbox.pos.y = 0
  64. defaults.synthchainbox.bg = {}
  65. defaults.synthchainbox.bg.red = 0
  66. defaults.synthchainbox.bg.green = 0
  67. defaults.synthchainbox.bg.blue = 0
  68. defaults.synthchainbox.bg.alpha = 150
  69. defaults.synthchainbox.text = {}
  70. defaults.synthchainbox.text.font = 'Courier New'
  71. defaults.synthchainbox.text.red = 255
  72. defaults.synthchainbox.text.green = 255
  73. defaults.synthchainbox.text.blue = 255
  74. defaults.synthchainbox.text.alpha = 255
  75. defaults.synthchainbox.text.size = 9
  76.  
  77. defaults.logging = true
  78. defaults.AddTimestamp = true
  79. defaults.TimestampFormat = '%H:%M:%S'
  80.  
  81. settings = config.load(defaults)
  82. settings:save()
  83.  
  84. name = windower.ffxi.get_player() and windower.ffxi.get_player().name
  85. text_box = texts.new(settings.display, settings)
  86. synthchainbox = texts.new(settings.synthchainbox, settings)
  87.  
  88. ValidChainOptions = S{"Liquefaction","Induration","Detonation","Scission","Impaction","Reverberation","Transfixion","Compression","Fusion","Distortion","Fragmentation","Gravitation","Light","Darkness"}
  89.  
  90. if windower.ffxi.get_player() then
  91.     synthchain_file = files.new('synthchain_'..name..'.lua')
  92.  
  93.     if synthchain_file:exists() then
  94.     else
  95.         emptyChain = {}
  96.         synthchain_file:write('return ' .. T(emptyChain):tovstring())
  97.     end
  98.  
  99.     synthchain_table = require('synthchain_'..name)
  100. end
  101.  
  102.  
  103.  
  104. ----------------------------------------------------------------
  105. -- Globals
  106. ----------------------------------------------------------------
  107. current_chain_packet_id_color = 0
  108. switch = false
  109. invonly = false
  110. info = {}
  111. lastpacket = nil
  112.  
  113. -- Modify this chain table for your desired chain. (how do we want this to look?)
  114. info.status = 'None'
  115. info.step = 1
  116. info.spirit = 0
  117.  
  118.  
  119. info.crystals = {
  120.     ['Fire Crystal'] = 0,
  121.     ['Water Crystal'] = 0,
  122.     ['Lightning Crystal'] = 0,
  123.     ['Wind Crystal'] = 0,
  124.     ['Dark Crystal'] = 0,
  125.     ['Light Crystal'] = 0,
  126.     ['Ice Crystal'] = 0,
  127.     ['Earth Crystal'] = 0}
  128.    
  129. info.spheres = {
  130.     ['Liquefaction Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  131.     ['Induration Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  132.     ['Detonation Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  133.     ['Scission Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  134.     ['Impaction Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  135.     ['Reverberation Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  136.     ['Transfixion Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  137.     ['Compression Sphere'] = { ['Count'] = 0, ['Tier'] = 1 },
  138.     ['Fusion Sphere'] = { ['Count'] = 0, ['Tier'] = 2 },
  139.     ['Distortion Sphere'] = { ['Count'] = 0, ['Tier'] = 2 },
  140.     ['Fragmentation Sphere'] = { ['Count'] = 0, ['Tier'] = 2 },
  141.     ['Gravitation Sphere'] = { ['Count'] = 0, ['Tier'] = 2 },
  142.     ['Light Sphere'] = { ['Count'] = 0, ['Tier'] = 3 },
  143.     ['Darkness Sphere'] = { ['Count'] = 0, ['Tier'] = 3 }}
  144.    
  145. info.catalysts = {
  146.     ['MC-I-SR01'] = 0,
  147.     ['MC-I-SR02'] = 0,
  148.     ['MC-I-SR03'] = 0}
  149.  
  150. info.synthchains = {
  151.     ['Liquefaction'] = {['Fire Crystal'] = 4353 },
  152.     ['Induration'] =  {['Ice Crystal'] = 8705 },
  153.     ['Detonation'] =  {['Wind Crystal'] = 13057 },
  154.     ['Scission'] =  {['Earth Crystal'] = 17409 },
  155.     ['Impaction'] =  {['Lightning Crystal'] = 21761 },
  156.     ['Reverberation'] = {['Water Crystal'] = 26113},
  157.     ['Transfixion'] = {['Light Crystal'] = 30465},
  158.     ['Compression'] = {['Dark Crystal'] = 34817},
  159.     ['Fusion'] = {['Fire Crystal'] = 37121, ['Light Crystal'] = 38657},
  160.     ['Distortion'] = {['Ice Crystal'] = 41473, ['Water Crystal'] = 42497},
  161.     ['Fragmentation'] = {['Wind Crystal'] = 45825, ['Lightning Crystal'] = 46337},
  162.     ['Gravitation'] = {['Dark Crystal'] = 51201, ['Earth Crystal'] = 50177},
  163.     ['Light'] = {['Fire Crystal'] = 53505, ['Wind Crystal'] = 54017, ['Lightning Crystal'] = 54529, ['Light Crystal'] = 55041 },
  164.     ['Darkness'] = {['Ice Crystal'] = 57857, ['Earth Crystal'] = 58369, ['Water Crystal'] = 58881, ['Dark Crystal'] = 59393 },
  165. }
  166.  
  167. function reverse_lookup_packet_id()
  168.     for index,chain in pairs(info.synthchains) do
  169.         for crystal,packet_id in pairs(chain) do
  170.             if packet_id == current_chain_packet_id_color then
  171.                 return {index,crystal,info.spheres[index..' Sphere']['Tier']}
  172.             end
  173.         end
  174.     end
  175.     return {nil,nil,nil}
  176. end
  177.  
  178. function update_synthchainbox()
  179.     local infobox = L{}
  180.     local loop_number = 1
  181.     infobox:append(' \\cs(0,255,255)Current Synthchain:\\cs(255,255,255)  ')
  182.     while loop_number <= #synthchain_table do
  183.         if loop_number == info.step then
  184.             infobox:append('\\cs(0,255,0)'..synthchain_table[loop_number])
  185.         else
  186.             infobox:append('\\cs(255,255,255)'..synthchain_table[loop_number])
  187.         end
  188.         loop_number = loop_number + 1
  189.     end
  190.     synthchainbox:clear()
  191.     synthchainbox:append(infobox:concat('\n'))
  192.     synthchainbox:show()
  193. end
  194.  
  195. function update_all_textboxes()
  196.     update_textbox()
  197.     update_synthchainbox()
  198. end
  199.  
  200. function return_color_count(count)
  201.     if count == 0 then
  202.         return '\\cs(255,0,0)'..count..'\\cs(255,255,255)'
  203.     end
  204.     if count < 10 then
  205.         return '\\cs(255,255,0)'..count..'\\cs(255,255,255)'
  206.     end
  207.     if count >= 10 then
  208.         return '\\cs(0,255,0)'..count..'\\cs(255,255,255)'
  209.     end
  210. end
  211.  
  212. function return_color_item(item)
  213.     local count = 1
  214.     local chain_data = reverse_lookup_packet_id()
  215.     while count <= #chain_data do
  216.         if item == chain_data[count] or item == chain_data[count]..' Sphere' or item == 'MC-I-SR0'..chain_data[count] then
  217.             return('\\cs(0,255,0)'..item..'\\cs(255,255,255)')
  218.         end
  219.         count = count +1
  220.     end
  221.     return(item)
  222. end
  223.  
  224. function logdata(data)
  225.     local date = os.date('*t')
  226.     local file = files.new('./logs/%s_%.4u.%.2u.%.2u.log':format(name, date.year, date.month, date.day))
  227.     if not file:exists() then
  228.         file:create()
  229.     end
  230.     file:append('%s%s\n':format(settings.AddTimestamp and os.date(settings.TimestampFormat, os.time()) or '', data:strip_format()))
  231. end
  232.  
  233. function update_textbox()
  234.     local infobox = L{}
  235.     infobox:append(' \\cs(0,255,255)Crystals:\\cs(255,255,255)')
  236.     infobox:append(return_color_item('Fire Crystal')..':         '..return_color_count(info.crystals['Fire Crystal']))
  237.     infobox:append(return_color_item('Ice Crystal')..':          '..return_color_count(info.crystals['Ice Crystal']))
  238.     infobox:append(return_color_item('Wind Crystal')..':         '..return_color_count(info.crystals['Wind Crystal']))
  239.     infobox:append(return_color_item('Earth Crystal')..':        '..return_color_count(info.crystals['Earth Crystal']))
  240.     infobox:append(return_color_item('Lightning Crystal')..':    '..return_color_count(info.crystals['Lightning Crystal']))
  241.     infobox:append(return_color_item('Water Crystal')..':        '..return_color_count(info.crystals['Water Crystal']))
  242.     infobox:append(return_color_item('Light Crystal')..':        '..return_color_count(info.crystals['Light Crystal']))
  243.     infobox:append(return_color_item('Dark Crystal')..':         '..return_color_count(info.crystals['Dark Crystal']))
  244.     infobox:append(' ')
  245.     infobox:append(' \\cs(0,255,255)Spheres:\\cs(255,255,255)')
  246.     infobox:append(return_color_item('Liquefaction Sphere')..':  '..return_color_count(info.spheres['Liquefaction Sphere']['Count']))
  247.     infobox:append(return_color_item('Induration Sphere')..':    '..return_color_count(info.spheres['Induration Sphere']['Count']))
  248.     infobox:append(return_color_item('Detonation Sphere')..':    '..return_color_count(info.spheres['Detonation Sphere']['Count']))
  249.     infobox:append(return_color_item('Scission Sphere')..':      '..return_color_count(info.spheres['Scission Sphere']['Count']))
  250.     infobox:append(return_color_item('Impaction Sphere')..':     '..return_color_count(info.spheres['Impaction Sphere']['Count']))
  251.     infobox:append(return_color_item('Reverberation Sphere')..': '..return_color_count(info.spheres['Reverberation Sphere']['Count']))
  252.     infobox:append(return_color_item('Transfixion Sphere')..':   '..return_color_count(info.spheres['Transfixion Sphere']['Count']))
  253.     infobox:append(return_color_item('Compression Sphere')..':   '..return_color_count(info.spheres['Compression Sphere']['Count']))
  254.     infobox:append(return_color_item('Fusion Sphere')..':        '..return_color_count(info.spheres['Fusion Sphere']['Count']))
  255.     infobox:append(return_color_item('Distortion Sphere')..':    '..return_color_count(info.spheres['Distortion Sphere']['Count']))
  256.     infobox:append(return_color_item('Fragmentation Sphere')..': '..return_color_count(info.spheres['Fragmentation Sphere']['Count']))
  257.     infobox:append(return_color_item('Gravitation Sphere')..':   '..return_color_count(info.spheres['Gravitation Sphere']['Count']))
  258.     infobox:append(return_color_item('Light Sphere')..':         '..return_color_count(info.spheres['Light Sphere']['Count']))
  259.     infobox:append(return_color_item('Darkness Sphere')..':      '..return_color_count(info.spheres['Darkness Sphere']['Count']))
  260.     infobox:append(' ')
  261.     infobox:append(' \\cs(0,255,255)Catalysts:\\cs(255,255,255)')
  262.     infobox:append(return_color_item('MC-I-SR01')..':            '..return_color_count(info.catalysts['MC-I-SR01']))
  263.     infobox:append(return_color_item('MC-I-SR02')..':            '..return_color_count(info.catalysts['MC-I-SR02']))
  264.     infobox:append(return_color_item('MC-I-SR03')..':            '..return_color_count(info.catalysts['MC-I-SR03']))
  265.     infobox:append(' ')
  266.     infobox:append(' ')
  267.     infobox:append(' \\cs(0,255,255)Spirit:\\cs(255,255,255)              '..info.spirit)
  268.    
  269.     text_box:clear()
  270.     text_box:append(infobox:concat('\n'))
  271.     text_box:show()
  272. end
  273.  
  274. text_box:register_event('reload', update_all_textboxes)
  275.  
  276.  
  277. windower.register_event('load', function()
  278.     update_all_textboxes()
  279. end)
  280.  
  281. ----------------------------------------------------------------
  282. -- Commands
  283. ----------------------------------------------------------------
  284.  
  285. windower.register_event('addon command', function (command, ...)
  286.     command = command and command:lower()
  287.     local args = T{...}
  288.    
  289.     if command == "start" then
  290.         if #synthchain_table < 1 then
  291.             warning('Synthchain Table Empty.  Please use //synthchain setchain Element1 Element2 Element3')
  292.             return
  293.         end
  294.         info.step = 1  -- resetting Chain back to 0 to start.
  295.         if settings.logging then
  296.            logdata("Start Command Issued.")
  297.         end
  298.        
  299.         notice('Starting SynthChain.')
  300.         switch = true
  301.         info.status = 'Open Menu'
  302.         local focuser = get_marray('synthesis focuser ii')
  303.         poke_npc(focuser[1].id, focuser[1].index)
  304.         return
  305.     end
  306.    
  307.     if command == "inv" then
  308.         if settings.logging then
  309.            logdata("Loading Inventory Start.")
  310.         end
  311.        
  312.         notice('Loading Inventory')
  313.         invonly = true
  314.         switch = true
  315.         info.status = 'Open Menu'
  316.         local focuser = get_marray('synthesis focuser ii')
  317.         poke_npc(focuser[1].id, focuser[1].index)
  318.     end
  319.  
  320.     if command == 'killmenu' then
  321.         if settings.logging then
  322.            logdata("Killing Menu Manually.")
  323.         end
  324.        
  325.         focuser_packet(10,false)
  326.     end
  327.    
  328.     if command == "stop" then
  329.         if settings.logging then
  330.            logdata("Stop Issued. Exiting Menu.")
  331.         end
  332.         notice('Stopping SynthChain.  Please wait for current synth to End and Exit Menu')
  333.         switch = false
  334.         coroutine.sleep(10)
  335.         focuser_packet(10,false)
  336.         notice('Exit Complete.')
  337.         return
  338.     end
  339.    
  340.     if command == "setchain" then
  341.         for i,v in pairs(args) do
  342.             local current = windower.convert_auto_trans(v)
  343.             if not ValidChainOptions:contains(current) then
  344.                 warning(v..' is not a valid Synthchain.  Please Fix.')
  345.                 return
  346.             end
  347.             args[i]=windower.convert_auto_trans(current)
  348.         end
  349.         synthchain_file:write('return ' .. T(args):tovstring())
  350.         synthchain_table = args
  351.         update_all_textboxes()
  352.     end
  353.    
  354.     if command == "log" then
  355.         if settings.logging then
  356.             settings.logging = false
  357.             settings:save()
  358.             notice('Turning off Logging')
  359.         else
  360.             settings.logging = true
  361.             settings:save()
  362.             notice('Turning on Logging')
  363.         end
  364.     end
  365.    
  366.     if command == "help" then
  367.         notice('Synthchain Help:')
  368.         notice('Step 1: Set chain.  //synthchain setchain Element1 Element2 Element3')
  369.         notice('Step 2: Stand next to Synthesis focuser and //synthchain start')
  370.         notice('You will automatically stop if you run out of spheres, crystals, or catalysts.')
  371.         notice('If you would like to stop manually, //synthchain stop')
  372.         notice('Other Commands:')
  373.         notice('...//synthchain inv         -- Populates Inventory Only')
  374.         notice('...//synthchain start       -- Starts Chain')
  375.         notice('...//synthchain stop        -- Exits Chain')
  376.         notice('...//synthchain log         -- turns on/off Debug Logging')
  377.         notice('...//synthchain setchain   -- Writes Chain. Case Sensitive. ')
  378.         notice('.......Ex: //synthchain setchain Liquefaction Impaction Fragmentation .. ..')
  379.     end
  380.    
  381. end)
  382.  
  383. ----------------------------------------------------------------
  384. -- Events
  385. ----------------------------------------------------------------
  386. windower.register_event('incoming chunk',function(id,data,modified,injected,blocked)
  387.     if id == 0x34 and info.status == 'Open Menu' then
  388.         info.status = 'Initial'
  389.         if settings.logging then
  390.             logdata("Received 0x34 back from Open Menu, Setting to Initial.")
  391.         end
  392.         if invonly then
  393.             focuser_packet(10, true)
  394.             if settings.logging then
  395.                 logdata("Setting for Inventory Load Only.")
  396.             end
  397.             return true
  398.         end
  399.         focuser_packet(10, true)
  400.         notice('Opening Chain Menu.')
  401.         if settings.logging then
  402.            logdata("Opening Initial Menu.")
  403.         end
  404.         return true
  405.     end
  406.  
  407.     if id == 0x5C and switch then
  408.         --local packet = packets.parse('incoming', data)
  409.         local packet = {}
  410.         if settings.logging then
  411.             local packet2 = packets.parse('incoming', data)
  412.             logdata("Received 0x05C. Current Status: "..info.status.."   Showing all non 0 byte packets:")
  413.             for i=0, packet2._size, 1 do
  414.                 currentChar = data:unpack('C',i)
  415.                 if currentChar ~= 0 then
  416.                     logdata("Byte "..i..": "..currentChar)
  417.                 end
  418.             end
  419.         end
  420.        
  421.        
  422.         -- Duplicate packet detection
  423.         if data == lastpacket then
  424.             if settings.logging then
  425.                 logdata("Dupe packet detected - Ignoring")
  426.             end
  427.             notice('Dupe packet detected, Ignoring')
  428.             return
  429.         end
  430.        
  431.         lastpacket = data
  432.        
  433.        
  434.         local TypePacket = 0
  435.         -- 1 = Inventory Update,  2 = Spirit Update,  3 = Ack/Shield/Other
  436.        
  437.         if data:unpack('II',33) == 0 then
  438.             TypePacket = 1
  439.         end
  440.         if data:unpack('II',33) ~= 0 then
  441.             TypePacket = 2
  442.         end
  443.         if data:unpack('C',10) == 103 and data:unpack('C',21) == 99 and data:unpack('C',13) == 0 and data:unpack('C',14) == 0 and data:unpack('C',15) == 0 then
  444.             TypePacket = 3
  445.         end
  446.        
  447.         packet['Spirit'] = data:unpack('II',33)
  448.        
  449.         if TypePacket == 1 then
  450.             packet['Fire Crystal'] = data:unpack('C',5)
  451.             packet['Ice Crystal'] = data:unpack('C',6)
  452.             packet['Wind Crystal'] = data:unpack('C',7)
  453.             packet['Earth Crystal'] = data:unpack('C',8)
  454.             packet['Lightning Crystal'] = data:unpack('C',9)
  455.             packet['Water Crystal'] = data:unpack('C',10)
  456.             packet['Light Crystal'] = data:unpack('C',11)
  457.             packet['Dark Crystal'] = data:unpack('C',12)
  458.             packet['MC-I-SR01'] = data:unpack('C',13)
  459.             packet['MC-I-SR02'] = data:unpack('C',14)
  460.             packet['MC-I-SR03'] = data:unpack('C',15)
  461.             packet['Liquefaction Sphere'] = data:unpack('C',16)
  462.             packet['Induration Sphere'] = data:unpack('C',17)
  463.             packet['Detonation Sphere'] = data:unpack('C',18)
  464.             packet['Scission Sphere'] = data:unpack('C',19)
  465.             packet['Impaction Sphere'] = data:unpack('C',20)
  466.             packet['Reverberation Sphere'] = data:unpack('C',21)
  467.             packet['Transfixion Sphere'] = data:unpack('C',22)
  468.             packet['Compression Sphere'] = data:unpack('C',23)
  469.             packet['Fusion Sphere'] = data:unpack('C',24)
  470.             packet['Distortion Sphere'] = data:unpack('C',25)
  471.             packet['Fragmentation Sphere'] = data:unpack('C',26)
  472.             packet['Gravitation Sphere'] = data:unpack('C',27)
  473.             packet['Light Sphere'] = data:unpack('C',28)
  474.             packet['Darkness Sphere'] = data:unpack('C',29)
  475.             info.crystals['Fire Crystal'] = packet['Fire Crystal']
  476.             info.crystals['Water Crystal'] = packet['Water Crystal']
  477.             info.crystals['Lightning Crystal'] = packet['Lightning Crystal']
  478.             info.crystals['Wind Crystal'] = packet['Wind Crystal']
  479.             info.crystals['Dark Crystal'] = packet['Dark Crystal']
  480.             info.crystals['Light Crystal'] = packet['Light Crystal']
  481.             info.crystals['Ice Crystal'] = packet['Ice Crystal']
  482.             info.crystals['Earth Crystal'] = packet['Earth Crystal']
  483.             info.spheres['Liquefaction Sphere']['Count'] = packet['Liquefaction Sphere']
  484.             info.spheres['Induration Sphere']['Count'] = packet['Induration Sphere']
  485.             info.spheres['Detonation Sphere']['Count'] = packet['Detonation Sphere']
  486.             info.spheres['Scission Sphere']['Count'] = packet['Scission Sphere']
  487.             info.spheres['Impaction Sphere']['Count'] = packet['Impaction Sphere']
  488.             info.spheres['Reverberation Sphere']['Count'] = packet['Reverberation Sphere']
  489.             info.spheres['Transfixion Sphere']['Count'] = packet['Transfixion Sphere']
  490.             info.spheres['Compression Sphere']['Count'] = packet['Compression Sphere']
  491.             info.spheres['Fusion Sphere']['Count'] = packet['Fusion Sphere']
  492.             info.spheres['Distortion Sphere']['Count'] = packet['Distortion Sphere']
  493.             info.spheres['Fragmentation Sphere']['Count'] = packet['Fragmentation Sphere']
  494.             info.spheres['Gravitation Sphere']['Count'] = packet['Gravitation Sphere']
  495.             info.spheres['Light Sphere']['Count'] = packet['Light Sphere']
  496.             info.spheres['Darkness Sphere']['Count'] = packet['Darkness Sphere']
  497.             info.catalysts['MC-I-SR01'] = packet['MC-I-SR01']
  498.             info.catalysts['MC-I-SR02'] = packet['MC-I-SR02']
  499.             info.catalysts['MC-I-SR03'] = packet['MC-I-SR03']
  500.             update_all_textboxes()
  501.         end
  502.        
  503.         if TypePacket == 2 then
  504.             --notice('Received updated Spirit Packet - Current spirit: '..packet['Spirit'])
  505.             info.spirit = packet['Spirit']
  506.         end
  507.            
  508.         if invonly then
  509.             if settings.logging then
  510.                 logdata("Inv only received.  Stopping and exiting Menu.")
  511.             end
  512.             invonly = false
  513.             switch = false
  514.             focuser_packet(10,false)
  515.             return
  516.         end
  517.  
  518.         if info.status == 'Initial' and TypePacket == 1 and not invonly then
  519.             --[[
  520.                 See if I have enough Catalysts, Crystals, and Sphere's for current step
  521.                 if 0, we don't have enough Catalysts, Crystals, or sphere.  Otherwise,
  522.                 we return the packet ID needed to submit the synth.
  523.             ]]
  524.             local chain_packet_id = synth_lookup(synthchain_table[info.step])
  525.             current_chain_packet_id_color = chain_packet_id
  526.             update_all_textboxes()
  527.             if chain_packet_id > 0 then
  528.                 coroutine.sleep(2)
  529.                 update_synthchainbox()
  530.                 focuser_packet(chain_packet_id, true)
  531.                 if settings.logging then
  532.                     logdata("Sending Synthchain: "..chain_packet_id..".  Setting info.status to Spirit Update")
  533.                 end
  534.                 info.status = 'Spirit Update'
  535.             else
  536.                 switch = false
  537.                 info.status = 'End'
  538.             end
  539.         elseif info.status == 'Spirit Update' and TypePacket == 2 then
  540.             --[[
  541.                 Get Packet Info:
  542.             On a Spirit Update:
  543.                 Byte 9 is animation for Skillchain.
  544.                     Value:
  545.                     0 = no animation / no chain
  546.                     1 = Liquefaction
  547.                     2 = Induration
  548.                     3 = Detonation
  549.                     4 = Scission
  550.                     5 = Impaction
  551.                     6 = Reverberation
  552.                     7 = Transfixion
  553.                     8 = Compression
  554.                     9 = Fusion
  555.                     10 = Distortion
  556.                     11 = Fragmentation
  557.                     12 = Gravitation
  558.                     13 = Light
  559.                     14 = Dark
  560.                 Byte 5 is 0 on a Synth fail, and 1 on a synth success  2 = (seems reasonably an HQ)
  561.                 Byte 17:  Correlates to the crystal used in res/elements.lua
  562.                 Byte 21:  _unknown (Seen values: 194, 134)
  563.                 Byte 22: 1 (static?)
  564.                 Byte 25: Amount of Spirit Gain/Loss
  565.                 Byte 29: Seen 0 - 80 observed - on errors seems to grow quickly;  I think could be Stability bar?  (negative? - normally at 100 and reduces by value?)
  566.             ]]
  567.             local SynthChainOptions = {
  568.                 [0] = "None",
  569.                 [1] = "Liquefaction",
  570.                 [2] = "Induration",
  571.                 [3] = "Detonation",
  572.                 [4] = "Scission",
  573.                 [5] = "Impaction",
  574.                 [6] = "Reverberation",
  575.                 [7] = "Transfixion",
  576.                 [8] = "Compression",
  577.                 [9] = "Fusion",
  578.                 [10] = "Distortion",
  579.                 [11] = "Fragmentation",
  580.                 [12] = "Gravitation",
  581.                 [13] = "Light",
  582.                 [14] = "Darkness",
  583.             }
  584.             local SynthSuccess = data:unpack('C',5)
  585.             local SynthChain = SynthChainOptions[data:unpack('C',9)]
  586.             local AnimationElement = res.elements[data:unpack('C',17)].en
  587.             local SpiritGain = data:unpack('C',25)
  588.             local Stability = data:unpack('C',29)
  589.            
  590.             info.spirit = packet['Spirit']
  591.  
  592.             if SynthSuccess == 0 then
  593.                 info.step = 1  -- We can work on timing and chose not to reset and instead repeat here.
  594.                 if settings.logging then
  595.                     notice("ERROR: Synth Fail. Resetting Chain. Current Spirit:"..info.spirit)
  596.                     logdata("ERROR: Synth Fail. Resetting Chain. Current Spirit:"..info.spirit)
  597.                 end
  598.             else
  599.                 if settings.logging then
  600.                     if SynthSuccess == 1 then
  601.                         notice("Synth Success! Chain Performed:"..SynthChain.." Spirit Gained:"..SpiritGain.." Current Spirit:"..info.spirit)
  602.                         logdata("Synth Success! Chain Performed:"..SynthChain.." Spirit Gained:"..SpiritGain.." Current Spirit:"..info.spirit)
  603.                     elseif SynthSuccess == 2 then
  604.                         notice("HQ Synth Success! Chain Performed:"..SynthChain.." Spirit Gained:"..SpiritGain.." Current Spirit:"..info.spirit)
  605.                         logdata("HQ Synth Success! Chain Performed:"..SynthChain.." Spirit Gained:"..SpiritGain.." Current Spirit:"..info.spirit)
  606.                     end
  607.                 end
  608.                 if info.step >= #synthchain_table then
  609.                     info.step = 1
  610.                     if settings.logging then
  611.                         logdata("Hit end of chain - resetting. Current Spirit:"..info.spirit)
  612.                        
  613.                     end
  614.                 else
  615.                     info.step = info.step + 1
  616.                     if settings.logging then
  617.                         logdata("Moving to next step. "..info.step.." Current Spirit:"..info.spirit)
  618.                     end
  619.                 end
  620.             end
  621.            
  622.             if settings.logging then
  623.                 logdata("Sleeping 10 for animation delay and sending ACK, setting to 'Chain Ready'")
  624.             end
  625.             coroutine.sleep(10)
  626.             focuser_packet(4,true)
  627.             info.status = 'Chain Ready'
  628.            
  629.         elseif info.status == 'Chain Ready' and TypePacket == 3 then
  630.             coroutine.sleep(1)
  631.             focuser_packet(10,true)
  632.             if switch then
  633.                 info.status = 'Initial'
  634.                 if settings.logging then
  635.                     logdata("Finished synth. Setting Status back to Initial")
  636.                 end
  637.             else
  638.                 info.status = 'End'
  639.                 warning('Chain Ended - Exiting Menu. ')
  640.                 if settings.logging then
  641.                     logdata("Chain Ended. Setting Status:"..info.status)
  642.                 end
  643.             end
  644.         end
  645.        
  646.         if info.status == 'End' then
  647.             coroutine.sleep(2)
  648.             focuser_packet(10,false)
  649.             if settings.logging then
  650.                logdata("Sending Exit Menu Packet.  Status: End")
  651.             end
  652.         end
  653.     end
  654. end)
  655.  
  656. ----------------------------------------------------------------
  657. -- Helpers
  658. ----------------------------------------------------------------
  659. --Obvious functionality
  660. function poke_npc(id, index)
  661.     if id and index then
  662.         local packet = packets.new('outgoing', 0x01A, {
  663.             ["Target"]=id,
  664.             ["Target Index"]=index,
  665.             ["Category"]=0,
  666.             ["Param"]=0,
  667.             ["_unknown1"]=0})
  668.         packets.inject(packet)
  669.     end
  670. end
  671.  
  672. --[[
  673. Check if I have the appropriate pre-req's to synth - return 0 if false, otherwise return packet ID
  674. ]]
  675. function synth_lookup(chain)
  676.     if settings.logging then
  677.        logdata("Looking up Chain.."..chain)
  678.     end
  679.        
  680.     local sphereInfo = info.spheres[chain..' Sphere']
  681.     local tier = sphereInfo['Tier']
  682.     -- Check Catalyst
  683.     if info.catalysts['MC-I-SR0'..tier] == 0 then
  684.         if settings.logging then
  685.             logdata(chain..": Out of Catalysts!")
  686.         end
  687.         warning(chain..': Out of Catalysts!')
  688.         return 0
  689.     end
  690.     -- Check Sphere's
  691.     if sphereInfo['Count'] == 0 then
  692.         if settings.logging then
  693.             logdata(chain..": Out of Spheres!")
  694.         end
  695.        
  696.         warning(chain..': Out of Spheres!')
  697.         return 0
  698.     end
  699.    
  700.     for crystal,value in pairs(info.synthchains[chain]) do
  701.         if info.crystals[crystal] > 0 then
  702.             notice(chain..': Found Crystal: '..crystal)
  703.             if settings.logging then
  704.                 logdata(chain..": Found Crystal: "..crystal)
  705.             end
  706.        
  707.             --notice('Chain Packet ID: '..value)
  708.             return value
  709.         end
  710.     end
  711.     if settings.logging then
  712.         logdata(chain..": Out of Crystals!")
  713.     end
  714.        
  715.     warning(chain..': Out of Crystals!')
  716.     return 0
  717. end
  718.  
  719. --[[
  720.     Pass an option index (4,10,chain value) as well as the automated message for exiting
  721. --]]
  722. function focuser_packet(option_index, automated)
  723.     local focuser = get_marray('synthesis focuser ii')
  724.     local packet = packets.new('outgoing', 0x05B, {
  725.         ["Target"]=focuser[1].id,
  726.         ["Option Index"]=option_index,
  727.         ["Target Index"]=focuser[1].index,
  728.         ["Zone"]=246,
  729.         ["Menu ID"]=426,
  730.         ["Automated Message"]=automated})
  731.     packets.inject(packet)
  732. end
  733.  
  734. --[[ Format of new Mob Array
  735.     Returns an array of comprehensive mob data. Useful fields below.
  736.     number:
  737.         id, index, claim_id, x, y, z, distance, facing, entity type, target index,
  738.         spawn_type, status, model_scale, heading, model_size, movement_speed,
  739.     string:
  740.         name,
  741.     booleans:
  742.         is_npc, in_alliance, charmed, in_party, valid_target
  743. --]]
  744. function get_marray(--[[optional]]name)
  745.     local marray = windower.ffxi.get_mob_array()
  746.     local target_name = name or nil
  747.     local new_marray = T{}
  748.    
  749.     for i,v in pairs(marray) do
  750.         if v.id == 0 or v.index == 0 then
  751.             marray[i] = nil
  752.         end
  753.     end
  754.    
  755.     -- If passed a target name, strip those that do not match
  756.     if target_name then
  757.         for i,v in pairs(marray) do
  758.             if v.name:lower() ~= target_name:lower() then
  759.                 marray[i] = nil
  760.             end
  761.         end
  762.     end
  763.    
  764.     for i,v in pairs(marray) do
  765.         new_marray[#new_marray + 1] = windower.ffxi.get_mob_by_index(i)
  766.     end
  767.     return new_marray
  768. end
  769.  
  770. windower.register_event('job change', function()
  771.     windower.send_command('lua r synthchain')    
  772. end)
  773.  
  774. windower.register_event('login', function()
  775.     windower.send_command('lua r synthchain')    
  776. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement