• 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

Guide - what order do you enter your dps spells

Joined
Feb 6, 2007
RedCents
1,683¢
I was playing with my new wizard and noticed something peculiar about the order in which I entered my spells in the dps section of my macro.
First NOTE: This is my custom macro that is loosely based on kissassist, I suspect the same behavior will occur with KA but didn't verify it.

I listed my spells like this:

Rich (BB code):
Format=alt/item/gem | SpellName | start<HPs | stop<HPs
DamageSpell1=gem|Voidfrost Lure|90|20
DamageSpell2=gem|Flarelure|80|20
DamageSpell3=gem|Wildmagic Blast|70|20
DamageSpell4=gem|Ethereal Iceblight|60|50

I expect the macro to cast each spell in order, what I got was my wizard cast gem1, gem2, gem1, gem2, gem1. The casting never progressed past the first two spells.

Changing the order like this

Rich (BB code):
Format=alt/item/gem | SpellName | start<HPs | stop<HPs
DamageSpell1=gem|Ethereal Iceblight|60|50
DamageSpell2=gem|Wildmagic Blast|70|20
DamageSpell3=gem|Flarelure|80|20
DamageSpell4=gem|Voidfrost Lure|90|20

Resulted in gem4, gem3, gem2, gem1, gem3. This is much closer to the result I was expecting with the first list.


The order in which you list the spells matters as much as the HPs you enter to start using them. Always list the lowest HPs (most restricted) spells first so they are evaluated for casting each time.

This is probable going to be true for healing spells too, I haven't even tried to check that.
 
Last edited:
There is a lot going on in the background. First you do not have to list them in order by HP. Kiss sorts the DPS array using HPs level tag, in descending order(100 ==> 1). When in the DPS casting routine kiss will cast any entry in the DPS array, but it does not check if the spell is ready before calling the CastWhat routine, and when returning from casting, never checks to see if it returned because the spell/aa was not ready.

Listed below is the CombatCast routine I have highlighted, in red, the section that calls the cast routine, and in green, is the return checking.

Bottom line the routine does not wait around to cast every DPS spell, it will only cast what it can at that point in time and leave. Then the next time it is called it starts over from the top of the DPS list.

If I had to guess why only your first 2 spells are getting cast, is because the first 2 are not on the same timer, and the other spells are on the same timers as your spell 1 and 2.

It would not take much to change the way this works based on DPSOn being set to 1 or 2, but I don't have the time at the moment to change the code and test it before posting it here.

Happy Valentines Day Everyone.

