Infight Shortbuff recast based on XTarget
My usecase: I want my mage(s) to cast and recast their shortbuff-ds at the tank, as soon as atleast one mob is on aggro (and therefor on their extended target list), despite not beeing in same group( or raid)
Again I found serveral nice ideas, reading the Luas available here.
What I noted: lot of code seems posted here, in a way, that I thought these would be working code.
Snipping parts of them to reuse it, while testing them, I noted that there where sometimes even far from beein a working syntax.
I would like to be able to disctinct "concept code" from "working code".
Code I post may have bug(s), but usually should be tested by myself in different variant uses. (Hopefully in all).
Instructions:
local XTarNr = 11 -- set the number of the slot of Xtarget, where your shortbuff shall land. Usually that will be the tank. Default: tank is on XTarget No. 11
local dsSpells = {
MAG={name='Scorching Skin',type='spell'},
DRU={name='Daggerthorn',type='aa'},
}
Define Class-Ability which Buff/AA shall be cast; NOTE: Daggerthorn is not the DRU best Ds, nor an aa ... this line is there just to show the possible format of an entry for an aa.
For each class, there shall be only one entry. You may add more Classes with an entry, if you find other classes useful infight-shortbuffs
The buffs/aas will be cast on its cooldown, no validation if buff is still on the target or not
As soon as the mob is down and no more mobs are on aggro, the spamming of the ds (or any other shortbuff) will hold
Import Block
Code:
cmV0dXJuIHsKIGxvYWQgPSB7CiAgYWx3YXlzID0gZmFsc2UsCiAgY2xhc3MgPSAiIiwKICB6b25lID0gIiIsCiB9LAogY29kZSA9ICJMUzB0UUhSNWNHVWdUWEVLTFMwdFFIUjVjR1VnU1cxSGRXa0tDbXh2WTJGc0lHMXhJRDBnY21WeGRXbHlaU2duYlhFbktRcHNiMk5oYkNCVGNHVnNiRzVoYldVOUp5Y0tDaTB0SUdsbUlGaFVZWEpPY2lBOVBTQXdJSFJvWlc0Z2JtOGdkR0Z5WjJWMGFXNW5JSE5vWVd4c0lHSmxJRzVsWldSbFpBb3RMU0JwYlhCdmNuUmhiblFnZEc4Z2JXRnJaU0IwYUdseklIZHZjbXM2SUdsdWMyVnlkQ0IwYUdVZ2MyeHZkQ0JwYmlCWVZHRnlaMlYwVjJsdVpHOTNJSGRvWlhKbElIUm9aU0JVWVc1cklISmxjMmxrWlhNZ2QyaHZJSE5vWld4c0lHZGxkQ0IwYUdVZ1pITW5aWE1LYkc5allXd2dXRlJoY2s1eUlEMGdNVEVnSUMwdElFRlVWRTQ2SUhObGRDQjViM1Z5SUZSaGJtc2dkRzhnWVNCemNHVmphV1pwWXlCWWRHVnVaR1ZrSUZSaGNtZGxkQ0JUYkc5MElHRnVaQ0JwYm5ObGNuUWdiblZ0WW1WeUlHaGxjbVVLQ214dlkyRnNJR1J6VTNCbGJHeHpJRDBnZXdvZ0lDQWdUVUZIUFh0dVlXMWxQU2RUWTI5eVkyaHBibWNnVTJ0cGJpY3NkSGx3WlQwbmMzQmxiR3duZlN3S0lDQWdJRVJTVlQxN2JtRnRaVDBuUkdGbloyVnlkR2h2Y200bkxIUjVjR1U5SjNOd1pXeHNKMzBzQ24wS0NteHZZMkZzSUdaMWJtTjBhVzl1SUZOMGIzQkVVRk1vS1FvZ0lDQWdiWEV1WTIxa0tDY3ZjM0YxWld4amFDQXZiWEZ3SUc5dUp5a0tJQ0FnSUcxeExtUmxiR0Y1S0RFd0tRb2dJQ0FnYVdZZ2JYRXVWRXhQTGsxbExrTnNZWE56TGxOb2IzSjBUbUZ0WlNncElEMDlJQ2RDVWtRbklIUm9aVzRLSUNBZ0lDQWdJQ0J0Y1M1amJXUW9KeTl6Y1hWbGJHTm9JQzkwZDJsemRDQnZabVluS1FvZ0lDQWdJQ0FnSUcxeExtUmxiR0Y1S0RFd0tRb2dJQ0FnSUNBZ0lHMXhMbU50WkNnbkwzTnhkV1ZzWTJnZ0wzTjBiM0J6YjI1bkp5a0tJQ0FnSUNBZ0lDQnRjUzVrWld4aGVTZ3hNQ2tLSUNBZ0lHVnVaQW9nSUNBZ0xTMXRjUzVqYldRb0p5OWhkSFJoWTJzZ2IyWm1KeWtLSUNBZ0lDMHRiWEV1WkdWc1lYa29NVEFwQ2lBZ0lDQnRjUzVqYldRb0p5OXpjWFZsYkdOb0lDOWliM2h5SUhCaGRYTmxKeWtLSUNBZ0lHMXhMbVJsYkdGNUtERXdLUW9nSUNBZ2QyaHBiR1VnYlhFdVZFeFBMazFsTGtOaGMzUnBibWN1U1VRb0tTQmtid29nSUNBZ0lDQWdiWEV1WkdWc1lYa29NVEF3S1FvZ0lDQWdaVzVrQ21WdVpBb0tiRzlqWVd3Z1puVnVZM1JwYjI0Z1VtVnpkVzFsUkZCVEtDa0tJQ0FnYlhFdVkyMWtLQ2N2YzNGMVpXeGphQ0F2YlhGd0lHOW1aaWNwQ2lBZ0lHMXhMbVJsYkdGNUtERXdLUW9nSUNCcFppQnRjUzVVVEU4dVRXVXVRMnhoYzNNdVUyaHZjblJPWVcxbEtDa2dQVDBnSjBKU1JDY2dkR2hsYmdvZ0lDQWdiWEV1WTIxa0tDY3ZjM0YxWld4amFDQXZkSGRwYzNRZ2IyNG5LUW9nSUNBZ2JYRXVaR1ZzWVhrb01UQXBDaUFnSUdWdVpBb2dJQ0J0Y1M1amJXUW9KeTl6Y1hWbGJHTm9JQzlpYjNoeUlIVnVjR0YxYzJVbktRb2dJQ0J0Y1M1a1pXeGhlU2d4TUNrS1pXNWtDZ3BzYjJOaGJDQm1kVzVqZEdsdmJpQnZibDlzYjJGa0tDa0tJQ0FnSUd4dlkyRnNJR1J6VTNCbGJHd2dQU0JrYzFOd1pXeHNjMXR0Y1M1VVRFOHVUV1V1UTJ4aGMzTXVVMmh2Y25ST1lXMWxLQ2xkQ2lBZ0lDQlRjR1ZzYkc1aGJXVWdQU0J0Y1M1VVRFOHVVM0JsYkd3b2RHOXpkSEpwYm1jb1pITlRjR1ZzYkM1dVlXMWxLU2t1VW1GdWEwNWhiV1VvS1FvZ0lDQWdhV1lnWkhOVGNHVnNiQ0JoYm1RZ1pITlRjR1ZzYkM1MGVYQmxJRDA5SUNkemNHVnNiQ2NnWVc1a0lGaFVZWEpPY2lBK0lEQWdkR2hsYmdvZ0lDQWdJQ0FnSUdsbUlHMXhMbFJNVHk1TlpTNUhaVzBvVTNCbGJHeHVZVzFsS1NncElHRnVaQ0J0Y1M1VVRFOHVUV1V1UjJWdEtGTndaV3hzYm1GdFpTa29LU0ErSURBZ2RHaGxiaUJ5WlhSMWNtNGdaVzVrQ2lBZ0lDQWdJQ0FnVTNSdmNFUlFVeWdwQ2lBZ0lDQWdJQ0FnYlhFdVkyMWtaaWduTDIxbGJYTndaV3hzSURFeklDSWxjeUluTENCVGNHVnNiRzVoYldVcENpQWdJQ0FnSUNBZ2JYRXVaR1ZzWVhrb0p6UnpKeWtLSUNBZ0lDQWdJQ0J0Y1M1VVRFOHVWMmx1Wkc5M0tDZFRjR1ZzYkVKdmIydFhibVFuS1M1RWIwTnNiM05sS0NrS0lDQWdJQ0FnSUNCU1pYTjFiV1ZFVUZNb0tRb2dJQ0FnWlc1a0NtVnVaQW9LTFMwdFFISmxkSFZ5YmlCaWIyOXNaV0Z1SUVCU1pYUjFjbTV6SUhSeWRXVWdhV1lnZEdobElHRmpkR2x2YmlCemFHOTFiR1FnWm1seVpTd2diM1JvWlhKM2FYTmxJR1poYkhObExncHNiMk5oYkNCbWRXNWpkR2x2YmlCamIyNWthWFJwYjI0b0tRb3RMUzFBWkdsaFoyNXZjM1JwWXlCa2FYTmhZbXhsTFc1bGVIUXRiR2x1WlRvZ2RXNWtaV1pwYm1Wa0xXWnBaV3hrQ2lBZ0lDQnlaWFIxY200Z2JYRXVWRXhQTGxoQmMzTnBjM1F1V0ZSR2RXeHNTR0YwWlhKRGIzVnVkQ2dwSUQ0Z01Bb2dJQ0FnTFMxeVpYUjFjbTRnYlhFdVZFeFBMazFsTGtOdmJXSmhkQ2dwSUMwdGIzSWdXRlJoY21kbGRBcGxibVFLQ214dlkyRnNJR1oxYm1OMGFXOXVJSFJoY21kbGRGOVVZVzVyS0NrS0lDQWdJR2xtSUZoVVlYSk9jaUErSURBZ2RHaGxiZ29nSUNBZ0lDQWdJRzF4TG1OdFpHWW9KeTk0ZEdGeUlDVnBKeXdnV0ZSaGNrNXlLUW9nSUNBZ0lDQWdJRzF4TG1SbGJHRjVLREl3S1FvZ0lDQWdaVzVrQ21WdVpBb0tiRzlqWVd3Z1puVnVZM1JwYjI0Z1kyRnpkQ2h6Y0dWc2JDa0tJQ0FnSUcxeExtTnRaR1lvSnk5allYTjBJQ1Z6Snl3Z2MzQmxiR3dwQ2lBZ0lDQnRjUzVrWld4aGVTZ3lNQ2tLSUNBZ0lHMXhMbVJ2WlhabGJuUnpLQ2tLTFMwdFFHUnBZV2R1YjNOMGFXTWdaR2x6WVdKc1pTMXVaWGgwTFd4cGJtVTZJSFZ1WkdWbWFXNWxaQzFtYVdWc1pBb2dJQ0FnYlhFdVpHVnNZWGtvTWpBcmJYRXVWRXhQTGsxbExrTmhjM1JVYVcxbFRHVm1kQzVTWVhjcENpQWdJQzB0SUcxeExtUmxiR0Y1S0RJd0syMXhMbFJNVHk1VGNHVnNiQ2h6Y0dWc2JDa3VUWGxEWVhOMFZHbHRaUzVTWVhjcENtVnVaQW9LYkc5allXd2dablZ1WTNScGIyNGdkWE5sWDJGaEtHRmhLUW9nSUNBZ2JYRXVZMjFrWmlnbkwyRnNkQ0JoWTNScGRtRjBaU0FsY3ljc0lGUk1UeTVOWlM1QmJIUkJZbWxzYVhSNUtHRmhLUzVKUkNrS0lDQWdJRzF4TG1SbGJHRjVLREl3S1FvZ0lDQWdiWEV1Wkc5bGRtVnVkSE1vS1FvdExTMUFaR2xoWjI1dmMzUnBZeUJrYVhOaFlteGxMVzVsZUhRdGJHbHVaVG9nZFc1a1pXWnBibVZrTFdacFpXeGtDaUFnSUNCdGNTNWtaV3hoZVNneU1DdHRjUzVVVEU4dVRXVXVRMkZ6ZEZScGJXVk1aV1owTGxKaGR5a0taVzVrQ2dwc2IyTmhiQ0JtZFc1amRHbHZiaUJrYzE5eVpXRmtlU2hrY3lrS0lDQWdJR2xtSUdSekxuUjVjR1VnUFQwZ0ozTndaV3hzSnlCMGFHVnVDaUFnSUNBZ0lDQWdjbVYwZFhKdUlHMXhMbFJNVHk1TlpTNVRjR1ZzYkZKbFlXUjVLRk53Wld4c2JtRnRaU2tnWVc1a0lHNXZkQ0J0Y1M1VVRFOHVUV1V1UTJGemRHbHVaeWdwQ2lBZ0lDQmxiSE5sYVdZZ1pITXVkSGx3WlNBOVBTQW5ZV0VuSUhSb1pXNEtJQ0FnSUNBZ0lDQnlaWFIxY200Z2JYRXVWRXhQTGsxbExrRnNkRUZpYVd4cGRIbFNaV0ZrZVNoMGIzTjBjbWx1Wnloa2N5NXVZVzFsS1NrZ1lXNWtJRzV2ZENCdGNTNVVURTh1VFdVdVEyRnpkR2x1WnlncENpQWdJQ0JsYm1RS1pXNWtDZ3BzYjJOaGJDQm1kVzVqZEdsdmJpQmhZM1JwYjI0b0tRb2dJQ0FnYkc5allXd2diWGxmWTJ4aGMzTWdQU0J0Y1M1VVRFOHVUV1V1UTJ4aGMzTXVVMmh2Y25ST1lXMWxLQ2tLSUNBZ0lHeHZZMkZzSUdSeklEMGdaSE5UY0dWc2JITmJiWGxmWTJ4aGMzTmRDaUFnSUNBdExTQnBaaUJ1YjNRZ1lTQmtjeUJqYkdGemN5d2djbVYwZFhKdUNpQWdJQ0JwWmlCdWIzUWdaSE1nZEdobGJpQnlaWFIxY200Z1pXNWtDaUFnSUNBdExTQnBaaUJrY3lCaFltbHNhWFI1SUdsemJpZDBJSEpsWVdSNUxDQnlaWFIxY200S0lDQWdJR2xtSUcxNVgyTnNZWE56SUg0OUlDZENVa1FuSUdGdVpDQnViM1FnWkhOZmNtVmhaSGtvZEc5emRISnBibWNvWkhNdWJtRnRaU2twSUhSb1pXNGdjbVYwZFhKdUlHVnVaQW9nSUNBZ1UzUnZjRVJRVXlncENpQWdJQ0IwWVhKblpYUmZWR0Z1YXlncENpQWdJQ0JwWmlCa2N5NTBlWEJsSUQwOUlDZHpjR1ZzYkNjZ2RHaGxiZ29nSUNBZ0lDQWdJR05oYzNRb1UzQmxiR3h1WVcxbEtRb2dJQ0FnWld4elpRb2dJQ0FnSUNBZ0lIVnpaVjloWVNoMGIzTjBjbWx1Wnloa2N5NXVZVzFsS1NrS0lDQWdJR1Z1WkFvZ0lDQWdkMmhwYkdVZ2JYRXVWRXhQTGsxbExrTmhjM1JwYm1jb0tTQmtid29nSUNBZ0lDQWdJRzF4TG1SdlpYWmxiblJ6S0NrS0lDQWdJQ0FnSUNCdGNTNWtaV3hoZVNnMU1Da0tJQ0FnSUdWdVpBb2dJQ0FnVW1WemRXMWxSRkJUS0NrS1pXNWtDZ3B5WlhSMWNtNGdlMjl1Ykc5aFpEMXZibDlzYjJGa0xDQmpiMjVrWm5WdVl6MWpiMjVrYVhScGIyNHNJR0ZqZEdsdmJtWjFibU05WVdOMGFXOXVmUT09IiwKIGNhdGVnb3J5ID0gImdlbmVyYWwiLAogdHlwZSA9ICJjb25kaXRpb25zIiwKIG5hbWUgPSAiQ2hhaW5EcyIsCn0=
Full Source Code
Code:
---@type Mq
---@type ImGui
local mq = require('mq')
local Spellname=''
-- if XTarNr == 0 then no targeting shall be needed
-- important to make this work: insert the slot in XTargetWindow where the Tank resides who shell get the ds'es
local XTarNr = 11 -- ATTN: set your Tank to a specific Xtended Target Slot and insert number here
local dsSpells = {
MAG={name='Scorching Skin',type='spell'},
DRU={name='Daggerthorn',type='spell'},
}
local function StopDPS()
mq.cmd('/squelch /mqp on')
mq.delay(10)
if mq.TLO.Me.Class.ShortName() == 'BRD' then
mq.cmd('/squelch /twist off')
mq.delay(10)
mq.cmd('/squelch /stopsong')
mq.delay(10)
end
--mq.cmd('/attack off')
--mq.delay(10)
mq.cmd('/squelch /boxr pause')
mq.delay(10)
while mq.TLO.Me.Casting.ID() do
mq.delay(100)
end
end
local function ResumeDPS()
mq.cmd('/squelch /mqp off')
mq.delay(10)
if mq.TLO.Me.Class.ShortName() == 'BRD' then
mq.cmd('/squelch /twist on')
mq.delay(10)
end
mq.cmd('/squelch /boxr unpause')
mq.delay(10)
end
local function on_load()
local dsSpell = dsSpells[mq.TLO.Me.Class.ShortName()]
Spellname = mq.TLO.Spell(tostring(dsSpell.name)).RankName()
if dsSpell and dsSpell.type == 'spell' and XTarNr > 0 then
if mq.TLO.Me.Gem(Spellname)() and mq.TLO.Me.Gem(Spellname)() > 0 then return end
StopDPS()
mq.cmdf('/memspell 13 "%s"', Spellname)
mq.delay('4s')
mq.TLO.Window('SpellBookWnd').DoClose()
ResumeDPS()
end
end
---@return boolean @Returns true if the action should fire, otherwise false.
local function condition()
---@diagnostic disable-next-line: undefined-field
return mq.TLO.XAssist.XTFullHaterCount() > 0
--return mq.TLO.Me.Combat() --or XTarget
end
local function target_Tank()
if XTarNr > 0 then
mq.cmdf('/xtar %i', XTarNr)
mq.delay(20)
end
end
local function cast(spell)
mq.cmdf('/cast %s', spell)
mq.delay(20)
mq.doevents()
---@diagnostic disable-next-line: undefined-field
mq.delay(20+mq.TLO.Me.CastTimeLeft.Raw)
-- mq.delay(20+mq.TLO.Spell(spell).MyCastTime.Raw)
end
local function use_aa(aa)
mq.cmdf('/alt activate %s', TLO.Me.AltAbility(aa).ID)
mq.delay(20)
mq.doevents()
---@diagnostic disable-next-line: undefined-field
mq.delay(20+mq.TLO.Me.CastTimeLeft.Raw)
end
local function ds_ready(ds)
if ds.type == 'spell' then
return mq.TLO.Me.SpellReady(Spellname) and not mq.TLO.Me.Casting()
elseif ds.type == 'aa' then
return mq.TLO.Me.AltAbilityReady(tostring(ds.name)) and not mq.TLO.Me.Casting()
end
end
local function action()
local my_class = mq.TLO.Me.Class.ShortName()
local ds = dsSpells[my_class]
-- if not a ds class, return
if not ds then return end
-- if ds ability isn't ready, return
if my_class ~= 'BRD' and not ds_ready(tostring(ds.name)) then return end
StopDPS()
target_Tank()
if ds.type == 'spell' then
cast(Spellname)
else
use_aa(tostring(ds.name))
end
while mq.TLO.Me.Casting() do
mq.doevents()
mq.delay(50)
end
ResumeDPS()
end
return {onload=on_load, condfunc=condition, actionfunc=action}
What if I would create a hotbutton on my tank like:
/dggae /lem event ChainDs off ## This will make shure, that all Mages will have this event disabled
/timed 400 /dex Mag1 /lem event ChainDs on
/timed 400 /dex Mag2 /lem event ChainDs on
/timed 400 /dex Mag3 /lem event ChainDs on
/dex Mag4 /lem event ChainDs on
where Mag1 .. Mag4 would be the names of my for mage
This will cause to run the event on 4 Mages, with a timeshift of 400 ms .....
During fighttime this timeshift would not stay fixed, as each mage works on its own ... but a simple click at the next start of a fight will sync them again with this timeshift