• You've discovered RedGuides, an EverQuest multi-boxing and scripting community 🧙‍♀️⚙️. We want you to play several EQ characters at once, come join us and say hello! 👋

  • A TLP without truebox has thawed (Very Vanilla ready)
    Frostreaver
KissAssist

KissAssist Release KissAssist (3 Viewers) 12.002.039

No permission to download
Try using the
Code:
/switchnow
command,

Code:
/switchnow 0
should be good if they just aren't switching fast enough,
Code:
/switchnow 1 ${Target.ID}
will have them switch and HOLD that target even if your MA switches to another target


Hi Dread.

Thank you for this advice to help with issue #1.

However I need more clarification please.

I don't find this txt in kissassist, where is it located?

How do i use this information when using kissassist?

What I do find in kissassist is pictured below ( TargetSwitchingOn=0 )
All character's .ini files are the same.

Please advise.
 

Attachments

  • Screenshot 2026-06-20 104859.png
    Screenshot 2026-06-20 104859.png
    5.3 KB · Views: 0
Hi Dread.

Thank you for this advice to help with issue #1.

However I need more clarification please.

I don't find this txt in kissassist, where is it located?

How do i use this information when using kissassist?

What I do find in kissassist is pictured below ( TargetSwitchingOn=0 )
All character's .ini files are the same.

Please advise.
Targetswitchingon is for your ma, so you could manually switch targets and not snap back to it

Nothing directly to do with switchnow or backoff
 
Targetswitchingon is for your ma, so you could manually switch targets and not snap back to it

Nothing directly to do with switchnow or backoff
Ok nice, thanks for clarifying that.
I manually drive from my MA with no macros so this is not relevant in my case.

I am barely novice/intermediate with MQ let alone coding, but I feel like there is something broken in the behind the scenes coding logic in kiss both for melee and my wiz/mag/enc nuking issues as I don't see any .ini configuration things to address this.

Does that sound like a fair assessment or am I missing something?
 
Ok I did some investigation using Claude Ai (since I am not a coder)
It has determined for my stuck melee issue #1 that Kiss is built around group action only.
Raid assist sub routines were built but abandoned and left unfinished/not implemented.

When in a raid it breaks my native group main assist setting, and that leaves my assisting toons with no action to trigger switching mobs mid fight.

Attached is a bug report with details and corrections to fix this in the main release. (If Claude is correct of course)

It also rewrote a corrected personal version of kissassist.mac for me which I will test as soon as i can to confirm its fix worked correctly.

Hope this is helpful, and can be implemented into live Kissassist.

Next to work on is the casters not chain nuking properly.
 

Attachments

Here is a copy paste of the bug report in case that file does not work.

Bug Report: Followers don't retarget when raid Main Assist switches targets​


Component: Sub CombatTargetCheck / Sub CombatTargetCheckRaidAffects: Any raid (12+ characters across multiple groups), regardless of roleSeverity: High for raid users — followers attack a single target and never switch even after the raid MA moves on, requiring manual intervention or a full combat reset to recover.


Summary​


In raid format, non-MA characters never notice when the designated raid Main Assist switches targets mid-fight. They correctly assist onto the first target in an engagement, then get stuck on it (or its corpse) until something external forces a re-target (e.g. /switch, a broadcasted target ID, or the mob despawning).


This does not happen in pure group play with a properly set in-game Group Main Assist — that path works as designed. It is specific to raid mode, where the in-game raid assist designation overrides/replaces the native group Main Assist flag, and the macro has no live mechanism that follows the raid assist target instead.


Root cause​


There are three contributing issues, all in the same area of code:


1.​


| Line ~2311, in CombatReset:<br>/if (!${IAmMA} &amp;&amp; ${TargetSwitchingOn}) /varset TargetSwitchingOn 0<br><br>| Line ~8838, in role setup:<br>/if (${TargetSwitchingOn} &amp;&amp; !${IAmMA}) /varset TargetSwitchingOn 0<br>

This is presumably intentional (TargetSwitchingOn appears designed to let the MA react to a manually-changed Target.ID}), but it means followers have zero fallback to this mechanism — they're entirely dependent on the Group.MainAssist/raid-assist detection block in CombatTargetCheck working correctly.


2. The live retarget gate in​


| Sub CombatTargetCheck, ~line 1353<br>/if (${Spawn[=${MainAssist}].ID} &amp;&amp; ${Group.MainAssist.ID} &amp;&amp; ${Spawn[=${MainAssist}].ID}==${Group.MainAssist.ID}) {<br> /if (!${IAmMA}) {<br> /if (${Target.ID}!=${Me.GroupAssistTarget.ID}) {<br> /if (${MyTargetID}!=${Me.GroupAssistTarget.ID} &amp;&amp; ${Spawn[id ${Me.GroupAssistTarget.ID} npc].ID}) {<br> /varset MyTargetID ${Me.GroupAssistTarget.ID}<br> }<br> }<br> }<br> ...<br>} else {<br> | falls back to CalledTargetID / AttackCalled broadcast event only<br>}<br>

This is the sub that's actually called every combat tick (from inside Sub Combat's attack loop, and elsewhere). It only ever checks Group.MainAssist/Me.GroupAssistTarget. When in a raid, the native in-game Group Main Assist designation gets overridden by the raid assist designation, so Group.MainAssist.ID no longer matches Spawn[=${MainAssist}].ID}, and this whole block is skipped. Followers fall into the else branch, which only updates via CalledTargetID, populated by the AttackCalled event — i.e., it only works if something explicitly broadcasts a target switch and the follower's broadcast plugin (EQBC/DanNet) receives it. There is no native polling of raid assist state at all in the sub that's actually called.


3.​


grep -n "call CombatTargetCheckRaid" kissassist.mac<br>→ (no results)<br>

CombatTargetCheckRaid is defined (~line 1420) but never invoked anywhere in the macro. Every actual call site goes to the group-only CombatTargetCheck.


Even setting that aside, the sub itself doesn't fully implement raid support:


/declare CIDCheck int local 0<br>/if (${Raid.Members}) {<br> /varset CIDCheck ${RaidTargetID}<br>} else {<br> /varset CIDCheck <br>}<br>| Check target matches MA if group mainassist assigned and MA is in group<br>/if <br>/if (${Spawn[=${MainAssist}].ID} &amp;&amp; ${Group.MainAssist.ID} &amp;&amp; ${Spawn[=${MainAssist}].ID}==${Group.MainAssist.ID}) {<br> ...<br>

CIDCheck is computed from ${RaidTargetID} but then never referenced again anywhere in the sub — the actual gate is still the same Group.MainAssist check as the non-raid version, so even a wired-up version of this sub would behave identically to CombatTargetCheck and still fail in raids. There's also a stray, condition-less /if line immediately above the real one, which looks like leftover/abandoned edit debris.


4.​


| Sub InitData, line ~16240 (called exactly once, at line ~307, before the main loop starts)<br>/noparse /varset RaidTargetID ${If[${Me.RaidAssistTarget[${RaidAssistEntry}].ID},${Me.RaidAssistTarget[${RaidAssistEntry}].ID},${If[${Me.XTarget[${XTSlot}].ID},${Me.XTarget[${XTSlot}].ID},0]}]}<br>

InitData runs a single time during macro startup. RaidTargetID is therefore frozen at whatever the raid MA happened to be targeting (if anything) the instant the macro launched, and never refreshes. Even if CombatTargetCheckRaid were wired in and its CIDCheck value were actually used, it would still be stale for the entire macro session.


Net effect​


There is currently no live path for a follower to detect that the raid Main Assist has switched targets:


  • TargetSwitchingOn → forced off for non-MA.
  • Group.MainAssist → not populated/matching once a raid assist designation is active.
  • CombatTargetCheckRaid → dead code, and incomplete even if called.
  • RaidTargetID → stale, computed once at startup.

The only thing that still works is the CalledTargetID/AttackCalled broadcast fallback, which depends entirely on something else explicitly sending a target-switch event (e.g. via the /switch bind) and the follower's broadcast plugin receiving it.


Suggested fix​


In Sub CombatTargetCheck, poll ${Me.RaidAssistTarget[${RaidAssistEntry}].ID} live (not the cached RaidTargetID) and use it as an additional/alternate branch alongside the existing Group.MainAssist check, e.g.:


/declare RaidAssistTargetID int local 0<br>/if (${Raid.Members}) /varset RaidAssistTargetID ${Me.RaidAssistTarget[${RaidAssistEntry}].ID}<br><br>/if (${Raid.Members} &amp;&amp; ${RaidAssistTargetID}) {<br> | raid assist path — compare against RaidAssistTargetID instead of Me.GroupAssistTarget<br> ...<br>} else /if (${Spawn[=${MainAssist}].ID} &amp;&amp; ${Group.MainAssist.ID} &amp;&amp; ...) {<br> | existing group MA path, unchanged<br> ...<br>} else {<br> | existing CalledTargetID/AttackCalled fallback, unchanged<br>}<br>

This mirrors the existing group-MA logic structure exactly, just sourced from the raid assist TLO instead of Group.MainAssist/Me.GroupAssistTarget, and polled every tick rather than cached once at startup. CombatTargetCheckRaid could then either be removed (since it's unused) or replaced by actually wiring this logic into it and calling it instead of CombatTargetCheck when ${Raid.Members} is true — either approach works; the important part is that something live actually checks raid assist state per-tick.


Reproduction​


  1. Build a raid of 2+ groups (12+ characters), each group running KissAssist.
  2. Set the in-game Group Main Assist on a tank in one group as normal.
  3. Have a raid leader (or anyone with raid assist privileges) set a raid Main Assist / Raid Assist 1, which overrides the group-level MA designation.
  4. Engage a mob; followers correctly assist.
  5. Have the raid MA switch to a new target (e.g. mob dies and the next target is picked, or the MA manually retargets).
  6. Observe: followers in groups other than the raid MA's own group (and frequently even within it, once Group.MainAssist stops matching) continue attacking the original target/corpse and never switch, until /switch is broadcast or some other external trigger forces it.

Environment​


  • KissAssist version: v12.002 (KissRevision = 039, per the macro's own /declare KissRevision string outer 039), maintained for RedGuides by Ctaylor22.
  • Tested in raid format only; group-only play with native Group Main Assist set is unaffected.
 
Here is a report from Claude Ai on the casters failing to chain nuke consistently and correctly, and suggested remediation.
Testing is still required for all these Ai generated fixes. I will try to test them today and report back my personal findings.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Bug Report: DPS spells, AAs, and discs use buff Duration instead of RecastTime to gate re-use, causing inconsistent/delayed casting​


Component: Sub CombatCastAffects: Any class casting "Regular spell," AA, or disc entries from DPS=/Burn= arrays — confirmed impact on Wizard nukes (Cloudburst Bolts, Wildmagic Burst/Strike Rk. II), expected to affect Mage, Enchanter, and any melee/hybrid using MashArray/disc-style DPS= entries identically, since the logic is class-agnostic.Severity: High — produces large, inconsistent DPS loss (observed: ~80% DPS reduction vs. comparable players) with no error, debug warning, or obvious symptom other than "sometimes casts, sometimes doesn't," making it hard to diagnose from in-game observation alone.


Summary​


Sub CombatCast computes how long to wait before attempting to use a spell/AA/disc again (DPSTimer${i}) using the spell's buff/debuff effect Duration (Spell[].Duration / Spell[].MyDuration) instead of its actual recast time (Spell[].RecastTime). These are unrelated values. Duration describes how long a spell's effect lingers on a target once it lands; RecastTime describes how long until the caster can use the spell again. For most pure-damage nukes and many discs, Duration is 0 or unrelated to recast entirely, which routes the calculation into a flat fallback (${DPSInterval}s, default 2s) regardless of the spell's real cooldown — and for spells/discs that do report a nonzero Duration for unrelated reasons, the timer becomes MyDuration × 10 (± DAMod), a number with no necessary relationship to true recast at all.


The practical effect: casters sit idle well past the point where MQ2 and the game itself report the spell/disc as ready again, because the macro's own internally-tracked DPSTimer${i} is still counting down based on the wrong number. This is checked as a hard, independent gate (/if (${ABTimer${i}} || ${DPSTimer${i}} || ${FDTimer${i}}) /break) in addition to the correct MQ2 readiness check, so both must clear — meaning a wrong, too-long DPSTimer${i} blocks the cast even when the game says it's available.


Root cause​


| Sub CombatCast, ~line 1841 (original numbering)<br>| Regular spells<br>} else /if (${Spell[${DPSPart1}].Duration.TotalSeconds}&gt;0) {<br> /if (${Select[${DAMod.Left[1]},-,+]}) {<br> /varcalc DPSTimer${i} (${Spell[${DPSPart1}].MyDuration.TotalSeconds}${DAMod})*10<br> } else {<br> /varcalc DPSTimer${i} ${DAMod}*10<br> }<br>| Spells with no timers assign DPS interval<br>} else {<br> /varset DPSTimer${i} ${DPSInterval}s<br>}<br>

Same pattern repeats for AAs:


} else /if (${Me.AltAbility[${DPSPart1}]}) {<br> /if (${Me.AltAbility[${DPSPart1}].Spell.MyDuration.TotalSeconds}) {<br> ...uses MyDuration...<br> } else /if (${Me.AltAbility[${DPSPart1}].Spell.Trigger.MyDuration.TotalSeconds}) {<br> ...uses Trigger.MyDuration...<br> }<br> | (no final else - DPSTimer silently left unset/0 if neither matches)<br>}<br>

And for discs:


| Disc Timers<br>} else /if (${Spell[${DPSPart1}].Duration}&gt;0 &amp;&amp; ${Me.CombatAbility[${DPSPart1}]}) {<br> /varcalc DPSTimer${i} ${Spell[${DPSPart1}].MyDuration.TotalSeconds}*10<br>| AA and disc with no timers assign DPS interval<br>} else {<br> /varset DPSTimer${i} ${DPSInterval}s<br>}<br>

Notably, the macro does use Spell[].RecastTime correctly elsewhere in the same file — Sub CastDisc loops on Me.CombatAbilityReady/RecastTime to pace its own internal retry, and a heal-related GCD calc elsewhere also references RecastTime. So the correct field is known and used in other subs; CombatCast's own timer-setting block is the one place that substitutes the wrong field.


There's also a DAMod= INI field (the 3rd/4th pipe-delimited value on a DPS=/Burn= line) that functions as a manual per-spell correction factor — its existence suggests this was a known/acknowledged inaccuracy that users were expected to hand-tune around, rather than fixing the underlying field reference.


Why this produces "sometimes casts, sometimes doesn't" rather than a consistent failure​


  • Whether a given spell/disc reports a nonzero Duration/MyDuration for unrelated reasons (e.g. a secondary proc/debuff component on an otherwise pure-damage spell) varies spell-by-spell and expansion-by-expansion, so some entries happen to land close to their real recast by coincidence while others don't.
  • For entries that fall through to the ${DPSInterval}s flat fallback (default 2s), anything with a true recast under 2s gets throttled unnecessarily; anything with recast just over 2s gets attempted slightly early, fails the live MQ2 readiness check, and then has to wait for the next full loop pass rather than retrying immediately — producing visibly inconsistent cadence rather than a clean, predictable cycle.
  • The bug is identical across spells, AAs, and discs, and is completely class-agnostic — it explains matching symptoms across a Wizard's nukes and a Bard/Monk's combat abilities/discs, since they all route through this same block.

Suggested fix​


Use Spell[].RecastTime (or Me.AltAbility[].Spell.RecastTime for AAs) as the primary source for DPSTimer${i}} whenever it resolves to a nonzero value, falling back to the existing Duration/MyDuration-based calculation only when RecastTime isn't available (e.g. some non-live/EMU spell data gaps), and falling back to ${DPSInterval}s} only as a last resort. DAMod can continue to apply on top of whichever base is used, so existing tuned INI values degrade gracefully rather than breaking outright — though note that any DAMod someone has already hand-tuned against the old (wrong) Duration-based number will likely need re-tuning once it's applied against the correct RecastTime-based number instead.


Example for the "Regular spells" branch:


} else /if (${Spell[${DPSPart1}].Duration.TotalSeconds}&gt;0 || ${Spell[${DPSPart1}].RecastTime.TotalSeconds}&gt;0) {<br> /if (${Spell[${DPSPart1}].RecastTime.TotalSeconds}&gt;0) {<br> /if (${Select[${DAMod.Left[1]},-,+]}) {<br> /varcalc DPSTimer${i} (${Spell[${DPSPart1}].RecastTime.TotalSeconds}${DAMod})*10<br> } else {<br> /varcalc DPSTimer${i} ${DAMod}*10<br> }<br> } else /if (${Select[${DAMod.Left[1]},-,+]}) {<br> /varcalc DPSTimer${i} (${Spell[${DPSPart1}].MyDuration.TotalSeconds}${DAMod})*10<br> } else {<br> /varcalc DPSTimer${i} ${DAMod}*10<br> }<br>} else {<br> /varset DPSTimer${i} ${DPSInterval}s<br>}<br>

The same RecastTime-first, Duration-fallback pattern applies to the AA and Disc branches. The AA branch's missing final else (no fallback if neither Spell.MyDuration nor Spell.Trigger.MyDuration resolves) should also be closed with a ${DPSInterval}s fallback to avoid DPSTimer${i} being left unset/0 in that edge case.


Reproduction​


  1. Configure a DPS= entry for a pure-damage nuke with a short real recast (~2-3s) and no meaningful buff/debuff Duration (e.g. an instant-cast Wizard nuke, or any short-cooldown disc such as a rogue/monk damage proc-style combat ability).
  2. Engage a long-lived target (raid boss or any mob that survives many cast cycles) with DebugCombat/DebugCast enabled.
  3. Observe the logged DPSTimer${i} value against the spell/ability's actual known recast (checkable via /disc/spell gem cooldown UI, or Spell[name].RecastTime queried directly via /echo).
  4. Compare against in-game observation: the ability visibly comes off cooldown (lights up / is castable) well before the macro attempts it again, and the gap is inconsistent spell-to-spell rather than a fixed, predictable delay.

Environment​


  • KissAssist version: v12.002 (KissRevision = 039), maintained for RedGuides by Ctaylor22.
  • Observed primarily on Wizard (Cloudburst Bolts Rk. II, Wildmagic Burst Rk. II, Wildmagic Strike Rk. II), with the same underlying code path expected to affect any class using DPS=/Burn= array entries for spells, AAs, or discs — including Mage, Enchanter, Bard, and Monk.
 

Attachments

KissAssist Release KissAssist

Users who are viewing this thread

  • C
  • R
Back
Top
Cart