|
new addon "Communication" (not working)
By Shichishito 2018-11-30 13:55:12
when i edited my sch.lua to automate chat messages for immanence skillchains the user Nekseus complained: Code You shouldn't be doing this type of automation with gearswap, instead you should make an independent addon. so i went ahead and spent 20+ days attempting to make a addon. i failed, hard.
i made the rules in their respective job.luas (all based on kinematics which use mote-includes) to the point where i got them to work. then i copied them to the addon file with minor tweaks (mainly added state toggles and key binds/unbinds for those toggles) and i just can't get it to work as addon. if anyone feels capable to get this addon running feel free to edit it.
i added the skillchains properties of SMN bloodpacts, BST sic/ready and BLU physical spells in the spell.xml/spell.lua and abils.xml/job_abilities.lua files by hand and they worked for me without problems. if a experienced dev doesn't see a problem with those edits it would probably be a good idea to replace the existing windower resource/res files with those befor windower pushes another update and potentialy makes changes to those files.
the updated files would allow to call skillchain properties for BLU chain affinity spells, BST sic/ready and SMN bloodpact rages with skillchain_a, skillchain_b and skillchain_c. i added them to the data folder in the download link.
full addon download link:
download link
individual files:
Readme.md Code #Communication
###############################
Addon Description
###############################
this addon is ment to support players setting up skillchains more easily, especially when pet jobs are involved.
it sends messages in party chat to inform team mates about the following:
- weaponskills used
- amount of SCH stratagems left and the recast till the next charge
- amount of BST pet charges left, how much charges the used ready command requires and recast till next charge.
- SMN bloodpact recast
- post the correlating skillchain properties of the used ability/spell/ws.
- will inform the party about selected debuffs the player got hit by.
###############################
Key Binds and Toggle States
###############################
skillchain related ws/abilities and debuffs have seperated keyboard binds, the following binds are default:
! + c auto informs party about weaponskills and recasts/charges for ready/sic/bloodpact/stratagems
@ + c manually posts recasts and charges about current ready/sic/bloodpact/stratagems
! + v auto informs party about current active selected debuffs
@ + v manually posts selected debuffs the player is currently affected by
the auto toggles have different states, debuffs are seperated from ws/recasts/charges:
AutoRecasts:
Off doesn't send any skillchain related party messages at all
Silent sends skillchain related party messages WITHOUT call sounds
Sound sends skillchain related party messages WITH call sounds
AutoDebuffs:
Off doesn't send any debuff related party messages at all
PrimarySilent sends primary debuff related party messages WITHOUT call sounds
PrimarySound sends primary debuff related party messages WITH call sounds
AllSilent sends all debuff related party messages WITHOUT call sounds
AllSound sends all debuff related party messages WITH call sounds Communication.lua Code --[[
Copyright © <2018>, <Shichishito>
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 <addon name> 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 <Shichishito> 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 = 'Communication'
_addon.author = 'Shichishito'
_addon.version = '1.3'
_addon.command = 'comu'
function job_setup()
ready_move_list = S{'Sic','Whirl Claws','Dust Cloud','Foot Kick','Sheep Song','Sheep Charge','Lamb Chop',
'Rage','Head Butt','Scream','Dream Flower','Wild Oats','Leaf Dagger','Claw Cyclone','Razor Fang',
'Roar','Gloeosuccus','Palsy Pollen','Soporific','Cursed Sphere','Venom','Geist Wall','Toxic Spit',
'Numbing Noise','Nimble Snap','Cyclotail','Spoil','Rhino Guard','Rhino Attack','Power Attack',
'Hi-Freq Field','Sandpit','Sandblast','Venom Spray','Mandibular Bite','Metallic Body','Bubble Shower',
'Bubble Curtain','Scissor Guard','Big Scissors','Grapple','Spinning Top','Double Claw','Filamented Hold',
'Frog Kick','Queasyshroom','Silence Gas','Numbshroom','Spore','Dark Spore','Shakeshroom','Blockhead',
'Secretion','Fireball','Tail Blow','Plague Breath','Brain Crush','Infrasonics','1000 Needles',
'Needleshot','Chaotic Eye','Blaster','Scythe Tail','Ripper Fang','Chomp Rush','Intimidate','Recoil Dive',
'Water Wall','Snow Cloud','Wild Carrot','Sudden Lunge','Spiral Spin','Noisome Powder','Wing Slap',
'Beak Lunge','Suction','Drainkiss','Acid Mist','TP Drainkiss','Back Heel','Jettatura','Choke Breath',
'Fantod','Charged Whisker','Purulent Ooze','Corrosive Ooze','Tortoise Stomp','Harden Shell','Aqua Breath',
'Sensilla Blades','Tegmina Buffet','Molting Plumage','Swooping Frenzy','Pentapeck','Sweeping Gouge',
'Zealous Snort'}
jug_pet_names = S{'Homunculus','HareFamiliar','KeenearedSteffi','CrabFamiliar','CourierCarrie',
'SheepFamiliar','LullabyMelodia','SlipperySilas','FlytrapFamiliar','VoraciousAudrey',
'FlowerpotBill','FlowerpotBen','TigerFamiliar','SaberSiravarde','MayflyFamiliar','ShellbusterOrob',
'LizardFamiliar','ColdbloodComo','EftFamiliar','AmbusherAllie','FunguarFamiliar',
'AntlionFamiliar','ChopsueyChucky','BeetleFamiliar','PanzerGalahad','MiteFamiliar','LifedrinkerLars',
'CraftyClyvonne','TurbidToloi','AmigoSabotender','DapperMac','NurseryNazuna','LuckyLulush','FlowerpotMerle',
'DipperYuly','DiscreetLouise','FatsoFargann','PrestoJulio','AudaciousAnna','MailbusterCetas',
'FaithfulFalcorr','SwiftSieghard','BloodclawShasra','BugeyedBroncha','GorefangHobs','GooeyGerard','CrudeRaphie',
'AmiableRoche','HeadbreakerKen','AnklebiterJedd','CursedAnnabelle','BrainyWaluis','GenerousArthur',
'RedolentCandi','AlluringHoney','CaringKiyomaro','VivaciousVickie','SuspiciousAlice','SurgingStorm','SubmergedIyo',
'WarlikePatrick','RhymingShizuna','BlackbeardRandy','ThreestarLynn','HurlerPercival','AcuexFamiliar','FluffyBredo',
'FleetReinhard','SharpwitHermes','AttentiveIbuki','SwoopingZhivago','SunburstMalfik','AgedAngus',
'ScissorlegXerin','BouncingBertha','SpiderFamiliar','GussyHachirobe','ColibriFamiliar','ChoralLeera',
'DroopyDortwin','PonderingPeter','HeraldHenry','MosquitoFamiliar','Left-HandedYoko','BraveHeroGlenn'}
end
function user_setup()
-- Off prevents to send messages
-- Silent sends messages without sounds
-- Sound sends messages with sounds
-- Primary... sends only message for important debuffs
-- All... sends messages for all active debuffs that have table entries
state.AutoRecasts = M{['description']='AutoRecasts', 'Off', 'Silent', 'Sound'}
state.ManualPostRecasts = M(false, 'ManualPostRecasts') -- to post recasts/charges on button push
state.AutoDebuffs = M{['description']='AutoDebuffs', 'Off', 'PrimarySilent', 'PrimarySound', 'AllSilent', 'AllSound'}
state.ManualPostDebuffs = M(false, 'ManualPostDebuffs') -- to post current afflicted debuffs on button push
-- Keyboard binds
-- current bind are alt + c (!c), windows button + c (@c), alt + v (!v), windows button + v (@v)
-- if you want to change the bind remember to also adjust the unbind
send_command('bind !c gs c toggle AutoRecasts')
send_command('bind @c gs c toggle ManualPostRecasts')
send_command('bind !v gs c toggle AutoDebuffs')
send_command('bind @v gs c toggle ManualPostDebuffs')
end
function file_unload()
-- keyboard unbinds after job change.
send_command('unbind !c')
send_command('unbind @c')
send_command('unbind !v')
send_command('unbind @v')
end
-- Call sounds range from 1-21, adjust to your individual taste
if state.AutoRecasts.value == "Sound" then
CallSoundMagicOpen = ' <call10>'
CallSoundMagicClose = ' <call11>'
CallSoundWS = ' <call14>'
CallSoundBP = ' <call19>'
CallSoundSicReady = ' <call18>'
CallSoundNotReadyYet = ' <call15>'
CallSoundBurstAffinity = ' <call12>'
else
CallSoundMagicOpen = ''
CallSoundMagicClose = ''
CallSoundWS = ''
CallSoundBP = ''
CallSoundSicReady = ''
CallSoundNotReadyYet = ''
CallSoundBurstAffinity = ''
end
if state.AutoDebuffs.value == 'PrimarySound' or state.AutoDebuffs.value == 'AllSound' then
CallSoundPrimaryDebuffs = ' <call20>' -- could be a more agressive sound
CallSoundSecondaryDebuffs = ' <call21>'
else
CallSoundPrimaryDebuffs = ''
CallSoundSecondaryDebuffs = ''
end
-- initiating delay variables for party chat spam protection
-- "...chat_delay" value can be changed, 5 seconds is default, shouldn't go lower than 3 seconds
recast_spam_protection = 0
recast_chat_delay = 5
Skillchain_spam_protection = 0
Skillchain_chat_delay = 3
Bloodpact_spam_protection = 0
Bloodpact_chat_delay = 5
SicReady_spam_protection = 0
SicReady_chat_delay = 5
Debuff_spam_protection = 0
Debuff_chat_delay = 3
--if player.main_job == 'SCH' or player.sub_job 'SCH' then
skillchain_window_open = 3
skillchain_window_close = 10
last_immanence_spell_time = 0
last_immanence_spell = ""
last_immanence_spell_element = ""
-- elemental debuffs can't open/close skillchains despite beeing "Elemental Magic"
elemental_debuffs = S{'Burn', 'Rasp', 'Drown', 'Choke', 'Frost', 'Shock'}
SC_opener_spell_elements = S{'Fire', 'Earth', 'Water', 'Wind', 'Ice', 'Lightning', 'Light', 'Dark'}
-- gets the total amount of job points spent
local job_infos_sch = windower.ffxi.get_player()
if job_infos_sch.job_points.sch.jp_spent >= 550 then
job_point_bonus = -15
else
job_point_bonus = 0
end
--end
--if player.main_job == 'BST' or player.sub_job 'BST' then
local main_slot = player.equipment.main
local sub_slot = player.equipment.sub
local leg_slot = player.equipment.legs
-- getting sic/ready recast reductions from gear/job points/merits
equip_recast_reduction = 0
if main_slot == "Charmer's Merlin" or sub_slot == "Charmer's Merlin" then
equip_recast_reduction = equip_recast_reduction + 5
end
if leg_slot == "Desultor Tassets" then -- assuming they have the "Sic" & "Ready" ability delay -5 augment, potential error source
equip_recast_reduction = equip_recast_reduction + 5
end
local job_infos_bst = windower.ffxi.get_player()
jp_recast_reduction = 0
if job_infos_bst.job_points.bst.jp_spent >= 100 then
jp_recast_reduction = 5
else
jp_recast_reduction = 0
end
merit_recast_reduction = job_infos_bst.merits.sic_recast
-- can't call spell.mp_cost from pet_aftercast so we have to get it from the job_precast first
pet_charge_cost = 0
--end
function job_precast(spell, action, spellMap, eventArgs)
-- informs party of remaining Bloodpact/Sic/Ready cooldown
local ability_recast = windower.ffxi.get_ability_recasts()
local BPRageRecast = ability_recast[173]
local ready_recast = ability_recast[102]
-- local sic_recast = ability_recast[255] -- something seems wrong with the recast_id 255 (Sic), 102 seems to be responsible for both ready and Sic
local strata_recast = ability_recast[231]
--if player.main_job == 'BST' or player.sub_job 'BST' then
-- default ready recast per charge is 30 seconds, max charges are 3
-- calculate current ready charges
local max_rdy_charges = 3
local reduced_rdy_recast_per_charge = 30 - equip_recast_reduction - jp_recast_reduction - merit_recast_reduction
local reduced_total_rdy_recast = reduced_rdy_recast_per_charge * max_rdy_charges
local current_rdy_charges = math.floor(max_rdy_charges - max_rdy_charges * ready_recast / reduced_total_rdy_recast)
-- calculate ready recast till next charge
local charging_rdy_charges = max_rdy_charges - current_rdy_charges
local negative_rdy_recast_till_next_charge = charging_rdy_charges * reduced_rdy_recast_per_charge - ready_recast
local rdy_recast_till_next_charge = reduced_rdy_recast_per_charge - negative_rdy_recast_till_next_charge
--end
--if player.main_job == 'SCH' or player.sub_job 'SCH' then
-- setup for SCH stratagems
-- calculates current stratagem charges
-- 240 is the full charge time for stratagems in seconds (excluding the job point bonus)
local max_stratagems = math.floor((player.main_job_level + 10) / 20)
local actual_full_recharge_time = 240 + max_stratagems * job_point_bonus
local current_strata_charges = math.floor(max_stratagems - max_stratagems * strata_recast / actual_full_recharge_time)
-- calculates recast time till next stratagem charge
local strata_recast_per_charge = 240 / max_stratagems + job_point_bonus
local current_stratas_recharging = max_stratagems - current_strata_charges
local negative_recast_till_next_charge = math.floor(current_stratas_recharging * strata_recast_per_charge - strata_recast)
local recast_till_next_charge = strata_recast_per_charge - negative_recast_till_next_charge
--end
-- toggle states for recasts, stratagems and pet charges
if state.AutoRecasts.value == "Silent" or state.AutoRecasts.value == "Sound" or state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
-- SMN Bloodpacts
if player.main_job == 'SMN' or player.sub_job 'SMN' then
if not state.Buff['Astral Conduit'] then
if spell.type == "BloodpactRage" and spell.skillchain_a ~= "" then
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
send_command('input /p '..spell.english..' ready in -'..BPRageRecast..'s.')
recast_spam_protection = os.clock()
end
end
end
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
if BPRageRecast > 0 then
send_command('input /p Blood Pact: Rage ready in -'..BPRageRecast..'s.')
recast_spam_protection = os.clock()
else
send_command('input /p Blood Pact: Rage is ready!')
recast_spam_protection = os.clock()
end
end
end
end
-- SCH Stratagems
if player.main_job == 'SCH' or player.sub_job 'SCH' then
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
if current_strata_charges < max_stratagems then
send_command('input /p Stratagems at '..current_strata_charges..'/'..max_stratagems..' charges, next charge in -'..recast_till_next_charge..'s.')
recast_spam_protection = os.clock()
else
send_command('input /p Stratagems ('..current_strata_charges..'/'..max_stratagems..') all charged and ready!')
recast_spam_protection = os.clock()
end
end
end
end
-- BST Sic/Ready
if player.main_job == 'BST' or player.sub_job 'BST' then
if not state.Buff['Unleash'] then
if spell.type == "Monster" and spell.skillchain_a ~= "" then
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if spell.mp_cost > current_rdy_charges then
send_command('input /p '..spell.english..' ('..spell.mp_cost..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundNotReadyYet..'')
recast_spam_protection = os.clock()
else
pet_charge_cost = spell.mp_cost
end
end
end
end
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
if current_rdy_charges < max_rdy_charges and jug_pet_names:contains(pet.name) then
send_command('input /p Ready at '..current_rdy_charges..'/'..max_rdy_charges..' charges, next charge in -'..rdy_recast_till_next_charge..'s.')
recast_spam_protection = os.clock()
elseif current_rdy_charges == max_rdy_charges and jug_pet_names:contains(pet.name) then
send_command('input /p Ready ('..current_rdy_charges..'/'..max_rdy_charges..') all charged and... ready!')
recast_spam_protection = os.clock()
elseif ready_recast > 0 and not jug_pet_names:contains(pet.name) then
send_command('input /p Sic ready in -'..ready_recast..'s.')
recast_spam_protection = os.clock()
elseif ready_recast == 0 and not jug_pet_names:contains(pet.name) then
send_command('input /p Sic is ready!')
recast_spam_protection = os.clock()
end
end
end
end
end
end
function job_aftercast(spell, action, spellMap, eventArgs)
if spell.interrupted then
return
end
local ability_recast = windower.ffxi.get_ability_recasts()
local ready_recast = ability_recast[102]
-- local sic_recast = ability_recast[255] -- something seems wrong with the recast_id 255 (Sic), 102 seems to be responsible for both ready and Sic
local burst_affinity_recast = ability_recast[182]
if state.AutoRecasts.value == "Silent" or state.AutoRecasts.value == "Sound" then
if spell.type == 'WeaponSkill' then
if (os.clock()-Skillchain_spam_protection > Skillchain_chat_delay) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it!!'..CallSoundWS..'')
Skillchain_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it!!'..CallSoundWS..'')
Skillchain_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it!!'..CallSoundWS..'')
Skillchain_spam_protection = os.clock()
end
end
end
--if player.main_job == 'SCH' or player.sub_job 'SCH' then
-- setup for SCH stratagems
local ability_recast = windower.ffxi.get_ability_recasts()
local strata_recast = ability_recast[231]
-- calculates current stratagem charges
-- 240 is the full charge time for stratagems in seconds (excluding the job point bonus)
local max_stratagems = math.floor((player.main_job_level + 10) / 20)
local actual_full_recharge_time = 240 + max_stratagems * job_point_bonus
local current_strata_charges = math.floor(max_stratagems - max_stratagems * strata_recast / actual_full_recharge_time)
-- calculates recast time till next stratagem charge
local strata_recast_per_charge = 240 / max_stratagems + job_point_bonus
local current_stratas_recharging = max_stratagems - current_strata_charges
local negative_recast_till_next_charge = math.floor(current_stratas_recharging * strata_recast_per_charge - strata_recast)
local recast_till_next_charge = strata_recast_per_charge - negative_recast_till_next_charge
-- SCH Stratagems
if buffactive['Immanence'] and spell.skill == 'Elemental Magic' and SC_opener_spell_elements:contains(spell.element) and not elemental_debuffs:contains(spell.english) then
if (os.clock()-last_immanence_spell_time > skillchain_window_open) and (os.clock()-last_immanence_spell_time < skillchain_window_close) and last_immanence_spell ~= spell.english then
-- LVL 1 skillchains
if spell.element == 'Fire' then
send_command('input /p Skillchain: >>Liquefaction<< / >>Fire<< ('..current_strata_charges..'/'..max_stratagems..') charges, next in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Light' and spell.element == 'Earth' then
send_command('input /p Skillchain: >>Scission<< / >>Earth<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Ice' and spell.element == 'Water' then
send_command('input /p Skillchain: >>Reverberation<< / >>Water<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif spell.element == 'Wind' then
send_command('input /p Skillchain: >>Detonation<< / >>Wind<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif spell.element == 'Ice' then
send_command('input /p Skillchain: >>Induration<< / >>Ice<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Fire' and spell.element == 'Lightning' then
send_command('input /p Skillchain: >>Impaction<< / >>Lightning<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif spell.element == 'Light' then
send_command('input /p Skillchain: >>Transfixion<< / >>Light<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Wind' and spell.element == 'Dark' then
send_command('input /p Skillchain: >>Compression<< / >>Dark<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
-- LVL 2 skillchains
elseif last_immanence_spell_element == 'Ice' and spell.element == 'Water' then
send_command('input /p Skillchain: >>Fragmentation<< / >>Wind/Lightning<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element == 'Fire' and spell.element == 'Lightning' then
send_command('input /p Skillchain: >>Fusion<< / >>Fire/Light<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element == 'Wind' and spell.element == 'Dark' then
send_command('input /p Skillchain: >>Gravitation<< / >>Dark/Earth<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element == 'Light' and spell.element == 'Earth' then
send_command('input /p Skillchain: >>Distortion<< / >>Water/Ice<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
end
else
send_command('input /p >>Opening Skillchain<< get ready!'..CallSoundMagicOpen..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
end
end
--end
-- BST Sic, doesn't need spam protection due to high cooldown
--if player.main_job == 'BST' or player.sub_job 'BST' then
if spell.english == "Sic" then
send_command('input /p >>'..spell.english..'<< just used it, current pet TP '..pet.tp..'.')
end
--end
-- BLU Chain Affinity, doesn't need spam protection due to high cooldown
--if player.main_job == 'BLU' or player.sub_job 'BLU' then
if buffactive['Chain Affinity'] and spell.skill == 'Blue Magic' then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it!! -'..burst_affinity_recast..'s cooldown.'..CallSoundBurstAffinity..'')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it!! -'..burst_affinity_recast..'s cooldown.'..CallSoundBurstAffinity..'')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it!! -'..burst_affinity_recast..'s cooldown.'..CallSoundBurstAffinity..'')
end
end
--end
end
end
-- Runs when pet completes an action
function job_pet_aftercast(spell, action, spellMap, eventArgs)
if spell.interrupted then
return
end
local ability_recast = windower.ffxi.get_ability_recasts()
local ready_recast = ability_recast[102]
-- local sic_recast = ability_recast[255] -- something is wrong with the recast_id 255, 102 seems to be responsible for both Ready and Sic
if state.AutoRecasts.value == "Silent" or state.AutoRecasts.value == "Sound" then
-- default ready recast per charge is 30 seconds, max charges are 3
-- calculate current ready charges
local max_rdy_charges = 3
local reduced_rdy_recast_per_charge = 30 - equip_recast_reduction - jp_recast_reduction - merit_recast_reduction
local reduced_total_rdy_recast = reduced_rdy_recast_per_charge * max_rdy_charges
local current_rdy_charges = math.floor(max_rdy_charges - max_rdy_charges * ready_recast / reduced_total_rdy_recast)
-- calculate ready recast till next charge
local charging_rdy_charges = max_rdy_charges - current_rdy_charges
local negative_rdy_recast_till_next_charge = charging_rdy_charges * reduced_rdy_recast_per_charge - ready_recast
local rdy_recast_till_next_charge = reduced_rdy_recast_per_charge - negative_rdy_recast_till_next_charge
-- handles messages for Bloodpact/Sic/Ready
if spell.type == "BloodpactRage" then
if (os.clock()-Bloodpact_spam_protection > Bloodpact_chat_delay) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it!!'..CallSoundBP..'')
Bloodpact_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it!!'..CallSoundBP..'')
Bloodpact_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it!!'..CallSoundBP..'')
Bloodpact_spam_protection = os.clock()
end
end
end
if ready_move_list:contains(spell.english) then
if jug_pet_names:contains(pet.name) then
if (os.clock()-SicReady_spam_protection > SicReady_chat_delay) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ['..pet_charge_cost..'] ('..spell.skillchain_a..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundSicReady..'')
SicReady_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ['..pet_charge_cost..'] ('..spell.skillchain_a..'/'..spell.skillchain_b..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundSicReady..'')
SicReady_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ['..pet_charge_cost..'] ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundSicReady..'')
SicReady_spam_protection = os.clock()
end
end
end
if not jug_pet_names:contains(pet.name) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it, next Sic in -'..ready_recast..'s!!')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it, next Sic in -'..ready_recast..'s!!')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it, next Sic in -'..ready_recast..'s!!')
else
send_command('input /p >>'..spell.english..'<< just used it, next Sic in -'..ready_recast..'s!!')
end
end
end
end
end
-- Called when a player gains or loses a buff.
-- buff == buff gained or lost
-- gain == true if the buff was gained, false if it was lost.
function job_buff_change(buff, gain)
-- probably unnecessary if you already use motes-include
if state.Buff[buff] ~= nil then
state.Buff[buff] = gain
end
-- buff ids correlate to the following debuffs in order, some debuffs have multiple entries in the buff.lua
-- if you want to add more debuffs to those tables make sure the entries have the exact same order in the _ids and _strs tables, cause they work like a dictionary!!
-- doom, charm, charm, petrification, gradual petrification,sleep, sleep, paralysis, paralysis, slow, slow
local prim_db_ids = {15,14,17,7,18,2,19,4,566,13,565}
local prim_db_strs = {'DOOMED','CHARMED','CHARMED','Petrified','gradually Petrifying','Asleep','Asleep','Paralyzed','Paralyzed','Slowed','Slowed'}
-- silence, addle
local situ_mage_db_ids = {6,21}
local situ_mage_db_strs = {'Silenced','Addled'}
-- blindness
local situ_melee_db_ids = {5}
local situ_melee_db_strs = {'Blinded'}
-- poison, curse, bind, weight, stun, terror
local seco_db_ids = {3,540,9,20,11,12,567,10,28}
local seco_db_strs = {'Poisoned','Poisoned','Cursed','Cursed','Bound','Weighed down','Weighed down','Stunned','Terrorized'}
local mage_job_list = S{'WHM','BLM','RDM','PLD','DRK','BRD','NIN','SMN','BLU',
'SCH','GEO','RUN'}
local melee_job_list = S{'WAR','MNK','THF','DRK','RNG','SAM','NIN','DRG',
'BLU','COR','PUP','DNC','RUN'} -- could arguably add 'BST','PLD','BRD'
-- provides a table with all current active buff/debuff ids
local current_buff_ids_table = (windower.ffxi.get_player().buffs)
local current_primary_debuffs_table = {}
local current_secondary_debuffs_table = {}
if (os.clock()-Debuff_spam_protection > Debuff_chat_delay) then
-- toggle states for debuffs
if state.ManualPostDebuffs.value == true or state.ManualPostDebuffs.value == false or gain and state.AutoDebuffs.value ~= 'Off' then
Debuff_spam_protection = os.clock()
for key_index, value_id in ipairs(current_buff_ids_table) do
-- checking for primary debuffs that need urgent removal
for key_prim_db_ids, value_prim_db_ids in ipairs(prim_db_ids) do
if value_id == value_prim_db_ids then
for key_prim_db_strs, value_prim_db_strs in ipairs(prim_db_strs) do
if key_prim_db_strs == key_prim_db_ids then
table.insert(current_primary_debuffs_table, value_prim_db_strs)
end
end
end
end
-- checking for situational primary mage debuffs that potentialy are urgent to remove from mages
if mage_job_list:contains(player.main_job) or mage_job_list:contains(player.sub_job) then
for key_situ_mage_db_ids, value_situ_mage_db_ids in ipairs(situ_mage_db_ids) do
if value_id == value_situ_mage_db_ids then
for key_situ_mage_db_strs, value_situ_mage_db_strs in ipairs(situ_mage_db_strs) do
if key_situ_mage_db_strs == key_situ_mage_db_ids then
table.insert(current_primary_debuffs_table, value_situ_mage_db_strs)
end
end
end
end
end
-- checking for situational primary melee debuffs that potentialy are urgent to remove from melees
if melee_job_list:contains(player.main_job) then
for key_situ_melee_db_ids, value_situ_melee_db_ids in ipairs(situ_melee_db_ids) do
if value_id == value_situ_melee_db_ids then
for key_situ_melee_db_strs, value_situ_melee_db_strs in ipairs(situ_melee_db_strs) do
if key_situ_melee_db_strs == key_situ_melee_db_ids then
table.insert(current_primary_debuffs_table, value_situ_melee_db_strs)
end
end
end
end
end
-- checking for secondary debuffs that aren't as important to remove
-- only checks if AllSilent/AllSound is toggled or the ManualPostDebuffs button got pushed
if state.AutoDebuffs.value == 'AllSilent' or state.AutoDebuffs.value == 'AllSound' or state.ManualPostDebuffs.value == true or state.ManualPostDebuffs.value == false then
for key_seco_db_ids, value_seco_db_ids in ipairs(seco_db_ids) do
if value_id == value_seco_db_ids then
for key_seco_db_strs, value_seco_db_strs in ipairs(seco_db_strs) do
if key_seco_db_strs == key_seco_db_ids then
table.insert(current_secondary_debuffs_table, value_seco_db_strs)
end
end
end
end
end
end
if current_primary_debuffs_table ~= {} and current_secondary_debuffs_table == {} then
send_command('input /p '..table.concat(current_primary_debuffs_table, ", ")..'!!'..CallSoundPrimaryDebuffs..'')
elseif current_primary_debuffs_table ~= {} and current_secondary_debuffs_table ~= {} then
send_command('input /p '..table.concat(current_primary_debuffs_table, ", ")..','..table.concat(current_secondary_debuffs_table, ", ")..'!!'..CallSoundPrimaryDebuffs..'')
elseif current_primary_debuffs_table == {} and current_secondary_debuffs_table ~= {} then
send_command('input /p '..table.concat(current_secondary_debuffs_table, ", ")..'!!'..CallSoundSecondaryDebuffs..'')
end
end
end
end
i can't add the job_abilities.lua/abils.xml and spells.lua/spells.xml files as code cause they are too long but as already mentioned you can find them in the addon zip file -> data folder.
Bahamut.Ivebian
サーバ: Bahamut
Game: FFXI
Posts: 39
By Bahamut.Ivebian 2018-11-30 15:10:35
ResourceExtractor parses the dats and generates those files automatically. Any fixes would have to be made to that program and not the resources lua/xml's. Not sure what you're trying to accomplish but there is an addon out there that tracks and displays skillchains. The included skills.lua is also automatically generated, with skillchain properties parsed from the weapon skill help text dat.
By Shichishito 2018-11-30 16:04:41
i'm aware they are automatically generated but there are only skillchain property entries for regular weaponskills. no clue why sic/ready/bloodpacts still have no info after so many years but they don't.
someone in the gearswap support thread said i'd have to make the edits myself. i wasn't aware of the ResourceExtractor nor who to contact to make the adjustments and i'm pretty sure if the person gave a damn he would have done them long ago. i wasn't aware there already are addons for all those features. i don't have a github account either.
the updated files are there so who ever has any use for them can do with them what ever they want.
since i reached a point where i can't progress further on my own and i don't want to bother people on the boards for every step i'll leave it at this stage. you can ignore it if you see no use for that addon or the updated files.
[+]
when i edited my sch.lua to automate chat messages for immanence skillchains the user Nekseus complained: Code You shouldn't be doing this type of automation with gearswap, instead you should make an independent addon. so i went ahead and spent 20+ days attempting to make a addon. i failed, hard.
i made the rules in their respective job.luas (all based on kinematics which use mote-includes) to the point where i got them to work. then i copied them to the addon file with minor tweaks (mainly added state toggles and key binds/unbinds for those toggles) and i just can't get it to work as addon. if anyone feels capable to get this addon running feel free to edit it.
i added the skillchains properties of SMN bloodpacts, BST sic/ready and BLU physical spells in the spell.xml/spell.lua and abils.xml/job_abilities.lua files by hand and they worked for me without problems. if a experienced dev doesn't see a problem with those edits it would probably be a good idea to replace the existing windower resource/res files with those befor windower pushes another update and potentialy makes changes to those files.
the updated files would allow to call skillchain properties for BLU chain affinity spells, BST sic/ready and SMN bloodpact rages with skillchain_a, skillchain_b and skillchain_c. i added them to the data folder in the download link.
full addon download link:
download link
individual files:
Readme.md Code #Communication
###############################
Addon Description
###############################
this addon is ment to support players setting up skillchains more easily, especially when pet jobs are involved.
it sends messages in party chat to inform team mates about the following:
- weaponskills used
- amount of SCH stratagems left and the recast till the next charge
- amount of BST pet charges left, how much charges the used ready command requires and recast till next charge.
- SMN bloodpact recast
- post the correlating skillchain properties of the used ability/spell/ws.
- will inform the party about selected debuffs the player got hit by.
###############################
Key Binds and Toggle States
###############################
skillchain related ws/abilities and debuffs have seperated keyboard binds, the following binds are default:
! + c auto informs party about weaponskills and recasts/charges for ready/sic/bloodpact/stratagems
@ + c manually posts recasts and charges about current ready/sic/bloodpact/stratagems
! + v auto informs party about current active selected debuffs
@ + v manually posts selected debuffs the player is currently affected by
the auto toggles have different states, debuffs are seperated from ws/recasts/charges:
AutoRecasts:
Off doesn't send any skillchain related party messages at all
Silent sends skillchain related party messages WITHOUT call sounds
Sound sends skillchain related party messages WITH call sounds
AutoDebuffs:
Off doesn't send any debuff related party messages at all
PrimarySilent sends primary debuff related party messages WITHOUT call sounds
PrimarySound sends primary debuff related party messages WITH call sounds
AllSilent sends all debuff related party messages WITHOUT call sounds
AllSound sends all debuff related party messages WITH call sounds Communication.lua Code --[[
Copyright © <2018>, <Shichishito>
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 <addon name> 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 <Shichishito> 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 = 'Communication'
_addon.author = 'Shichishito'
_addon.version = '1.3'
_addon.command = 'comu'
function job_setup()
ready_move_list = S{'Sic','Whirl Claws','Dust Cloud','Foot Kick','Sheep Song','Sheep Charge','Lamb Chop',
'Rage','Head Butt','Scream','Dream Flower','Wild Oats','Leaf Dagger','Claw Cyclone','Razor Fang',
'Roar','Gloeosuccus','Palsy Pollen','Soporific','Cursed Sphere','Venom','Geist Wall','Toxic Spit',
'Numbing Noise','Nimble Snap','Cyclotail','Spoil','Rhino Guard','Rhino Attack','Power Attack',
'Hi-Freq Field','Sandpit','Sandblast','Venom Spray','Mandibular Bite','Metallic Body','Bubble Shower',
'Bubble Curtain','Scissor Guard','Big Scissors','Grapple','Spinning Top','Double Claw','Filamented Hold',
'Frog Kick','Queasyshroom','Silence Gas','Numbshroom','Spore','Dark Spore','Shakeshroom','Blockhead',
'Secretion','Fireball','Tail Blow','Plague Breath','Brain Crush','Infrasonics','1000 Needles',
'Needleshot','Chaotic Eye','Blaster','Scythe Tail','Ripper Fang','Chomp Rush','Intimidate','Recoil Dive',
'Water Wall','Snow Cloud','Wild Carrot','Sudden Lunge','Spiral Spin','Noisome Powder','Wing Slap',
'Beak Lunge','Suction','Drainkiss','Acid Mist','TP Drainkiss','Back Heel','Jettatura','Choke Breath',
'Fantod','Charged Whisker','Purulent Ooze','Corrosive Ooze','Tortoise Stomp','Harden Shell','Aqua Breath',
'Sensilla Blades','Tegmina Buffet','Molting Plumage','Swooping Frenzy','Pentapeck','Sweeping Gouge',
'Zealous Snort'}
jug_pet_names = S{'Homunculus','HareFamiliar','KeenearedSteffi','CrabFamiliar','CourierCarrie',
'SheepFamiliar','LullabyMelodia','SlipperySilas','FlytrapFamiliar','VoraciousAudrey',
'FlowerpotBill','FlowerpotBen','TigerFamiliar','SaberSiravarde','MayflyFamiliar','ShellbusterOrob',
'LizardFamiliar','ColdbloodComo','EftFamiliar','AmbusherAllie','FunguarFamiliar',
'AntlionFamiliar','ChopsueyChucky','BeetleFamiliar','PanzerGalahad','MiteFamiliar','LifedrinkerLars',
'CraftyClyvonne','TurbidToloi','AmigoSabotender','DapperMac','NurseryNazuna','LuckyLulush','FlowerpotMerle',
'DipperYuly','DiscreetLouise','FatsoFargann','PrestoJulio','AudaciousAnna','MailbusterCetas',
'FaithfulFalcorr','SwiftSieghard','BloodclawShasra','BugeyedBroncha','GorefangHobs','GooeyGerard','CrudeRaphie',
'AmiableRoche','HeadbreakerKen','AnklebiterJedd','CursedAnnabelle','BrainyWaluis','GenerousArthur',
'RedolentCandi','AlluringHoney','CaringKiyomaro','VivaciousVickie','SuspiciousAlice','SurgingStorm','SubmergedIyo',
'WarlikePatrick','RhymingShizuna','BlackbeardRandy','ThreestarLynn','HurlerPercival','AcuexFamiliar','FluffyBredo',
'FleetReinhard','SharpwitHermes','AttentiveIbuki','SwoopingZhivago','SunburstMalfik','AgedAngus',
'ScissorlegXerin','BouncingBertha','SpiderFamiliar','GussyHachirobe','ColibriFamiliar','ChoralLeera',
'DroopyDortwin','PonderingPeter','HeraldHenry','MosquitoFamiliar','Left-HandedYoko','BraveHeroGlenn'}
end
function user_setup()
-- Off prevents to send messages
-- Silent sends messages without sounds
-- Sound sends messages with sounds
-- Primary... sends only message for important debuffs
-- All... sends messages for all active debuffs that have table entries
state.AutoRecasts = M{['description']='AutoRecasts', 'Off', 'Silent', 'Sound'}
state.ManualPostRecasts = M(false, 'ManualPostRecasts') -- to post recasts/charges on button push
state.AutoDebuffs = M{['description']='AutoDebuffs', 'Off', 'PrimarySilent', 'PrimarySound', 'AllSilent', 'AllSound'}
state.ManualPostDebuffs = M(false, 'ManualPostDebuffs') -- to post current afflicted debuffs on button push
-- Keyboard binds
-- current bind are alt + c (!c), windows button + c (@c), alt + v (!v), windows button + v (@v)
-- if you want to change the bind remember to also adjust the unbind
send_command('bind !c gs c toggle AutoRecasts')
send_command('bind @c gs c toggle ManualPostRecasts')
send_command('bind !v gs c toggle AutoDebuffs')
send_command('bind @v gs c toggle ManualPostDebuffs')
end
function file_unload()
-- keyboard unbinds after job change.
send_command('unbind !c')
send_command('unbind @c')
send_command('unbind !v')
send_command('unbind @v')
end
-- Call sounds range from 1-21, adjust to your individual taste
if state.AutoRecasts.value == "Sound" then
CallSoundMagicOpen = ' <call10>'
CallSoundMagicClose = ' <call11>'
CallSoundWS = ' <call14>'
CallSoundBP = ' <call19>'
CallSoundSicReady = ' <call18>'
CallSoundNotReadyYet = ' <call15>'
CallSoundBurstAffinity = ' <call12>'
else
CallSoundMagicOpen = ''
CallSoundMagicClose = ''
CallSoundWS = ''
CallSoundBP = ''
CallSoundSicReady = ''
CallSoundNotReadyYet = ''
CallSoundBurstAffinity = ''
end
if state.AutoDebuffs.value == 'PrimarySound' or state.AutoDebuffs.value == 'AllSound' then
CallSoundPrimaryDebuffs = ' <call20>' -- could be a more agressive sound
CallSoundSecondaryDebuffs = ' <call21>'
else
CallSoundPrimaryDebuffs = ''
CallSoundSecondaryDebuffs = ''
end
-- initiating delay variables for party chat spam protection
-- "...chat_delay" value can be changed, 5 seconds is default, shouldn't go lower than 3 seconds
recast_spam_protection = 0
recast_chat_delay = 5
Skillchain_spam_protection = 0
Skillchain_chat_delay = 3
Bloodpact_spam_protection = 0
Bloodpact_chat_delay = 5
SicReady_spam_protection = 0
SicReady_chat_delay = 5
Debuff_spam_protection = 0
Debuff_chat_delay = 3
--if player.main_job == 'SCH' or player.sub_job 'SCH' then
skillchain_window_open = 3
skillchain_window_close = 10
last_immanence_spell_time = 0
last_immanence_spell = ""
last_immanence_spell_element = ""
-- elemental debuffs can't open/close skillchains despite beeing "Elemental Magic"
elemental_debuffs = S{'Burn', 'Rasp', 'Drown', 'Choke', 'Frost', 'Shock'}
SC_opener_spell_elements = S{'Fire', 'Earth', 'Water', 'Wind', 'Ice', 'Lightning', 'Light', 'Dark'}
-- gets the total amount of job points spent
local job_infos_sch = windower.ffxi.get_player()
if job_infos_sch.job_points.sch.jp_spent >= 550 then
job_point_bonus = -15
else
job_point_bonus = 0
end
--end
--if player.main_job == 'BST' or player.sub_job 'BST' then
local main_slot = player.equipment.main
local sub_slot = player.equipment.sub
local leg_slot = player.equipment.legs
-- getting sic/ready recast reductions from gear/job points/merits
equip_recast_reduction = 0
if main_slot == "Charmer's Merlin" or sub_slot == "Charmer's Merlin" then
equip_recast_reduction = equip_recast_reduction + 5
end
if leg_slot == "Desultor Tassets" then -- assuming they have the "Sic" & "Ready" ability delay -5 augment, potential error source
equip_recast_reduction = equip_recast_reduction + 5
end
local job_infos_bst = windower.ffxi.get_player()
jp_recast_reduction = 0
if job_infos_bst.job_points.bst.jp_spent >= 100 then
jp_recast_reduction = 5
else
jp_recast_reduction = 0
end
merit_recast_reduction = job_infos_bst.merits.sic_recast
-- can't call spell.mp_cost from pet_aftercast so we have to get it from the job_precast first
pet_charge_cost = 0
--end
function job_precast(spell, action, spellMap, eventArgs)
-- informs party of remaining Bloodpact/Sic/Ready cooldown
local ability_recast = windower.ffxi.get_ability_recasts()
local BPRageRecast = ability_recast[173]
local ready_recast = ability_recast[102]
-- local sic_recast = ability_recast[255] -- something seems wrong with the recast_id 255 (Sic), 102 seems to be responsible for both ready and Sic
local strata_recast = ability_recast[231]
--if player.main_job == 'BST' or player.sub_job 'BST' then
-- default ready recast per charge is 30 seconds, max charges are 3
-- calculate current ready charges
local max_rdy_charges = 3
local reduced_rdy_recast_per_charge = 30 - equip_recast_reduction - jp_recast_reduction - merit_recast_reduction
local reduced_total_rdy_recast = reduced_rdy_recast_per_charge * max_rdy_charges
local current_rdy_charges = math.floor(max_rdy_charges - max_rdy_charges * ready_recast / reduced_total_rdy_recast)
-- calculate ready recast till next charge
local charging_rdy_charges = max_rdy_charges - current_rdy_charges
local negative_rdy_recast_till_next_charge = charging_rdy_charges * reduced_rdy_recast_per_charge - ready_recast
local rdy_recast_till_next_charge = reduced_rdy_recast_per_charge - negative_rdy_recast_till_next_charge
--end
--if player.main_job == 'SCH' or player.sub_job 'SCH' then
-- setup for SCH stratagems
-- calculates current stratagem charges
-- 240 is the full charge time for stratagems in seconds (excluding the job point bonus)
local max_stratagems = math.floor((player.main_job_level + 10) / 20)
local actual_full_recharge_time = 240 + max_stratagems * job_point_bonus
local current_strata_charges = math.floor(max_stratagems - max_stratagems * strata_recast / actual_full_recharge_time)
-- calculates recast time till next stratagem charge
local strata_recast_per_charge = 240 / max_stratagems + job_point_bonus
local current_stratas_recharging = max_stratagems - current_strata_charges
local negative_recast_till_next_charge = math.floor(current_stratas_recharging * strata_recast_per_charge - strata_recast)
local recast_till_next_charge = strata_recast_per_charge - negative_recast_till_next_charge
--end
-- toggle states for recasts, stratagems and pet charges
if state.AutoRecasts.value == "Silent" or state.AutoRecasts.value == "Sound" or state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
-- SMN Bloodpacts
if player.main_job == 'SMN' or player.sub_job 'SMN' then
if not state.Buff['Astral Conduit'] then
if spell.type == "BloodpactRage" and spell.skillchain_a ~= "" then
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
send_command('input /p '..spell.english..' ready in -'..BPRageRecast..'s.')
recast_spam_protection = os.clock()
end
end
end
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
if BPRageRecast > 0 then
send_command('input /p Blood Pact: Rage ready in -'..BPRageRecast..'s.')
recast_spam_protection = os.clock()
else
send_command('input /p Blood Pact: Rage is ready!')
recast_spam_protection = os.clock()
end
end
end
end
-- SCH Stratagems
if player.main_job == 'SCH' or player.sub_job 'SCH' then
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
if current_strata_charges < max_stratagems then
send_command('input /p Stratagems at '..current_strata_charges..'/'..max_stratagems..' charges, next charge in -'..recast_till_next_charge..'s.')
recast_spam_protection = os.clock()
else
send_command('input /p Stratagems ('..current_strata_charges..'/'..max_stratagems..') all charged and ready!')
recast_spam_protection = os.clock()
end
end
end
end
-- BST Sic/Ready
if player.main_job == 'BST' or player.sub_job 'BST' then
if not state.Buff['Unleash'] then
if spell.type == "Monster" and spell.skillchain_a ~= "" then
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if spell.mp_cost > current_rdy_charges then
send_command('input /p '..spell.english..' ('..spell.mp_cost..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundNotReadyYet..'')
recast_spam_protection = os.clock()
else
pet_charge_cost = spell.mp_cost
end
end
end
end
if ability_recast[spell.recast_id] > 1 and (os.clock()-recast_spam_protection > recast_chat_delay) then
if state.ManualPostRecasts.value == true or state.ManualPostRecasts.value == false then
if current_rdy_charges < max_rdy_charges and jug_pet_names:contains(pet.name) then
send_command('input /p Ready at '..current_rdy_charges..'/'..max_rdy_charges..' charges, next charge in -'..rdy_recast_till_next_charge..'s.')
recast_spam_protection = os.clock()
elseif current_rdy_charges == max_rdy_charges and jug_pet_names:contains(pet.name) then
send_command('input /p Ready ('..current_rdy_charges..'/'..max_rdy_charges..') all charged and... ready!')
recast_spam_protection = os.clock()
elseif ready_recast > 0 and not jug_pet_names:contains(pet.name) then
send_command('input /p Sic ready in -'..ready_recast..'s.')
recast_spam_protection = os.clock()
elseif ready_recast == 0 and not jug_pet_names:contains(pet.name) then
send_command('input /p Sic is ready!')
recast_spam_protection = os.clock()
end
end
end
end
end
end
function job_aftercast(spell, action, spellMap, eventArgs)
if spell.interrupted then
return
end
local ability_recast = windower.ffxi.get_ability_recasts()
local ready_recast = ability_recast[102]
-- local sic_recast = ability_recast[255] -- something seems wrong with the recast_id 255 (Sic), 102 seems to be responsible for both ready and Sic
local burst_affinity_recast = ability_recast[182]
if state.AutoRecasts.value == "Silent" or state.AutoRecasts.value == "Sound" then
if spell.type == 'WeaponSkill' then
if (os.clock()-Skillchain_spam_protection > Skillchain_chat_delay) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it!!'..CallSoundWS..'')
Skillchain_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it!!'..CallSoundWS..'')
Skillchain_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it!!'..CallSoundWS..'')
Skillchain_spam_protection = os.clock()
end
end
end
--if player.main_job == 'SCH' or player.sub_job 'SCH' then
-- setup for SCH stratagems
local ability_recast = windower.ffxi.get_ability_recasts()
local strata_recast = ability_recast[231]
-- calculates current stratagem charges
-- 240 is the full charge time for stratagems in seconds (excluding the job point bonus)
local max_stratagems = math.floor((player.main_job_level + 10) / 20)
local actual_full_recharge_time = 240 + max_stratagems * job_point_bonus
local current_strata_charges = math.floor(max_stratagems - max_stratagems * strata_recast / actual_full_recharge_time)
-- calculates recast time till next stratagem charge
local strata_recast_per_charge = 240 / max_stratagems + job_point_bonus
local current_stratas_recharging = max_stratagems - current_strata_charges
local negative_recast_till_next_charge = math.floor(current_stratas_recharging * strata_recast_per_charge - strata_recast)
local recast_till_next_charge = strata_recast_per_charge - negative_recast_till_next_charge
-- SCH Stratagems
if buffactive['Immanence'] and spell.skill == 'Elemental Magic' and SC_opener_spell_elements:contains(spell.element) and not elemental_debuffs:contains(spell.english) then
if (os.clock()-last_immanence_spell_time > skillchain_window_open) and (os.clock()-last_immanence_spell_time < skillchain_window_close) and last_immanence_spell ~= spell.english then
-- LVL 1 skillchains
if spell.element == 'Fire' then
send_command('input /p Skillchain: >>Liquefaction<< / >>Fire<< ('..current_strata_charges..'/'..max_stratagems..') charges, next in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Light' and spell.element == 'Earth' then
send_command('input /p Skillchain: >>Scission<< / >>Earth<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Ice' and spell.element == 'Water' then
send_command('input /p Skillchain: >>Reverberation<< / >>Water<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif spell.element == 'Wind' then
send_command('input /p Skillchain: >>Detonation<< / >>Wind<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif spell.element == 'Ice' then
send_command('input /p Skillchain: >>Induration<< / >>Ice<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Fire' and spell.element == 'Lightning' then
send_command('input /p Skillchain: >>Impaction<< / >>Lightning<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif spell.element == 'Light' then
send_command('input /p Skillchain: >>Transfixion<< / >>Light<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element ~= 'Wind' and spell.element == 'Dark' then
send_command('input /p Skillchain: >>Compression<< / >>Dark<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
-- LVL 2 skillchains
elseif last_immanence_spell_element == 'Ice' and spell.element == 'Water' then
send_command('input /p Skillchain: >>Fragmentation<< / >>Wind/Lightning<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element == 'Fire' and spell.element == 'Lightning' then
send_command('input /p Skillchain: >>Fusion<< / >>Fire/Light<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element == 'Wind' and spell.element == 'Dark' then
send_command('input /p Skillchain: >>Gravitation<< / >>Dark/Earth<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
elseif last_immanence_spell_element == 'Light' and spell.element == 'Earth' then
send_command('input /p Skillchain: >>Distortion<< / >>Water/Ice<< ('..current_strata_charges..'/'..max_stratagems..') charges, next charge in -'..recast_till_next_charge..'s!!'..CallSoundMagicClose..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
end
else
send_command('input /p >>Opening Skillchain<< get ready!'..CallSoundMagicOpen..'')
last_immanence_spell_element = spell.element
last_immanence_spell = spell.english
last_immanence_spell_time = os.clock()
end
end
--end
-- BST Sic, doesn't need spam protection due to high cooldown
--if player.main_job == 'BST' or player.sub_job 'BST' then
if spell.english == "Sic" then
send_command('input /p >>'..spell.english..'<< just used it, current pet TP '..pet.tp..'.')
end
--end
-- BLU Chain Affinity, doesn't need spam protection due to high cooldown
--if player.main_job == 'BLU' or player.sub_job 'BLU' then
if buffactive['Chain Affinity'] and spell.skill == 'Blue Magic' then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it!! -'..burst_affinity_recast..'s cooldown.'..CallSoundBurstAffinity..'')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it!! -'..burst_affinity_recast..'s cooldown.'..CallSoundBurstAffinity..'')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it!! -'..burst_affinity_recast..'s cooldown.'..CallSoundBurstAffinity..'')
end
end
--end
end
end
-- Runs when pet completes an action
function job_pet_aftercast(spell, action, spellMap, eventArgs)
if spell.interrupted then
return
end
local ability_recast = windower.ffxi.get_ability_recasts()
local ready_recast = ability_recast[102]
-- local sic_recast = ability_recast[255] -- something is wrong with the recast_id 255, 102 seems to be responsible for both Ready and Sic
if state.AutoRecasts.value == "Silent" or state.AutoRecasts.value == "Sound" then
-- default ready recast per charge is 30 seconds, max charges are 3
-- calculate current ready charges
local max_rdy_charges = 3
local reduced_rdy_recast_per_charge = 30 - equip_recast_reduction - jp_recast_reduction - merit_recast_reduction
local reduced_total_rdy_recast = reduced_rdy_recast_per_charge * max_rdy_charges
local current_rdy_charges = math.floor(max_rdy_charges - max_rdy_charges * ready_recast / reduced_total_rdy_recast)
-- calculate ready recast till next charge
local charging_rdy_charges = max_rdy_charges - current_rdy_charges
local negative_rdy_recast_till_next_charge = charging_rdy_charges * reduced_rdy_recast_per_charge - ready_recast
local rdy_recast_till_next_charge = reduced_rdy_recast_per_charge - negative_rdy_recast_till_next_charge
-- handles messages for Bloodpact/Sic/Ready
if spell.type == "BloodpactRage" then
if (os.clock()-Bloodpact_spam_protection > Bloodpact_chat_delay) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it!!'..CallSoundBP..'')
Bloodpact_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it!!'..CallSoundBP..'')
Bloodpact_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it!!'..CallSoundBP..'')
Bloodpact_spam_protection = os.clock()
end
end
end
if ready_move_list:contains(spell.english) then
if jug_pet_names:contains(pet.name) then
if (os.clock()-SicReady_spam_protection > SicReady_chat_delay) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ['..pet_charge_cost..'] ('..spell.skillchain_a..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundSicReady..'')
SicReady_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ['..pet_charge_cost..'] ('..spell.skillchain_a..'/'..spell.skillchain_b..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundSicReady..'')
SicReady_spam_protection = os.clock()
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ['..pet_charge_cost..'] ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') | '..current_rdy_charges..'/'..max_rdy_charges..' charges left, next charge in -'..rdy_recast_till_next_charge..'s.'..CallSoundSicReady..'')
SicReady_spam_protection = os.clock()
end
end
end
if not jug_pet_names:contains(pet.name) then
if spell.skillchain_a ~= "" and spell.skillchain_b == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..') just used it, next Sic in -'..ready_recast..'s!!')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c == "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..') just used it, next Sic in -'..ready_recast..'s!!')
elseif spell.skillchain_a ~= "" and spell.skillchain_b ~= "" and spell.skillchain_c ~= "" then
send_command('input /p >>'..spell.english..'<< ('..spell.skillchain_a..'/'..spell.skillchain_b..'/'..spell.skillchain_c..') just used it, next Sic in -'..ready_recast..'s!!')
else
send_command('input /p >>'..spell.english..'<< just used it, next Sic in -'..ready_recast..'s!!')
end
end
end
end
end
-- Called when a player gains or loses a buff.
-- buff == buff gained or lost
-- gain == true if the buff was gained, false if it was lost.
function job_buff_change(buff, gain)
-- probably unnecessary if you already use motes-include
if state.Buff[buff] ~= nil then
state.Buff[buff] = gain
end
-- buff ids correlate to the following debuffs in order, some debuffs have multiple entries in the buff.lua
-- if you want to add more debuffs to those tables make sure the entries have the exact same order in the _ids and _strs tables, cause they work like a dictionary!!
-- doom, charm, charm, petrification, gradual petrification,sleep, sleep, paralysis, paralysis, slow, slow
local prim_db_ids = {15,14,17,7,18,2,19,4,566,13,565}
local prim_db_strs = {'DOOMED','CHARMED','CHARMED','Petrified','gradually Petrifying','Asleep','Asleep','Paralyzed','Paralyzed','Slowed','Slowed'}
-- silence, addle
local situ_mage_db_ids = {6,21}
local situ_mage_db_strs = {'Silenced','Addled'}
-- blindness
local situ_melee_db_ids = {5}
local situ_melee_db_strs = {'Blinded'}
-- poison, curse, bind, weight, stun, terror
local seco_db_ids = {3,540,9,20,11,12,567,10,28}
local seco_db_strs = {'Poisoned','Poisoned','Cursed','Cursed','Bound','Weighed down','Weighed down','Stunned','Terrorized'}
local mage_job_list = S{'WHM','BLM','RDM','PLD','DRK','BRD','NIN','SMN','BLU',
'SCH','GEO','RUN'}
local melee_job_list = S{'WAR','MNK','THF','DRK','RNG','SAM','NIN','DRG',
'BLU','COR','PUP','DNC','RUN'} -- could arguably add 'BST','PLD','BRD'
-- provides a table with all current active buff/debuff ids
local current_buff_ids_table = (windower.ffxi.get_player().buffs)
local current_primary_debuffs_table = {}
local current_secondary_debuffs_table = {}
if (os.clock()-Debuff_spam_protection > Debuff_chat_delay) then
-- toggle states for debuffs
if state.ManualPostDebuffs.value == true or state.ManualPostDebuffs.value == false or gain and state.AutoDebuffs.value ~= 'Off' then
Debuff_spam_protection = os.clock()
for key_index, value_id in ipairs(current_buff_ids_table) do
-- checking for primary debuffs that need urgent removal
for key_prim_db_ids, value_prim_db_ids in ipairs(prim_db_ids) do
if value_id == value_prim_db_ids then
for key_prim_db_strs, value_prim_db_strs in ipairs(prim_db_strs) do
if key_prim_db_strs == key_prim_db_ids then
table.insert(current_primary_debuffs_table, value_prim_db_strs)
end
end
end
end
-- checking for situational primary mage debuffs that potentialy are urgent to remove from mages
if mage_job_list:contains(player.main_job) or mage_job_list:contains(player.sub_job) then
for key_situ_mage_db_ids, value_situ_mage_db_ids in ipairs(situ_mage_db_ids) do
if value_id == value_situ_mage_db_ids then
for key_situ_mage_db_strs, value_situ_mage_db_strs in ipairs(situ_mage_db_strs) do
if key_situ_mage_db_strs == key_situ_mage_db_ids then
table.insert(current_primary_debuffs_table, value_situ_mage_db_strs)
end
end
end
end
end
-- checking for situational primary melee debuffs that potentialy are urgent to remove from melees
if melee_job_list:contains(player.main_job) then
for key_situ_melee_db_ids, value_situ_melee_db_ids in ipairs(situ_melee_db_ids) do
if value_id == value_situ_melee_db_ids then
for key_situ_melee_db_strs, value_situ_melee_db_strs in ipairs(situ_melee_db_strs) do
if key_situ_melee_db_strs == key_situ_melee_db_ids then
table.insert(current_primary_debuffs_table, value_situ_melee_db_strs)
end
end
end
end
end
-- checking for secondary debuffs that aren't as important to remove
-- only checks if AllSilent/AllSound is toggled or the ManualPostDebuffs button got pushed
if state.AutoDebuffs.value == 'AllSilent' or state.AutoDebuffs.value == 'AllSound' or state.ManualPostDebuffs.value == true or state.ManualPostDebuffs.value == false then
for key_seco_db_ids, value_seco_db_ids in ipairs(seco_db_ids) do
if value_id == value_seco_db_ids then
for key_seco_db_strs, value_seco_db_strs in ipairs(seco_db_strs) do
if key_seco_db_strs == key_seco_db_ids then
table.insert(current_secondary_debuffs_table, value_seco_db_strs)
end
end
end
end
end
end
if current_primary_debuffs_table ~= {} and current_secondary_debuffs_table == {} then
send_command('input /p '..table.concat(current_primary_debuffs_table, ", ")..'!!'..CallSoundPrimaryDebuffs..'')
elseif current_primary_debuffs_table ~= {} and current_secondary_debuffs_table ~= {} then
send_command('input /p '..table.concat(current_primary_debuffs_table, ", ")..','..table.concat(current_secondary_debuffs_table, ", ")..'!!'..CallSoundPrimaryDebuffs..'')
elseif current_primary_debuffs_table == {} and current_secondary_debuffs_table ~= {} then
send_command('input /p '..table.concat(current_secondary_debuffs_table, ", ")..'!!'..CallSoundSecondaryDebuffs..'')
end
end
end
end
i can't add the job_abilities.lua/abils.xml and spells.lua/spells.xml files as code cause they are too long but as already mentioned you can find them in the addon zip file -> data folder.
|
|