Rich (BB code):
    Sub CombatCast
        /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast Enter
        /declare i int local 0
        /declare DPSText string local
        /declare DPSAt int local ${AssistAt}
        /declare DPSTargetID int local ${MyTargetID}
        /declare DPSItem string local
        /for i 1 to ${DPS.Size}       
            /doevents
            /call CombatTargetCheck
            /if (${Spawn[${MyTargetID}].Type.Equal[Corpse]} || !${Spawn[${MyTargetID}].ID}) {
                /if (${DebugCombat}) /echo CombatCast: Return from CombatCast cause my target is a corpse or dead.
                /return
            }
            /if (${DPSPaused}) {
                /if (${DebugCombat}) /echo CombatCast: Return from CombatCast cause DPSPaused is ${DPSPaused}
                /return
            }
            /call WriteDebuffs
            |--- only call code for GroupEscape kick off.
            /if (${GroupEscapeOn} && ${Select[${Me.Class.ShortName},WIZ,DRU]} && (${Raid.Members}==0)) /call GroupEscape
            /if (${MezOn}) /call DoMezStuff
            /if (${HealsOn}) /call CheckHealth
            /if (${CuresOn}) /call CheckCures
            /varset DebugTimer2 600
            /if (${DebuffOn}) /call DoDebuffStuff ${MyTargetID}
            /if (${DebugCombat}) /echo Time Spent in DoDebuffStuff 2 : ${Math.Calc[(600-${DebugTimer2})/10]}
            /if (${Spawn[${MyTargetID}].Type.Equal[Corpse]}) /return
            /if (${Target.Mezzed.ID} && ${MainAssist.NotEqual[${Me}]} && ${Spell[${DPS[${i}].Arg[1,|]}].Category.NotEqual[Utility Detrimental]}) {
                /if (${DebugCombat}) /echo Skipping spell in CombatCast because target is mezzed and I.m not mainassist and it will wake up the mob.
                /goto :skipcast
            }
            /if (!${DPS[${i}].Length}) {
                /if (${DebugCombat}) CombatCast: /echo im skipping in CombatCast cause there is no spell: DPS${i} 
                /goto :skipcast    
            }
            /if (${MercOn} && !${MercAssisting} && ${MyTargetID} && ${Mercenary.State.Equal[Active]}) /call MercsDoWhat
            /if (${AEOn}) /call AECheck
            /if (${AggroOn}) /call AggroCheck
            /if (${PetOn} && ${PetCombatOn}) /call CombatPet
            /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast ${DPS[${i}]} ${DPS[${i}].Arg[1,|]} ${DPS[${i}].Arg[2,|]} ${DPS[${i}].Arg[3,|]}
            | - Check for 2nd value in dps for mob health
            /if (${DPS[${i}].Arg[2,|].Length}) {
                /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast /echo ${DPS[${i}]}
                /varset DPSText ${DPS[${i}]}
                /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast /echo ${DPSText}
                /varset DPS[${i}] ${DPSText.Arg[1,|]}
                /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast /echo ${DPS[${i}]}
                /varset DPSAt ${DPSText.Arg[2,|]}
                /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast /echo ${DPSAt}
                /if (${DPSText.Arg[3,|].Find[MA]}) /varset DPSTargetID ${Spawn[=${MainAssist}].ID}
                /if (${DPSText.Arg[3,|].Find[Me]} || ${DPSText.Arg[3,|].Find[Feign]}) /varset DPSTargetID ${Me.ID}
            }
            /if (${Me.Class.Name.Equal[Cleric]} && ${DPS[${i}].Find[Hammer]} && ${Me.Pet.ID}) /goto :skipcast
            /if (${Me.Class.Name.Equal[Wizard]} && ${Me.Pet.ID} && (${DPS[${i}].Find[sword]} || ${DPS[${i}].Find[blade]})) /goto :skipcast
            /if (${Spawn[${DPSTargetID}].PctHPs}<${DPSSkip} || ${DPS[${i}].Equal[NULL]} || ${ABTimer${i}} || ${DPSTimer${i}} || ${FDTimer${i}} || (!${Select[${EverQuest.Server},zek]} && ${Spawn[${DPSTargetID}].Type.NotEqual[NPC]} && ${Spawn[${DPSTargetID}].Master.Type.NotEqual[NPC]})) /goto :skipcast
           /if (${MainAssist.Equal[${Me}]} && ${DPSOn}==1) /varset DPSOn 2
           /if (${Spawn[${DPSTargetID}].PctHPs}>${DPSAt} && ${DPSOn}==1) /goto :skipcast
                /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast Spell: ${DPS[${i}]} Target: ${DPSTargetID}=${Target.ID} Timer: ${DPSTimer${i}} DPSOn: ${DPSOn}
                /if (${Select[${DPSText.Arg[3,|]},Me,MA]} && ${Me.Combat} && ${MainAssist.NotEqual[${Me}]}) {
                    /attack off
                    /delay 10 !${Me.Combat}
                }
                | Only cast spells with weave tag during global cooldown
                /if (${DPSText.Arg[3,|].Find[weave]} && !${IAmABard} && !${Me.SpellReady[${castWhat}]} && !${Me.SpellReady[${Me.Gem[1].Name}]} && !${Me.SpellReady[${Me.Gem[3].Name}]} && !${Me.SpellReady[${Me.Gem[5].Name}]} && !${Me.SpellReady[${Me.Gem[7].Name}]}) {
                    /call CastWhat "${DPS[${i}]}" ${DPSTargetID} DPS
                } else  /if (${DPSText.Arg[3,|].Find[weave]}) {
                    /goto :skipcast
                } else {
                    /call CastWhat "${DPS[${i}]}" ${DPSTargetID} DPS
                } 
                    /if (${Macro.Return.Equal[CAST_RESIST]}) {
                        /echo ** ${DPS[${i}]} on >> ${Spawn[${DPSTargetID}].CleanName} << - RESISTED
                        /if (${DPSText.Arg[3,|].Length} && ${DPSText.Arg[3,|].Find[once]}) {
                            /varset DPSTimer${i} 5m
                            /goto :skipcast
                        }
                    }
                    /if (${Macro.Return.Equal[CAST_TAKEHOLD]}) {
                        /echo ** ${DPS[${i}]} on >> ${Spawn[${DPSTargetID}].CleanName} << - DID NOT TAKE HOLD
                        /varset DPSTimer${i} 5m
                        /goto :skipcast
                    }
                    /if (${Macro.Return.Equal[CAST_SUCCESS]}) {
                        /echo ** ${DPS[${i}]} on >> ${Spawn[${DPSTargetID}].CleanName} <<
                    | Set timer for spells labeled once 5m
                    /if (${DPSText.Arg[3,|].Length} && ${DPSText.Arg[3,|].Find[once]}) {
                        /varset DPSTimer${i} 5m
                        /goto :skipcast
                    | Timers for items    
                    } else /if (${FindItemCount[=${DPS[${i}]}]}) {
                        /varcalc DPSTimer${i} ${FindItem[=${DPS[${i}]}].Spell.Duration.TotalSeconds}*10
                        /goto :skipcast
                    | FD to lose aggro
                    } else /if (${Select[${Me.Class.ShortName},MNK,NEC,SHD]} && ${DPSText.Arg[3,|].Find[Feign]}) {
                        /delay 30 ${Me.State.Equal[FEIGN]}
                        /varset FDTimer${i} 60s
                        /delay 10s ${Me.State.NotEqual[FEIGN]}
                        /if (${Me.State.Equal[FEIGN]} && !${Me.Sitting}) /stand
                    | Timers for spells
                    } else /if (${Me.Book[${DPS[${i}]}]}) {
                        | - Attack Buff Timers are seperate. DPS timers are cleared after every fight.
                        /if (${Select[${DPSTargetID},${Me.ID},${Spawn[=${MainAssist}].ID}]}) {
                            /varcalc ABTimer${i} (${Spell[${DPS[${i}]}].Duration.TotalSeconds}*${DurationMod})*10
                            /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast Spell: ${DPS[${i}]} Timer: ABTimer${i} {ABTimer${i}}
                            /goto :skipcast
                        | - Custom timer for counterbias
                        } else /if (${Me.Class.Name.Equal[Shaman]} && ${DPS[${i}].Find[counterbias]}) {
                            /varset DPSTimer${i} 1.5m
                            /goto :skipcast
                        | Custom timer for Chanter suffocation
                        } else /if (${Me.Class.Name.Equal[enchanter]} && ${DPS[${i}].Find[suffocation]}) {
                            /varset DPSTimer${i} 1m
                            /goto :skipcast
                        | Custom timer for Beastlord Feralgia Timer
                        } else /if (${Me.Class.Name.Equal[Beastlord]} && ${DPS[${i}].Find[feralgia]}) {
                            /varset DPSTimer${i} 1.5m
                            /goto :skipcast
                        | Regular spells
                        } else /if (${Spell[${DPS[${i}]}].Duration}>0) {
                            /varcalc DPSTimer${i} ${Spell[${DPS[${i}]}].Duration.TotalSeconds}*10
                            /goto :skipcast
                        | Spells with no timers assign DPS interval
                        } else {
                            /varset DPSTimer${i} ${DPSInterval}s
                            /goto :skipcast
                        }
                    | AA and disc timers
                    } else /if (${Spell[${DPS[${i}]}].Duration}>0) {
                        /varcalc DPSTimer${i} ${Spell[${DPS[${i}]}].Duration.TotalSeconds}*10
                        /goto :skipcast
                    | AA and disc with no timers assign DPS interval
                    } else {
                        /varset DPSTimer${i} ${DPSInterval}s
                        /goto :skipcast
                    }
                }
            :skipcast
            /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast ${DPS[${i}]} ${Macro.Return} DPSTimer${i} ${DPSTimer${i}}
            /if (${Select[${DPSText.Arg[3,|]},Me,MA]}) /call CombatTargetCheck
            | Reset values if 2nd value in dps for mob health exists
            /if (${DPSText.Arg[2,|].Length}) {
                /varset DPS[${i}] ${DPSText}
                /varset DPSAt ${AssistAt}
                /varset DPSText
                /varset DPSTargetID ${MyTargetID}
            }
        /next i
        /if (${DebugCombat}) /echo DEBUGCOMBAT CombatCast: Leave
    /return
 
I'm not sure I completely understand what ctaylor22 is saying, but it sounds like kissassist sorts the dps spells and it won't matter what order you list them. This renders my original post false.

Just to clarify a bit:

The behavior was the result of a custom macro that I wrote for my use. Because of the way I coded the damage spell casting routines the order does make a difference.
It checks each spell in order 1-8 to determine if conditions are approved for that spell to be cast. Conditions are: mobs HPs, range, mana cost<available mana and spell/ability is ready to be cast.
It was casting spell1, spell2, spell1, spell2... because the conditions were approved. By listing the spell with the most restricted conditions first I made sure that it was always evaluated and would be cast when the conditions were approved.

I still think this behavior could/would be reproduced in a large number of macros, possible even kissassist. I am not familiar enough with the coding in kissassist to hazard more than a guess at the possibility.
 
He is talking about his own macro. Kiss cast the spells in the order you tell to. You can tell to cast according to mob health or in a specific order depending on DPSOn=1 or DPSOn=2
Once again what he is discussing has nothing to do with Kiss

We would have to see you code that handles you casting to trouble shoot this issue,
 
We would have to see you code that handles you casting to trouble shoot this issue,

It's not really an issue, but more of an observation I thought others might find useful.

I'll include me casting sub because you almost asked:

Rich (BB code):
|---------------------------------------------------------------------------------------------------------------
Sub DamageCasting
|---------------------------------------------------------------------------------------------------------------
|Format = alt/item/gem|spellname|start HPs|stop HPs

