diff options
author | chai <chaifix@163.com> | 2021-11-15 13:53:59 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-11-15 13:53:59 +0800 |
commit | 942a030afd348ab2e02eac8054b43e3c3a72ea48 (patch) | |
tree | a13459f39a3d2f1b533fbd1b5ab523d7a621f673 /Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua | |
parent | e307051a56a54c27f10438fd2025edf61d0dfeed (diff) |
*rename
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua b/Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua new file mode 100644 index 0000000..b688d09 --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua @@ -0,0 +1,370 @@ +--Copyright (c) 2013-2014, Thomas Rogers +--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 RollTracker 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 THOMAS ROGERS 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 = 'RollTracker' +_addon.version = '1.8.0.0' +_addon.author = 'Balloon' +_addon.commands = {'rolltracker','rt'} + +require('luau') +chat = require('chat') +chars = require('chat.chars') +packets = require('packets') + +defaults = {} +defaults.autostopper = true +defaults.bust = 1 +defaults.effected = 1 +defaults.fold = 1 +defaults.luckyinfo = true + +settings = config.load(defaults) + +windower.register_event('addon command',function (...) + cmd = {...} + if cmd[1] ~= nil then + if cmd[1]:lower() == "help" then + 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 + 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('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) + +function getGear(slot) + local equip = windower.ffxi.get_items()['equipment'] + return windower.ffxi.get_items(equip[slot..'_bag'])[equip[slot]]~= nil and windower.ffxi.get_items(equip[slot..'_bag'])[equip[slot]].id or 0 +end + +windower.register_event('load', function() + + --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'), + [4]=getGear('head'),[9]=getGear('neck'),[11]=getGear('left_ear'),[12]=getGear('right_ear'), + [5]=getGear('body'),[6]=getGear('hands'),[13]=getGear('left_ring'),[14]=getGear('right_ring'), + [15]=getGear('back'),[10]=getGear('waist'),[7]=getGear('legs'),[8]=getGear('feet') + } + buffId = S{309} + S(res.buffs:english(string.endswith-{' Roll'})):map(table.get-{'id'}) + partyColour = { + p0 = string.char(0x1E, 247), + p1 = string.char(0x1F, 204), + p2 = string.char(0x1E, 156), + p3 = string.char(0x1E, 238), + p4 = string.char(0x1E, 5), + p5 = string.char(0x1E, 6) + } + local rollInfoTemp = { + -- 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) +end) + +windower.register_event('load', 'login', function() + isLucky = false + rollPlusBonus = false + lastRoll = 0 + player = windower.ffxi.get_player() +end) + +windower.register_event('incoming text', function(old, new, color) + --Hides Battlemod + 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 + return true + end + + --Hides Vanilla + if old:match('.* receives the effect of .* Roll.') ~= nil then + return true + end + + return new, color +end) + +windower.register_event('action', function(act) + if act.category == 6 and table.containskey(rollInfo, act.param) then + --This is used later to allow/disallow busting + --If you are not the rollActor you will not be disallowed to bust. + rollActor = act.actor_id + 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 + function(act) + for i = 1, #act.targets do + if act.targets[i].id == player.id then + return true + end + end + return false + end(act) + then + local party = windower.ffxi.get_party() + rollMembers = {} + 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 + rollMembers[effectedTarget] = partyColour[partyMem] .. party[partyMem].name .. chat.controls.reset + end + end + end + + 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 rollBonus = RollEffect(rollID, rollNum+1) + local luckChat = '' + isLucky = false + 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, rollActor)..ReportRollInfo(rollID, rollActor)) + end + end + end +end) + + +function RollEffect(rollid, rollnum) + if rollnum == 13 then + 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 + lastRoll = rollid + rollPlusBonus = false + gearBonus = false + jobBonus = false + end + + --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 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" + end + + --If there's no Roll Val can't add to it + if rollVal ~= '?' then + 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 + + --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 + + --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(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 +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 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 (cleaned:match('/jobability \"?Fold') or cleaned:match('/ja \"?Fold')) then + local count = 0 + local canBust = false + + --Check to see how many buffs are active + 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 = 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) |