Advertisement
R3G1STRY

stunner

Aug 15th, 2013
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 19.38 KB | None | 0 0
  1. --[[
  2. Copyright (c) 2013, Registry
  3. All rights reserved.
  4.  
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7.  
  8.     * Redistributions of source code must retain the above copyright
  9.       notice, this list of conditions and the following disclaimer.
  10.     * Redistributions in binary form must reproduce the above copyright
  11.       notice, this list of conditions and the following disclaimer in the
  12.       documentation and/or other materials provided with the distribution.
  13.     * Neither the name of stunner nor the
  14.       names of its contributors may be used to endorse or promote products
  15.       derived from this software without specific prior written permission.
  16.  
  17. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. DISCLAIMED. IN NO EVENT SHALL Registry BE LIABLE FOR ANY
  21. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. ]]
  28.  
  29.  
  30. -- NOTE: Escaping horizontal tabs seems to not work in a text box.
  31. -- NOTE: Spells/abils/targets are currently set for Morimar. If possible, find a way to load different settings files for different zones.
  32. -- NOTE: Order implementation has not yet been tested.
  33. require 'luau'
  34.  
  35. _addon = _addon or {}
  36. _addon.name = 'stunner'
  37. _addon.command = 'stunner'
  38. _addon.short_command = 'stunner'
  39. _addon.version = 1.1
  40.  
  41. settings = T{}
  42. settings.abilityList = {'Incinerating Lahar', 'Volcanic Stasis', 'Tyrannical Blow', 'Blistering Roar', 'Searing Serration', 'Batholithic Shell', 'Pyroclastic Surge', 'Testudo Tremor', 'Calcifying Mist', 'Torpefying Charge'}
  43. settings.spellList = {'Dispelga', 'Breakga', 'Thundaga V', 'Thundaja', 'Aeroga V', 'Aeroja', 'Firaga V', 'Firaja', 'Stonega V', 'Stoneja', 'Kaustra', 'Meteor'}
  44. settings.targetList = {'Tojil', 'Kurma', 'Tutewehiwehi'}
  45. settings.stun = true
  46. settings.useAlacrity = true
  47. settings.order = false
  48. settings.afterWho = '(none)'
  49. settings.beforeWho = '(none)'
  50. settings.sendMessage = false
  51. settings.messageToSend = "Casting stun now! you're next!"
  52. settings.messsageToWatch = '(none)'
  53. settings.display = true
  54. settings.showTargets = true
  55. settings.showAbilities = false
  56. settings.showSpells = false
  57. settings.xPos = 700
  58. settings.yPos = 50
  59. settings.debug = false
  60.  
  61. -- Statuses that stop you from reactions.
  62. statusblock = S{
  63.     'Dead', 'Event', 'Charmed'
  64. }
  65.  
  66. -- Aliases for reactions on/off
  67. on = T{'on', 'yes', 'true'}
  68. off = T{'off', 'no', 'false'}
  69.  
  70. function event_load()
  71.     settings = config.load(settings)
  72.    
  73.     spells = {}
  74.     job_abilities = {}
  75.     mob_abilities = {}
  76.    
  77.     spell_file_name = '../../plugins/resources/spells.xml'
  78.     ja_file_name = '../../plugins/resources/abils.xml'
  79.     ma_file_name = '../libs/resources/mabils.xml'
  80.    
  81.     spell_file = files.new(spell_file_name)
  82.     ja_file = files.new(ja_file_name)
  83.     mob_abil_file = files.new(ma_file_name)
  84.    
  85.     spells = parse_resources(spell_file:readlines())
  86.     job_abilities = parse_resources(ja_file:readlines())
  87.     mob_abilities = parse_resources(mob_abil_file:readlines())
  88.    
  89.     can_stun = true
  90.     last_abil = '(none)'
  91.     last_spell = '(none)'
  92.     last_target = '(none)'
  93.    
  94.     create_display()
  95.    
  96.     send_command('alias stunner lua c stunner')
  97.    
  98.     log('Stunner is now loaded! For a list of commands please type //stunner help.')
  99.     log('There may still be bugs with this program, it was written quite quickly. If you find anything and would like to let me know, please send me a PM on ffxiah.com or guildwork.com or, additionally, you can post on github.com/r3g1stry/Lua/issues. If you post a bug report on GitHub (make sure it\'s my fork), please title it Stunner and list the issue you\'re having as a comment. Also, If you would like any sort of functionality added, feel free to ask.')
  100. end
  101.  
  102. function event_addon_command(command, ...)
  103.     command = command and command:lower() or 'status'
  104.     local args = T{...}
  105.    
  106.     -- prints help message
  107.     if command == 'help' then
  108.         write('stunner available commands:')
  109.         write('stunner help : Shows this help message')
  110.         write('stunner [off|on]: Turns stunner on or off')
  111.         write('stunner order [on|off]: Turns stun order on or off, if no mode specified it will toggle on or off')
  112.         write('stunner order [next|prev]: Sets next true or false - this is to be used in case something breaks')
  113.         write('stunner [before|after] [player]: Changes the player you are before or after in the stun order')
  114.         write('stunner message [on|off]: Turns message after stunning on or off')
  115.         write('stunner lists: Prints Target List, TP List, and Spell List to chat log')
  116.         write('stunner display [on|off]: Turns the display on or off, if no mode specified it will toggle on or off')
  117.         write('stunner [show|hide] [abilities|spells|targets]: Shows or hides specified list on display')
  118.         write('stunner xpos [x position]: Changes the x position of the display')
  119.         write('stunner ypos [y position]: Changes the y position of the display')
  120.        
  121.     -- Turns stunner off
  122.     elseif command == 'off' then
  123.         settings.stun = false
  124.         log('You have turned stunner off.')
  125.    
  126.     -- turns stunner on
  127.     elseif command == 'on' then
  128.         settings.stun = true
  129.         log('You have turned stunner on.')
  130.    
  131.     -- turns order on or off - or, alternatively, sets you next in order just in case.
  132.     elseif command == 'order' then
  133.         local status = args[1] or 'status'
  134.         if status:isin(on) then
  135.             settings.order = true
  136.             log('Order turned on.')
  137.         elseif status:isin(off) then
  138.             settings.order = false
  139.             log('Order turned off.')
  140.         elseif string.lower(status) == 'next' then
  141.             if settings.order == true then
  142.                 can_stun = true
  143.                 log('You are now next in the stun order.')
  144.             else
  145.                 log('Please set order on to use this command.')
  146.             end
  147.         elseif string.lower(status) == 'prev' then
  148.             if settings.order == true then
  149.                 can_stun = false
  150.                 log('You no longer next in the stun order.')
  151.             else
  152.                 log('Please set order on to use this command.')
  153.             end
  154.         elseif status == 'status' then
  155.             if settings.order then
  156.                 if can_stun == true then
  157.                     can_stun = false
  158.                     log('You no longer next in the stun order.')
  159.                 else
  160.                     can_stun = true
  161.                     log('You are now next in the stun order.')
  162.                 end
  163.             else
  164.                 log('Please set order on to use this command.')
  165.             end
  166.         else
  167.             error('Invalid status:', args[1])
  168.             return
  169.         end
  170.    
  171.     -- changes who you are before in stun order
  172.     elseif command == 'before' then
  173.         local player = args[1] or 'player'
  174.         if player == 'player' then
  175.             log('Currently before '..settings.beforeWho..' in the stun order.')
  176.         else
  177.             settings.beforeWho = player
  178.             log('You are now before '..settings.beforeWho..' in the stun order.')
  179.         end
  180.    
  181.     -- changes who you are after in stun order
  182.     elseif command == 'after' then
  183.         local player = args[1] or 'player'
  184.         if player == 'player' then
  185.             log('Currently after '..settings.afterWho..' in the stun order.')
  186.         else
  187.             settings.afterWho = player
  188.             log('You are now after '..settings.afterWho..' in the stun order.')
  189.         end
  190.    
  191.     -- changes x-position
  192.     elseif command == 'xpos' then
  193.         local xpos = args[1] or 'xpos'
  194.         if xpos == 'xpos' then
  195.             log('X position: '..settings.xPos)
  196.         else
  197.             settings.xPos = tonumber(xpos)
  198.             log('X position changed to: '..settings.xPos)
  199.         end
  200.    
  201.     -- changes y-position
  202.     elseif command == 'ypos' then
  203.         local ypos = args[1] or 'ypos'
  204.         if ypos == 'ypos' then
  205.             log('Y position: '..settings.yPos)
  206.         else
  207.             settings.yPos = tonumber(ypos)
  208.             log('Y position changed to: '..settings.yPos)
  209.         end
  210.    
  211.     -- shows or hides specified list on display
  212.     elseif command == 'show' or command == 'hide' then
  213.         if not args[1] then
  214.             log('List not specified - please specify abilities, spells, or targets.')
  215.             return
  216.         end
  217.         if command == 'show' then
  218.             if args[1] == 'abilities' then
  219.                 settings.showAbilities = true
  220.             elseif args[1] == 'spells' then
  221.                 settings.showSpells = true
  222.             elseif args[1] == 'targets' then
  223.                 settings.showTargets = true
  224.             else
  225.                 log('Please specify abilities, targets, or spells.')
  226.                 return         
  227.             end
  228.         else
  229.             if args[1] == 'abilities' then
  230.                 settings.showAbilities = false
  231.             elseif args[1] == 'spells' then
  232.                 settings.showSpells = false
  233.             elseif args[1] == 'targets' then
  234.                 settings.showTargets = false
  235.             else
  236.                 log('Please specify abilities, targets, or spells.')
  237.                 return         
  238.             end
  239.         end
  240.        
  241.     -- turns display on or off
  242.     elseif command == 'display' then
  243.         local status = args[1] or 'status'
  244.         if status:isin(on) then
  245.             settings.display = true
  246.             toggle_display()
  247.             log('Display turned on.')
  248.         elseif status:isin(off) then
  249.             settings.display = false
  250.             toggle_display()
  251.             log('Display turned off.')
  252.         elseif status == 'status' then
  253.             if settings.display == true then
  254.                 settings.display = false
  255.                 toggle_display()
  256.                 log('Display turned off.')
  257.             else
  258.                 settings.display = true
  259.                 toggle_display()
  260.                 log('Display turned on.')
  261.             end
  262.         else
  263.             error('Invalid status:', args[1])
  264.             return
  265.         end
  266.    
  267.     -- turns option to send message after stunning on or off
  268.     elseif command == 'message' then
  269.         local status = args[1] or 'status'
  270.         if status:isin(on) then
  271.             settings.sendMessage = true
  272.             log('Now sending message: '..settings.messageToSend)
  273.         elseif status:isin(off) then
  274.             settings.sendMessage = false
  275.             log('Message is now turned off.')
  276.         elseif status == 'status' then
  277.             if settings.sendMessage == false then
  278.                 settings.sendMessage = true
  279.                 log('Now sending message: '..settings.messageToSend)
  280.             else
  281.                 settings.sendMessage = false
  282.                 log('Message is now turned off.')
  283.             end
  284.         else
  285.             error('Invalid status:', tostring(args[1]))
  286.             return
  287.         end
  288.        
  289.     -- prints current lists
  290.     elseif command == 'lists' then
  291.         log('TP List:', settings.abilityList:empty() and '(empty)' or settings.abilityList:format('csv'))
  292.         log('Spell List:', settings.spellList:empty() and '(empty)' or settings.spellList:format('csv'))
  293.         log('Target List:', settings.targetList:empty() and '(empty)' or settings.targetList:format('csv'))
  294.    
  295.     -- ignores (and prints a warning) if unknown command is passed.
  296.     else
  297.         warning('Unkown command \''..command..'.\' Command ignored.')
  298.     end
  299.     update_display()
  300.     settings:save()
  301. end
  302.  
  303. function event_action(act)
  304.     local actor_table = get_mob_by_id(act['actor_id'])
  305.     local actor = actor_table['name']
  306.     local abil_id, spell_id, abil, spell, player
  307.    
  308.     -- 8 is player and npc spells
  309.     if act['category'] == 8 then
  310.         if act['param'] ~= 24931 then -- 24931 is start, 28787 is interrupt
  311.             return
  312.         end
  313.        
  314.         if act['targets'][1]['actions'][1]['param'] then
  315.             spell_id = tonumber(act['targets'][1]['actions'][1]['param'])
  316.             spell = string.lower(tostring(spells[spell_id]['english']))
  317.             --[[DEBUG]] if settings.debug == true then if is_mob(tonumber(act['actor_id'])) == true then log('DEBUG: Spell just used (by mob) was: '..spell..'.') else log('DEBUG: Spell just used (by player) was: '..spell..'.') end end
  318.         end
  319.        
  320.     -- 7 is player and npc abilities/weaponskills
  321.     elseif act['category'] == 7 and is_mob(tonumber(act['actor_id'])) then
  322.         if act['param'] ~= 24931 then -- 24931 is start, 28787 is interrupt
  323.             return
  324.         end
  325.  
  326.         if act['targets'][1]['actions'][1]['param'] then               
  327.             abil_id = tonumber(act['targets'][1]['actions'][1]['param']) - 256 -- have to subtract 256 from param to get ID for mabils.xml
  328.             if abil_id < 1 then
  329.                 error('Ability ID was below 1 after subtracting 256 - returning.') -- this should not happen
  330.                 return
  331.             end
  332.             abil = string.lower(tostring(mob_abilities[abil_id]['english']))
  333.             --[[DEBUG]] if settings.debug == true then log('DEBUG: Ability just used (by mob) was: '..abil..'.') end
  334.         end
  335.        
  336.     else
  337.         --[[DEBUG]] if settings.debug == true then log('DEBUG: Not ability or spell - returning.') end
  338.         return
  339.     end
  340.    
  341.     --[[DEBUG]] if settings.debug == true and settings.order == true then log('DEBUG: Order is currently turned on.') end
  342.     --[[DEBUG]] if settings.debug == true and string.lower(tostring(spell)) == 'stun' then log('DEBUG: Stun was just cast by '..actor..'.') end
  343.     --[[DEBUG]] if settings.debug == true and string.lower(tostring(actor)) == string.lower(tostring(settings.afterWho)) then log('DEBUG: Action was performed by '..settings.afterWho..'. They are before you in the stun order.') end
  344.    
  345.     if settings.order == true and string.lower(tostring(actor)) == string.lower(tostring(settings.afterWho)) and string.lower(tostring(spell)) == 'stun' then
  346.         can_stun = true
  347.     end
  348.    
  349.     if string_in_table(actor, settings.targetList) == true then
  350.         last_target = string.capitalize(actor)
  351.        
  352.         if abil then
  353.             if string_in_table(abil, settings.abilityList) == true then
  354.                 try_stun()
  355.             end
  356.             last_abil = string.capitalize(abil)
  357.         end
  358.        
  359.         if spell then
  360.             if string_in_table(spell, settings.spellList) == true then
  361.                 try_stun()
  362.             end
  363.             last_spell = string.capitalize(spell)
  364.         end
  365.     end
  366.  
  367.     update_display()
  368. end
  369.  
  370. -- Tries to stun
  371. function try_stun()
  372.     local player_status = get_player()['status']
  373.     local command_to_send
  374.    
  375.     if settings.stun == false then
  376.         notice('Stunner is inactive.')
  377.         return
  378.     end
  379.    
  380.     if settings.order == true and can_stun == false then
  381.         --[[DEBUG]] if settings.debug == true then log('DEBUG: It is not your turn in the stun order.') end
  382.         return
  383.     end
  384.    
  385.     if statusblock:contains(get_player()['status_id']) == true or string_in_table(player_status, statusblock) == true then
  386.         log('Currently unable to stun.')
  387.         return
  388.     end
  389.    
  390.     command_to_send = 'input /ma "Stun" <bt>'
  391.     if settings.useAlacrity == true then
  392.         --[[DEBUG]] if settings.debug == true then log('DEBUG: Using Alacrity.') end
  393.         command_to_send = command_to_send..';wait4;input /ja "Alacrity" <me>'
  394.     else
  395.         --[[DEBUG]] if settings.debug == true then log('DEBUG: Not using Alacrity.') end
  396.     end
  397.    
  398.     send_command(command_to_send)
  399.    
  400.     if settings.order == true then
  401.         --[[DEBUG]] if settings.debug == true then log('DEBUG: Attempting to set can_stun variable to false.') end
  402.         can_stun = false
  403.         if settings.sendMessage == true then
  404.             --[[DEBUG]] if settings.debug == true then log('DEBUG: Attempting to send message.') end
  405.             send_command('input /t '..settings.beforeWho..' '..settings.messageToSend)
  406.         end
  407.     end
  408.    
  409.     update_display()
  410. end
  411.  
  412. function create_display()
  413.     tb_create('stunner')
  414.     tb_set_bg_color('stunner',200,30,30,30)
  415.     tb_set_color('stunner',255,200,200,200)
  416.     tb_set_location('stunner',settings.xPos,settings.yPos)
  417.     tb_set_bg_visibility('stunner',1)
  418.     tb_set_font('stunner','Consolas',12)
  419.     tb_set_visibility('stunner',settings.display)
  420.     update_display()
  421. end
  422.  
  423. function update_display()
  424.     if not settings.display then
  425.         return
  426.     end
  427.    
  428.     local text = 'Stunner version: '..tonumber(_addon.version)..'        Author: r3g1stry\n\n'
  429.    
  430.     -- sets end of display title - on or off
  431.     if settings.stun then
  432.         text = text..'~~~~~~~~~ Stunner currently \\cs(0, 225, 0)active\\cr ~~~~~~~~~\n\n'
  433.     else
  434.         text = text..'~~~~~~~~ Stunner currently \\cs(225, 0, 0)inactive\\cr ~~~~~~~~\n\n'
  435.     end
  436.    
  437.     if settings.order then
  438.         text = text..'Stun order: \\cs(0, 225, 0)on\\cr'
  439.         if can_stun then
  440.             text = text..'        Next: \\cs(0, 225, 0)yes\\cr\n'
  441.         else
  442.             text = text..'        Next: \\cs(225, 0, 0)no\\cr\n'
  443.         end
  444.        
  445.         if settings.beforeWho == settings.afterWho then
  446.             text = text..'In order with: \\cs(0, 200 ,200)'..settings.beforeWho..'\\cr\n'
  447.         else
  448.             text = text..'After: \\cs(0, 200, 200)'..settings.afterWho..'\\cr          '.. 'Before: \\cs(0, 200, 200)'..settings.beforeWho..'\\cr\n'
  449.         end
  450.        
  451.         if settings.sendMessage then
  452.             text = text..'Sending message: "\\cs(220, 20, 150)'..settings.messageToSend..'\\cr"\n\n'
  453.         end
  454.     else
  455.         text = text..'Stun order: \\cs(225, 0, 0)off\\cr\n\n'
  456.     end
  457.    
  458.     if settings.showTargets then
  459.         if table.empty(settings.targetList) then
  460.             text = text..'Targets:          Last target: \\cs(0, 225, 0)'..last_target..'\n\t(none)\\cr\n\n'
  461.         else
  462.             text = text..'Targets:          Last target: \\cs(0, 225, 0)'..last_target..'\\cr'
  463.             for _,targ in ipairs(settings.targetList) do
  464.                 text = text..'\n    \\cs(0, 225, 0)'..tostring(targ)..'\\cr'
  465.             end
  466.             text = text..'\n\n'
  467.         end
  468.     else
  469.         text = text..'Last target: \\cs(0, 225, 0)'..last_target..'\\cr\n\n'
  470.     end
  471.    
  472.     if settings.showAbilities then
  473.         if table.empty(settings.abilityList) then
  474.             text = text..'Abilities:        Last used: \\cs(225, 0, 0)'..last_abil..'\n\t(none)\\cr\n\n'
  475.         else
  476.             text = text..'Abilities:        Last used: \\cs(225, 0, 0)'..last_abil..'\\cr'
  477.             for _,abil in ipairs(settings.abilityList) do
  478.                 text = text..'\n    \\cs(225, 0, 0)'..tostring(abil)..'\\cr'
  479.             end
  480.             text = text..'\n\n'
  481.         end
  482.     else
  483.         text = text..'Last ability used: \\cs(225, 0, 0)'..last_abil..'\\cr\n\n'
  484.     end
  485.    
  486.     if settings.showSpells then
  487.         if table.empty(settings.spellList) then
  488.             text = text..'Spells:           Last used: \\cs(0, 75, 225)'..last_spell..'\n\t(none)\\cr'
  489.         else
  490.             text = text..'Spells:           Last used: \\cs(0, 75, 225)'..last_spell..'\\cr'
  491.             for _,spell in ipairs(settings.spellList) do
  492.                 text = text..'\n    \\cs(0, 75, 225)'..tostring(spell)..'\\cr'
  493.             end
  494.         end
  495.     else
  496.         text = text..'Last spell used: \\cs(0, 75, 225)'..last_spell..'\\cr'
  497.     end
  498.  
  499.     tb_set_text('stunner', text)
  500. end
  501.  
  502. function toggle_display()
  503.     tb_set_visibility('stunner', settings.display)
  504. end
  505.  
  506. -- Check if the actor is actually an npc rather than a player
  507. function is_mob(id)
  508.     return get_mob_by_id(id)['is_npc']
  509. end
  510.  
  511. -- Checks if a string is in a table, case does not matter.
  512. function string_in_table(str, tab)
  513.     str = string.lower(str)
  514.     for i, arg in ipairs(tab) do
  515.         arg = tostring(arg)
  516.         arg = string.lower(arg)
  517.         if arg == str then
  518.             return true
  519.         end
  520.     end
  521.  
  522.     return false
  523. end
  524.  
  525. function parse_resources(lines_file) -- Code: Byrth (Battlemod)
  526.     local completed_table = T{}
  527.     local counter = 0
  528.     for i in ipairs(lines_file) do
  529.         local str = tostring(lines_file[i])
  530.         local g,h,typ,key = string.find(str,'<(%w+) id="(%d+)" ')
  531.         if typ == 's' then
  532.             g,h,key = string.find(str,'index="(%d+)" ')
  533.         end
  534.         if key ~=nil then
  535.             completed_table[tonumber(key)] = T{}
  536.             local q = 1
  537.             while q <= str:len() do
  538.                 local a,b,ind,val = string.find(str,'(%w+)="(.-)"',q)
  539.                 if ind~=nil then
  540.                     if ind~='id' and ind~='index' then
  541.                         completed_table[tonumber(key)][ind] = T{}
  542.                         completed_table[tonumber(key)][ind] = val:gsub('&quot;','\42'):gsub('&apos;','\39')
  543.                     end
  544.                     q = b+1
  545.                 else
  546.                     q = str:len()+1
  547.                 end
  548.             end
  549.             local k,v,english = string.find(str,'>([^<]+)</')
  550.             if english~=nil then
  551.                 completed_table[tonumber(key)][ind] = T{}
  552.                 completed_table[tonumber(key)]['english']=english
  553.             end
  554.         end
  555.     end
  556.     return completed_table
  557. end
  558.  
  559. function event_unload()
  560.     send_command('unalias stunner')
  561.     tb_delete('stunner')
  562. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement