Advertisement
Guest User

Roll Tracker - Regal Necklace Support

a guest
Apr 17th, 2017
264
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.45 KB | None | 0 0
  1. --Copyright (c) 2013-2014, Thomas Rogers
  2. --All rights reserved.
  3.  
  4. --Redistribution and use in source and binary forms, with or without
  5. --modification, are permitted provided that the following conditions are met:
  6.  
  7. --    * Redistributions of source code must retain the above copyright
  8. --      notice, this list of conditions and the following disclaimer.
  9. --    * Redistributions in binary form must reproduce the above copyright
  10. --      notice, this list of conditions and the following disclaimer in the
  11. --      documentation and/or other materials provided with the distribution.
  12. --    * Neither the name of RollTracker nor the
  13. --      names of its contributors may be used to endorse or promote products
  14. --      derived from this software without specific prior written permission.
  15.  
  16. --THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17. --ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. --WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. --DISCLAIMED. IN NO EVENT SHALL THOMAS ROGERS BE LIABLE FOR ANY
  20. --DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. --(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. --LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. --ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. --(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. --SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  
  27. _addon.name = 'RollTracker'
  28. _addon.version = '1.4.0.0'
  29. _addon.author = 'Balloon'
  30. _addon.command = 'rolltracker'
  31.  
  32. require('luau')
  33. chat = require('chat')
  34. chars = require('chat.chars')
  35. packets = require('packets')
  36.  
  37. defaults = {}
  38. defaults.autostop = 0
  39. defaults.bust = 1
  40. defaults.effected = 1
  41. defaults.fold = 1
  42.  
  43. settings = config.load(defaults)
  44.  
  45. windower.register_event('addon command',function (...)
  46.     cmd = {...}
  47.     if cmd[1] ~= nil then
  48.         if cmd[1]:lower() == "help" then
  49.             print('To stop rolltracker stopping rolls type: //rolltracker autostop')
  50.             print('To restart rolltracker stopping doubleup type //rolltracker Doubleup')  
  51.         end
  52.        
  53.         if cmd[1]:lower() == "autostop" then
  54.             override = true
  55.             print('Disabled Autostopping Double Up')
  56.         end
  57.        
  58.         if cmd[1]:lower() == "doubleup" then
  59.             override = false
  60.             print('Enable Autostoppping Doubleup')
  61.         end
  62.     end
  63. end)
  64.  
  65. --This is done because GearSwap swaps out too fast, and sometimes things aren't reported in memory.
  66. --Therefore, we store it within rolltracker so we can do the check locally.
  67. windower.register_event('outgoing chunk', function(id,data)
  68.     if id == 0x050 then
  69.         local packet = packets.parse('outgoing', data)
  70.         local slot = windower.ffxi.get_items(packet['Bag'])[packet['Item Index']]
  71.         gearTable[packet['Equip Slot']] = slot ~= nil and slot.id or 0
  72.     end
  73. end)
  74.  
  75. function getGear(slot)
  76.     local equip = windower.ffxi.get_items()['equipment']
  77.     return windower.ffxi.get_items(equip[slot..'_bag'])[equip[slot]]~= nil and windower.ffxi.get_items(equip[slot..'_bag'])[equip[slot]].id or 0
  78. end
  79.  
  80. windower.register_event('load', function()
  81.  
  82.     --We need a gear table, and we need to initialise it when we load
  83.     --So that if someone doesn't swap gear, at least it still works.
  84.     gearTable = {
  85.         [0]=getGear('main'),[1]=getGear('sub'),[2]=getGear('range'),[3]=getGear('ammo'),
  86.         [4]=getGear('head'),[9]=getGear('neck'),[11]=getGear('left_ear'),[12]=getGear('right_ear'),
  87.         [5]=getGear('body'),[6]=getGear('hands'),[13]=getGear('left_ring'),[14]=getGear('right_ring'),
  88.         [15]=getGear('back'),[10]=getGear('waist'),[7]=getGear('legs'),[8]=getGear('feet')
  89.     }
  90.     buffId = S{309} + S(res.buffs:english(string.endswith-{' Roll'})):map(table.get-{'id'})
  91.     partyColour = {
  92.         p0 = string.char(0x1E, 247),
  93.         p1 = string.char(0x1F, 204),
  94.         p2 = string.char(0x1E, 156),
  95.         p3 = string.char(0x1E, 238),
  96.         p4 = string.char(0x1E, 5),
  97.         p5 = string.char(0x1E, 6)
  98.     }
  99.     local rollInfoTemp = {
  100.         -- Okay, this goes 1-11 boost, Bust effect, Effect, Lucky, +1 Phantom Roll Effect, Bonus Equipment and Effect,
  101.         ['Chaos'] = {6,8,9,25,11,13,16,3,17,19,31,"-4", '% Attack!', 4, 3},
  102.         ['Fighter\'s'] = {2,2,3,4,12,5,6,7,1,9,18,'-4','% Double-Attack!', 5, 1},
  103.         ['Wizard\'s'] = {4,6,8,10,25,12,14,17,2,20,30, "-10", ' MAB', 5, 2},
  104.         ['Evoker\'s'] = {1,1,1,1,3,2,2,2,1,3,4,'-1', ' Refresh!',5, 1},
  105.         ['Rogue\'s'] = {2,2,3,4,12,5,6,6,1,8,14,'-6', '% Critical Hit Rate!', 5, 1},
  106.         ['Corsair\'s'] = {10, 11, 11, 12, 20, 13, 15, 16, 8, 17, 24, '-6', '% Experience Bonus',5, 2},
  107.         ['Hunter\'s'] = {10,13,15,40,18,20,25,5,27,30,50,'-?', ' Accuracy Bonus',4, 5},
  108.         ['Magus\'s'] = {5,20,6,8,9,3,10,13,14,15,25,'-8',' Magic Defense Bonus',2, 2},
  109.         ['Healer\'s'] = {3,4,12,5,6,7,1,8,9,10,16,'-4','% Cure Potency',3, 1},
  110.         ['Drachen'] = {10,13,15,40,18,20,25,5,28,30,50,'-8',' Pet: Accuracy Bonus',4, 5},
  111.         ['Choral'] = {8,42,11,15,19,4,23,27,31,35,50,'+25', '- Spell Interruption Rate',2, 0},
  112.         ['Monk\'s'] = {8,10,32,12,14,15,4,20,22,24,40,'-?', ' Subtle Blow', 3, 4},
  113.         ['Beast'] = {6,8,9,25,11,13,16,3,17,19,31,'-10', '% Pet: Attack Bonus',4, 3},
  114.         ['Samurai'] = {7,32,10,12,14,4,16,20,22,24,40,'-10',' Store TP Bonus',2, 4},
  115.         ['Warlock\'s'] = {2,3,4,12,5,6,7,1,8,9,15,'-5',' Magic Accuracy Bonus',4, 1},
  116.         ['Puppet'] = {5,8,35,11,14,18,2,22,26,30,40,'-8',' Pet: Magic Attack Bonus',3, 3},
  117.         ['Gallant\'s'] = {4,5,15,6,7,8,3,9,10,11,20,'-10','% Defense Bonus', 3, 2.4},
  118.         ['Dancer\'s'] = {3,4,12,5,6,7,1,8,9,10,16,'-4',' Regen',3, 2},
  119.         ['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},
  120.         ['Caster\'s'] = {6,15,7,8,9,10,5,11,12,13,20,'-10','% Fast Cast',2, 3,{7,11140,10}},
  121.         ['Tactician\'s'] = {10,10,10,10,30,10,10,0,20,20,40,'-10',' Regain',5, 2, {5, 11100, 10}},
  122.         ['Miser\'s'] = {30,50,70,90,200,110,20,130,150,170,250,'0',' Save TP',5, 15},
  123.         ['Ninja'] = {4,5,5,14,6,7,9,2,10,11,18,'-10',' Evasion Bonus',4, 2},
  124.         ['Scholar\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Conserve MP',2, 0},
  125.         ['Allies\''] = {6,7,17,9,11,13,15,17,17,5,17,'?','% Skillchain Damage',3, 1,{6,11120, 5}},
  126.         ['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}},
  127.         ['Avenger\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Counter Rate',4, 0},
  128.         ['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}},
  129.         ['Courser\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Snapshot',3, 0},
  130.         ['Runeist\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Magic Evasion',4, 0},
  131.         ['Naturalist\'s'] = {'?','?','?','?','?','?','?','?','?','?','?','?',' Enhancing Magic Duration',3, 0}
  132.     }
  133.  
  134.     rollInfo = {}
  135.     for key, val in pairs(rollInfoTemp) do
  136.         rollInfo[res.job_abilities:with('english', key .. ' Roll').id] = {key, unpack(val)}
  137.     end
  138.    
  139.     settings = config.load(defaults)
  140.     --Wanted to change this to true/false in config file, but it wouldn't update to everyone -- This is an inelegant solution.
  141.     override = settings.autostop == 1 and true or false
  142. end)
  143.  
  144. windower.register_event('load', 'login', function()
  145.     isLucky = false
  146.     ringBonus = false
  147.     lastRoll = 0
  148.     player = windower.ffxi.get_player()
  149. end)
  150.  
  151. windower.register_event('incoming text', function(old, new, color)
  152.     --Hides Battlemod
  153.     if old:match("Roll.* The total.*") or old:match('.*Roll.*' .. string.char(0x81, 0xA8)) or old:match('.*uses Double.*The total') and color ~= 123 then
  154.         return true
  155.     end
  156.  
  157.     --Hides normal
  158.     if old:match('.* receives the effect of .* Roll.') ~= nil then
  159.         return true
  160.     end
  161.  
  162.     --Hides Older Battlemod versions --Antiquated
  163.     if old:match('%('..'%w+'..'%).* Roll ') then
  164.         new = old
  165.     end
  166.  
  167.     return new, color
  168. end)
  169.  
  170. windower.register_event('action', function(act)
  171.     if act.category == 6 and table.containskey(rollInfo, act.param) then
  172.         --This is used later to allow/disallow busting
  173.         --If you are not the rollActor you will not be disallowed to bust.
  174.         rollActor = act.actor_id
  175.         local rollID = act.param
  176.         local rollNum = act.targets[1].actions[1].param
  177.  
  178.        
  179.         -- anonymous function that checks if the player.id is in the targets without wrapping it in another layer of for loops.
  180.         if
  181.             function(act)
  182.                 for i = 1, #act.targets do
  183.                     if act.targets[i].id == player.id then
  184.                         return true
  185.                     end
  186.                 end
  187.                 return false
  188.             end(act)
  189.         then
  190.             local party = windower.ffxi.get_party()
  191.             rollMembers = {}
  192.             for partyMem in pairs(party) do
  193.                 for effectedTarget = 1, #act.targets do
  194.                     --if mob is nil then the party member is not in zone, will fire an error.
  195.                     if type(party[partyMem]) == 'table' and party[partyMem].mob and act.targets[effectedTarget].id == party[partyMem].mob.id then  
  196.                         rollMembers[effectedTarget] = partyColour[partyMem] .. party[partyMem].name .. chat.controls.reset
  197.                     end
  198.                 end
  199.             end
  200.  
  201.             local membersHit = table.concat(rollMembers, ', ')
  202.             --fake 'ternary' assignment. if settings.effected is 1 then it'll show numbers, otherwise it won't.
  203.             local amountHit = settings.effected == 1 and '[' .. #rollMembers .. '] ' or ''            
  204.             local rollBonus = RollEffect(rollID, rollNum+1)
  205.             local luckChat = ''
  206.             isLucky = false
  207.             if rollNum == rollInfo[rollID][15] or rollNum == 11 then
  208.                 isLucky = true
  209.                 luckChat = string.char(31,158).." (Lucky!)"
  210.             end
  211.  
  212.             if rollNum == 12 and #rollMembers > 0 then
  213.                 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]..')')
  214.             else
  215.                 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))
  216.             end
  217.         end
  218.     end
  219. end)
  220.  
  221.  
  222. function RollEffect(rollid, rollnum)
  223.     if rollnum == 13 then
  224.         return
  225.     end
  226.  
  227.  
  228.     --There's gotta be a better way to do this.
  229.     local rollName = rollInfo[rollid][1]
  230.     local rollVal = rollInfo[rollid][rollnum]
  231.    
  232.     if lastRoll ~= rollid then
  233.         lastRoll = rollid
  234.         ringBonus = false
  235.     end
  236.  
  237.     --I'm handling one roll a bit odd, so I need to deal with it seperately.
  238.     --Which is stupid, I know, but look at how I've done most of this
  239.     if rollName == "Companion\'s" then
  240.         local hpVal = rollVal[1]
  241.         local tpVal = rollVal[2]
  242.         if gearTable[9] == 26038 or ringBonus then
  243.             hpVal =  hpVal + (rollInfo[rollid][16][1]*7)
  244.             tpVal = tpVal  + (rollInfo[rollid][16][2]*7)
  245.             ringBonus = true
  246.         elseif gearTable[13] == 28548 or gearTable[14]== 28548 or ringBonus then
  247.             hpVal =  hpVal + (rollInfo[rollid][16][1]*5)
  248.             tpVal = tpVal  + (rollInfo[rollid][16][2]*5)
  249.             ringBonus = true
  250.         elseif gearTable[13] == 28547 or gearTable[14] == 28547 or ringBonus then
  251.             hpVal =  hpVal + (rollInfo[rollid][16][1]*3)
  252.             tpVal = tpVal  + (rollInfo[rollid][16][2]*3)
  253.             ringBonus = true
  254.         end
  255.         return "Pet:"..hpVal.." Regen".." +"..tpVal.." Regain"
  256.     end
  257.  
  258.     --If there's no Roll Val can't add to it
  259.     if rollVal ~= '?' then
  260.         if gearTable[9] == 26038 or ringBonus then
  261.             rollVal = rollVal + (rollInfo[rollid][16]*7)
  262.             ringBonus = true
  263.         elseif gearTable[13] == 28548 or gearTable[14] == 28548 or ringBonus then
  264.             rollVal = rollVal + (rollInfo[rollid][16]*5)
  265.             ringBonus = true
  266.         elseif gearTable[13] == 28547 or gearTable[14] == 28547 or ringBonus then
  267.             rollVal = rollVal + (rollInfo[rollid][16]*3)
  268.             ringBonus = true
  269.         end
  270.     end
  271.     -- Convert Bolters to Movement Speed based on 5.0 being 100%
  272.     if(rollName == "Bolter\'s") then
  273.         rollVal = '%.0f':format(100*((5+rollVal) / 5 - 1))
  274.     end
  275.  
  276.     if(rollInfo[rollid][17] ~= nil) then
  277.         local bonusVal = gearTable[rollInfo[rollid][17][1]] == rollInfo[rollid][17][2] and rollInfo[rollid][17][3] or 0
  278.         rollVal = rollVal + bonusVal
  279.     end
  280.  
  281.     return rollVal..rollInfo[rollid][14]
  282. end
  283.  
  284.  
  285. function BustRate(num, rollerID)
  286.     if num <= 5 or num == 11 or rollerID ~= player.id or settings.bust == 0 then
  287.         return ''
  288.     end
  289.     return '\7  [Chance to Bust]: ' .. '%.1f':format((num-5)*16.67) .. '%'
  290. end
  291.  
  292. --Checks to see if the below event has ran more than twice to enable busting
  293. ranMultiple = false
  294. windower.register_event('outgoing text', function(original, modified)
  295.     modified = original
  296.     if original:match('/jobability \"Double.*Up') then
  297.         if isLucky and not override and rollActor == player.id then
  298.             windower.add_to_chat(159,'Attempting to Doubleup on a Lucky Roll: Re-double up to continue.')
  299.             isLucky = false
  300.             modified = ""
  301.         end
  302.     end
  303.    
  304.     if settings.fold == 1 and original:match('/jobability \"Fold') then
  305.         local count = 0
  306.         local canBust = false
  307.  
  308.         --Check to see how many buffs are active
  309.         local cor_buffs = S(player.buffs) * buffId
  310.         canBust = cor_buffs:contains(res.buffs:with('name', 'Bust').id) or cor_buffs:length() > 1
  311.         if canBust or ranMultiple then
  312.             modified = original
  313.             ranMultiple = false
  314.         else
  315.             windower.add_to_chat(159, 'No \'Bust\'. Fold again to continue.')
  316.             ranMultiple = true
  317.             modified = ""
  318.         end
  319.        
  320.         return modified
  321.     end
  322.    return modified
  323.    
  324. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement