summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-11-15 13:53:59 +0800
committerchai <chaifix@163.com>2021-11-15 13:53:59 +0800
commit942a030afd348ab2e02eac8054b43e3c3a72ea48 (patch)
treea13459f39a3d2f1b533fbd1b5ab523d7a621f673 /Data/BuiltIn/Libraries/lua-addons/addons/rolltracker/rolltracker.lua
parente307051a56a54c27f10438fd2025edf61d0dfeed (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.lua370
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)