Soandso2
Well-known member
- Joined
- Mar 13, 2023
- RedCents
- 937¢
I am converting my macro to Lua, and I have run into a bug that I cannot figure out. I have a few clues, though, but no matter what I try, the problem persists.
It seems to occur when a target dies, because it does not happen while the target is alive. It also never happens when fighting mobs that do not die, like combat dummies. At first I thought that the problem happened because I had ONE check for being in combat, having a target, etc, and that quite a lot of stuff would still happen, even if the target died in the middle of the in-combat-check.
I tried to put checks for weather I have a target or not before everything I do, but still, when the target dies, the Lua crashes with the following message: attempt to compare nil with a number on row 107
And yes, nil in this case comes from mq.TLO.Target.Distance()
The whole Lua goes like this. I hope you can tell me why this fails and how to remedy it.
[CODE lang="Lua" title="bam.Lua" highlight="107"]mq = require('mq')
-- INIT VARIABLES
local terminate = false
local long = false
local foraging = false
local haveBegged = false
-- "Short Disciplines" are disciplines that are instant cast OR place a buff in either the buff or song windows, and generally have a short reuse timer.
local shortDiscs={
["Vigorous Shuriken"]=175,
["Curse of Sixteen Shadows"]=50,
["Bloodwalker's Synergy"]=50,
["Buffeting of Fists"]=50,
["Zlexak's Fang"]=50,
["Bloodwalker's Precision Strike"]=200,
["Dragons's Poise"]=50,
["Ecliptic Form"]=50,
["Heron Stance"]=50
}
-- "Long Disciplines" are disciplines that start the timer countdown in the discipline window, and generally have a long use (and reuse) timer. Use for raid targets or longer fights.
local longDiscs={
"Eye of the Storm",
"Heel of Zagali",
"Terrorpalm Discipline",
"Speed Focus Discipline",
"Ironfist Discipline"
}
-- "combatAAs" are Alt Abilities that must be activated (by hot button) in combat.
local combatAAs={
["1012"]={"Five Point Palm",100},
["1235"]={"Two-Finger Wasp Touch",50},
["377"]={"Focused Destructive Force",15},
["7001"]={"Zan Fi's Whistle",50}
}
local reflex = mq.TLO.Spell("Decisive Reflexes").RankName()
-- STARTUP MESSAGES
print('Running Bam.Lua')
print('Only using short duration disciplines')
print('Not foraging')
print('/bam terminate to end Bam.Lua')
print('/bam long on/off for using long duration combat discs')
print('/bam forage on/off for automatic foraging when not in combat')
-- HANDLE BINDS
local function binds(cmd,val)
if cmd == 'terminate' then
print('Terminating bam.Lua')
terminate = true
elseif cmd == "long" then
if val == "on" then
long = true
print('Using long duration disciplines')
else
long = false
print('Only using short duration disciplines')
end
elseif cmd == "forage" then
if val == "on" then
foraging = true
print('Foraging')
else
foraging = false
print('Not foraging')
end
else
print(cmd..' is not a reqognised command')
end
end
mq.bind('/bam', binds)
-- CHECKING THAT WE ARE ACTUALLY ABLE TO DO WHATEVER WE WANT TO DO
local function goodToGo()
-- Credit: LeRogue.Lua by @rawmotion at RedGuides.com
return not mq.TLO.Me.Stunned()
and not mq.TLO.Me.Dead()
and not mq.TLO.Me.Feigning()
and not mq.TLO.Me.Ducking()
and not mq.TLO.Me.Silenced()
and not mq.TLO.Me.Charmed()
and not mq.TLO.Me.Mezzed()
and not mq.TLO.Me.Invulnerable()
and not mq.TLO.Me.Casting()
end
-- HANDLE COMBAT DISCIPLINES: SHORT AND LONG
local function useShortDisc(discName,targetDist)
local shortDisc = mq.TLO.Spell(discName).RankName
if mq.TLO.Target.ID() and goodToGo() and mq.TLO.Me.CombatAbilityReady(shortDisc)() and mq.TLO.Target.Distance() < targetDist then
mq.cmdf('/doability "%s"',shortDisc)
printf('Short disc: \ay%s',shortDisc)
mq.delay(1000)
end
end
local function useLongDisc(discName)
local longDisc = mq.TLO.Spell(discName).RankName
if mq.TLO.Target.ID() and goodToGo() and not mq.TLO.Me.ActiveDisc.ID() and mq.TLO.Me.CombatAbilityReady(longDisc)() then
mq.cmdf('/doability "%s"',longDisc)
printf('Long disc: \am%s',longDisc)
mq.delay(1000)
end
end
local function useDiscs(useLong)
for disc,range in pairs(shortDiscs) do
if mq.TLO.Target.ID() and goodToGo() then
useShortDisc(disc,range)
end
end
if useLong then
for _,disc in pairs(longDiscs) do
useLongDisc(disc)
end
end
end
-- HANDLE COMBAT AAs AND COMBAT SKILLS
local function useCombatAAs()
for act,aaData in pairs (combatAAs) do
if mq.TLO.Target.ID() and goodToGo() and mq.TLO.Me.AltAbilityReady(aaData[1])() and mq.TLO.Target.Distance() < aaData[2] then
mq.delay(500)
mq.cmdf('/alt activate "%s"',act)
printf('Combat AA: \ag%s',aaData[1])
end
end
end
local function useCombatSkill(combatSkill)
if mq.TLO.Target.ID() and mq.TLO.Target.Distance()<15 and goodToGo() and mq.TLO.Me.AbilityReady(combatSkill)() then
mq.cmdf('/doability "%s"',combatSkill)
printf('Combat Skill: \at%s',combatSkill)
mq.delay(500)
end
end
local function useCombatSkills()
if mq.TLO.Me.AbilityReady("Begging")() and not haveBegged and mq.TLO.Target.PctHPs() < 90 then
mq.cmd("/attack off")
mq.delay(100)
mq.cmd("/doability Begging")
print("CombatSkill: Begging")
haveBegged = true
mq.delay(500)
mq.cmd("/attack on")
end
useCombatSkill("Disarm")
useCombatSkill("Intimidation")
if mq.TLO.Me.PctHPs() < 50 then
useCombatSkill("Mend")
end
end
-- HANDLE FORAGING
local function useForage()
mq.cmd("/doability Forage")
mq.delay(500)
if mq.TLO.Cursor.ID() ~= nil then
printf('Foraged: %s',mq.TLO.Cursor.Name())
mq.cmd("/autoinv")
mq.delay(500)
if mq.TLO.Cursor.ID() ~= nil then
printf('Bonus: %s',mq.TLO.Cursor.Name())
mq.cmd("/autoinv")
end
end
end
-- HANDLE CLICKYS
local function useClickys(clickyName)
if clickyName == "combat" then
if mq.TLO.Spell("Celestial Tranquility").Stacks() and not mq.TLO.Me.Buff("Celestial Tranquility").ID() then
mq.cmdf('/useitem "%s"',"Celestial Fists")
end
if mq.TLO.Spell("Seven Chakras Heel Technique").Stacks and not mq.TLO.Me.Song("Seven Chakras Heel Technique").ID() and mq.TLO.FindItem("Soulforge Tunic of the Celestial Zenith").TimerReady() == 0 then
mq.cmdf('/useitem "%s"',"Soulforge Tunic of the Celestial Zenith")
end
if not mq.TLO.FindItem("Transcended Fistwraps of Immortality").TimerReady() then
mq.cmdf('/useitem "%s"',"Transcended Fistwraps of Immortality")
end
else
if mq.TLO.FindItem(clickyName).ID() > 0 and mq.TLO.FindItem(clickyName).TimerReady() == 0 then
mq.cmdf('/useitem "%s"',clickyName)
end
end
end
-- MAIN LOOP
while not terminate do
-- Combat indifferent, instant click/use, always use
if not mq.TLO.Me.Buff(reflex).ID() and mq.TLO.Me.CombatAbilityReady(reflex)() and mq.TLO.Spell(reflex).Stacks() and goodToGo() then
mq.cmdf('/doability "%s"',reflex)
end
-- Do this when in combat
if mq.TLO.Me.Combat() and mq.TLO.Target.ID() and goodToGo() then
useDiscs(long)
useCombatSkills()
useCombatAAs()
useClickys("combat")
end
-- Do this when not in combat
if not mq.TLO.Me.Combat() and goodToGo() then
if haveBegged then
haveBegged = false
end
if not mq.TLO.Me.Aura.ID() and not mq.TLO.Me.Moving() then
mq.cmd("/disc Master's Aura")
end
if foraging and mq.TLO.Me.AbilityReady("Forage") then
useForage()
end
if not mq.TLO.Me.Buff("Illusion: Human").ID() and not mq.TLO.Me.Moving() then
useClickys("Circlet of Disguise")
end
if mq.TLO.Me.Buff("Familiar: Fungal Underbulk").ID() == nil and not mq.TLO.Me.Moving() then
useClickys("Fungal Underbulk")
mq.delay(5050)
mq.cmd("/familiar leave")
end
end
end[/CODE]
It seems to occur when a target dies, because it does not happen while the target is alive. It also never happens when fighting mobs that do not die, like combat dummies. At first I thought that the problem happened because I had ONE check for being in combat, having a target, etc, and that quite a lot of stuff would still happen, even if the target died in the middle of the in-combat-check.
I tried to put checks for weather I have a target or not before everything I do, but still, when the target dies, the Lua crashes with the following message: attempt to compare nil with a number on row 107
And yes, nil in this case comes from mq.TLO.Target.Distance()
The whole Lua goes like this. I hope you can tell me why this fails and how to remedy it.
[CODE lang="Lua" title="bam.Lua" highlight="107"]mq = require('mq')
-- INIT VARIABLES
local terminate = false
local long = false
local foraging = false
local haveBegged = false
-- "Short Disciplines" are disciplines that are instant cast OR place a buff in either the buff or song windows, and generally have a short reuse timer.
local shortDiscs={
["Vigorous Shuriken"]=175,
["Curse of Sixteen Shadows"]=50,
["Bloodwalker's Synergy"]=50,
["Buffeting of Fists"]=50,
["Zlexak's Fang"]=50,
["Bloodwalker's Precision Strike"]=200,
["Dragons's Poise"]=50,
["Ecliptic Form"]=50,
["Heron Stance"]=50
}
-- "Long Disciplines" are disciplines that start the timer countdown in the discipline window, and generally have a long use (and reuse) timer. Use for raid targets or longer fights.
local longDiscs={
"Eye of the Storm",
"Heel of Zagali",
"Terrorpalm Discipline",
"Speed Focus Discipline",
"Ironfist Discipline"
}
-- "combatAAs" are Alt Abilities that must be activated (by hot button) in combat.
local combatAAs={
["1012"]={"Five Point Palm",100},
["1235"]={"Two-Finger Wasp Touch",50},
["377"]={"Focused Destructive Force",15},
["7001"]={"Zan Fi's Whistle",50}
}
local reflex = mq.TLO.Spell("Decisive Reflexes").RankName()
-- STARTUP MESSAGES
print('Running Bam.Lua')
print('Only using short duration disciplines')
print('Not foraging')
print('/bam terminate to end Bam.Lua')
print('/bam long on/off for using long duration combat discs')
print('/bam forage on/off for automatic foraging when not in combat')
-- HANDLE BINDS
local function binds(cmd,val)
if cmd == 'terminate' then
print('Terminating bam.Lua')
terminate = true
elseif cmd == "long" then
if val == "on" then
long = true
print('Using long duration disciplines')
else
long = false
print('Only using short duration disciplines')
end
elseif cmd == "forage" then
if val == "on" then
foraging = true
print('Foraging')
else
foraging = false
print('Not foraging')
end
else
print(cmd..' is not a reqognised command')
end
end
mq.bind('/bam', binds)
-- CHECKING THAT WE ARE ACTUALLY ABLE TO DO WHATEVER WE WANT TO DO
local function goodToGo()
-- Credit: LeRogue.Lua by @rawmotion at RedGuides.com
return not mq.TLO.Me.Stunned()
and not mq.TLO.Me.Dead()
and not mq.TLO.Me.Feigning()
and not mq.TLO.Me.Ducking()
and not mq.TLO.Me.Silenced()
and not mq.TLO.Me.Charmed()
and not mq.TLO.Me.Mezzed()
and not mq.TLO.Me.Invulnerable()
and not mq.TLO.Me.Casting()
end
-- HANDLE COMBAT DISCIPLINES: SHORT AND LONG
local function useShortDisc(discName,targetDist)
local shortDisc = mq.TLO.Spell(discName).RankName
if mq.TLO.Target.ID() and goodToGo() and mq.TLO.Me.CombatAbilityReady(shortDisc)() and mq.TLO.Target.Distance() < targetDist then
mq.cmdf('/doability "%s"',shortDisc)
printf('Short disc: \ay%s',shortDisc)
mq.delay(1000)
end
end
local function useLongDisc(discName)
local longDisc = mq.TLO.Spell(discName).RankName
if mq.TLO.Target.ID() and goodToGo() and not mq.TLO.Me.ActiveDisc.ID() and mq.TLO.Me.CombatAbilityReady(longDisc)() then
mq.cmdf('/doability "%s"',longDisc)
printf('Long disc: \am%s',longDisc)
mq.delay(1000)
end
end
local function useDiscs(useLong)
for disc,range in pairs(shortDiscs) do
if mq.TLO.Target.ID() and goodToGo() then
useShortDisc(disc,range)
end
end
if useLong then
for _,disc in pairs(longDiscs) do
useLongDisc(disc)
end
end
end
-- HANDLE COMBAT AAs AND COMBAT SKILLS
local function useCombatAAs()
for act,aaData in pairs (combatAAs) do
if mq.TLO.Target.ID() and goodToGo() and mq.TLO.Me.AltAbilityReady(aaData[1])() and mq.TLO.Target.Distance() < aaData[2] then
mq.delay(500)
mq.cmdf('/alt activate "%s"',act)
printf('Combat AA: \ag%s',aaData[1])
end
end
end
local function useCombatSkill(combatSkill)
if mq.TLO.Target.ID() and mq.TLO.Target.Distance()<15 and goodToGo() and mq.TLO.Me.AbilityReady(combatSkill)() then
mq.cmdf('/doability "%s"',combatSkill)
printf('Combat Skill: \at%s',combatSkill)
mq.delay(500)
end
end
local function useCombatSkills()
if mq.TLO.Me.AbilityReady("Begging")() and not haveBegged and mq.TLO.Target.PctHPs() < 90 then
mq.cmd("/attack off")
mq.delay(100)
mq.cmd("/doability Begging")
print("CombatSkill: Begging")
haveBegged = true
mq.delay(500)
mq.cmd("/attack on")
end
useCombatSkill("Disarm")
useCombatSkill("Intimidation")
if mq.TLO.Me.PctHPs() < 50 then
useCombatSkill("Mend")
end
end
-- HANDLE FORAGING
local function useForage()
mq.cmd("/doability Forage")
mq.delay(500)
if mq.TLO.Cursor.ID() ~= nil then
printf('Foraged: %s',mq.TLO.Cursor.Name())
mq.cmd("/autoinv")
mq.delay(500)
if mq.TLO.Cursor.ID() ~= nil then
printf('Bonus: %s',mq.TLO.Cursor.Name())
mq.cmd("/autoinv")
end
end
end
-- HANDLE CLICKYS
local function useClickys(clickyName)
if clickyName == "combat" then
if mq.TLO.Spell("Celestial Tranquility").Stacks() and not mq.TLO.Me.Buff("Celestial Tranquility").ID() then
mq.cmdf('/useitem "%s"',"Celestial Fists")
end
if mq.TLO.Spell("Seven Chakras Heel Technique").Stacks and not mq.TLO.Me.Song("Seven Chakras Heel Technique").ID() and mq.TLO.FindItem("Soulforge Tunic of the Celestial Zenith").TimerReady() == 0 then
mq.cmdf('/useitem "%s"',"Soulforge Tunic of the Celestial Zenith")
end
if not mq.TLO.FindItem("Transcended Fistwraps of Immortality").TimerReady() then
mq.cmdf('/useitem "%s"',"Transcended Fistwraps of Immortality")
end
else
if mq.TLO.FindItem(clickyName).ID() > 0 and mq.TLO.FindItem(clickyName).TimerReady() == 0 then
mq.cmdf('/useitem "%s"',clickyName)
end
end
end
-- MAIN LOOP
while not terminate do
-- Combat indifferent, instant click/use, always use
if not mq.TLO.Me.Buff(reflex).ID() and mq.TLO.Me.CombatAbilityReady(reflex)() and mq.TLO.Spell(reflex).Stacks() and goodToGo() then
mq.cmdf('/doability "%s"',reflex)
end
-- Do this when in combat
if mq.TLO.Me.Combat() and mq.TLO.Target.ID() and goodToGo() then
useDiscs(long)
useCombatSkills()
useCombatAAs()
useClickys("combat")
end
-- Do this when not in combat
if not mq.TLO.Me.Combat() and goodToGo() then
if haveBegged then
haveBegged = false
end
if not mq.TLO.Me.Aura.ID() and not mq.TLO.Me.Moving() then
mq.cmd("/disc Master's Aura")
end
if foraging and mq.TLO.Me.AbilityReady("Forage") then
useForage()
end
if not mq.TLO.Me.Buff("Illusion: Human").ID() and not mq.TLO.Me.Moving() then
useClickys("Circlet of Disguise")
end
if mq.TLO.Me.Buff("Familiar: Fungal Underbulk").ID() == nil and not mq.TLO.Me.Moving() then
useClickys("Fungal Underbulk")
mq.delay(5050)
mq.cmd("/familiar leave")
end
end
end[/CODE]


Thank you, everyone, for your input!