/if (${debugsubtime}) /varset StartTime ${Macro.RunTime}
	
/declare casttype 	string 	local
/declare spellname 	string 	local
/declare maxhp 		int 	local
/declare minhp		int		local
/declare dt			int		local
/declare whatrange	int		local
/declare whatmana	int		local
/declare LoM		int		local 0

	/for tc 1 to 8

	/varset casttype ${DamageSpell[${tc}].Arg[1,|]}
	/varset spellname ${DamageSpell[${tc}].Arg[2,|]}
	/varset maxhp ${DamageSpell[${tc}].Arg[3,|]}
	/varset minhp ${DamageSpell[${tc}].Arg[4,|]}
	/varset dt ${DamageTarget}

	/if (${Select[${DamageSpell[${tc}].Arg[1,|]},gem,alt]}) {
		/varset whatrange ${Spell[${DamageSpell[${tc}].Arg[2,|]}].MyRange}
		/varset whatmana ${Spell[${DamageSpell[${tc}].Arg[2,|]}].Mana}
	} else {
		/varset whatrange ${Spell[${FindItem[${DamageSpell[${tc}].Arg[2,|]}].Spell}].MyRange}
		/varset whatmana ${Spell[${FindItem[${DamageSpell[${tc}].Arg[2,|]}].Spell}].Mana}
	}

	/if (${HealOn} && ${Me.PctMana}<${MedAt}) {
		/varset LoM 1
		/if (!${LoMTimer}) /gsay I'm low mana, no damage spells for while
		/varset LoMTimer ${Math.Calc[${Math.Rand[20]}+20]}s
	}

	/if (${DamageTimer${tc}} || ${DamageSpell[${tc}].Equal[0]} || !${Cast.Ready[${spellname}|${casttype}]}) {
		/next tc
		/varset DamageCastTimer ${DamageSpellDelay}s
		/return
	}

	/if (${LoM} && ${casttype.Equal[gem]}) {
		/next tc
		/varset DamageCastTimer ${Math.Calc[${DamageSpellDelay}+10]}s
		/return
	}

	/if (${Spawn[${dt}].PctHPs}<${maxhp} && ${Spawn[${dt}].PctHPs}>${minhp} && ${Spawn[${dt}].Distance}<${whatrange} && ${whatmana}<${Me.CurrentMana}) {
		/if (${casttype.Equal[gem]} && !${LoM}) /casting "${spellname}" ${casttype}${DamageSpellGem} -targetid|${dt} -invis
		/if (${casttype.Equal[alt]} && ${Cast.Ready[${spellname}|alt]}) /casting "${spellname}" ${casttype} -targetid|${dt} -invis
		/if (${casttype.Equal[item]} && ${Cast.Ready[${spellname}|item]}) /casting "${spellname}" ${casttype} -targetid|${dt} -invis
		/call castdelay CAspell ${Macro.CurLine} damage
		/if (${Cast.Result.Equal[CAST_SUCCESS]}||${Cast.Result.Equal[CAST_TAKEHOLD]}) {
			/varset DamageTimer${tc} ${Spell[${spellname}].Duration.TotalSeconds}s
			/if (${Math.Calc[${DamageTimer${tc}}/10]}<${DamageSpellDelay}) /varset DamageTimer${tc} ${Math.Calc[${DamageSpellDelay}+${Spell[${spellname}].RecastTime}]}s
			/if (${spellname.Equal[Mending Counterbias]}) /varset DamageTimer${tc} 30s
			/if (${debugdamage}) /echo CAspell ${Macro.CurLine} - DamageTimer${tc} set to ${Math.Calc[${DamageTimer${tc}}/10]} seconds for spell ${spellname}
		}
	}
	/next tc
	/varset DamageCastTimer ${DamageSpellDelay}s

	/if (${debugsubtime}) {
		/varset EndTime ${Macro.RunTime}
		/echo CAspell ${Macro.CurLine} - damage casting complete, elasped time = ${Math.Calc[${EndTime}-${StartTime}]} seconds
	}
	
/return
 
Guide - what order do you enter your dps spells

Users who are viewing this thread

Back
Top
Cart