• 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

Fork / Mod Optimzations for Healers (Mostly)

TheNomadMan

New member
Joined
Feb 8, 2014
RedCents
451¢
So; I finally got some time to put in a few changes to heals.

-Heal Loop: The current heal loop does not loop back to the top after each successful heal cast. Instead, it continues on down the heal logic and then restarts from the bottom. IMO this defeats the purpose. In order to make a good logic based "decision" on the next heal, it must start at the top after each successful heal.

-Group Heal: The current Group Heal logic is based solely on the group average. While this metric is necessary, it's also insufficient for deciding if a group heal is required. So; I put in a system to determine the number of people currently in need of a heal. This way; if only one person needs a heal, only single heals will fire. This could easily be turned in to a ini setting if for some reason single target group healing, or a higher threshold, is desired.

-Heal Order: With the group heal no longer firing on single targets, moving the group heal to the front of the line becomes an option. And; one that I find to be very effective and efficient.

-XTarget Healing: Currently only one XTarget Heal-Target is allowed, the slot must be specified in the ini, and this does not work for NPC's. On raids we need a lot more than one Xtarget slot, we need to be able to switch slots on-the-fly, we need it to work for pet tanks and/or protected NPCs and we need it to be snappy. So; I've rigged up exactly that. if Xtarget healing is on; the ${AggroTargetID} now swiches on-the-fly, any player/npc/pet can be added to (or removed from) any xtarget slot at any time without restarting the macro or messing up the DPS targeting, and the hard delays have been pulled out.

-Healing tags: In an attempt to have the smartest healer out there, I had been adding new tags (Mob, XT, Me, etc). Eventually my heal spell array was 25 deep with three entries for everything, defined different ways. So; I ended up reflowing the heal section in such a manner that everything I was trying to do with all these tags is just part of the normal heal logic and all the tags could be dropped. Now I have a single entry for all heal spells, no tags, and it's all much simpler to setup and run with. All such tags are still valid if one wishes to over-ride the built-in logic. But after seeing this tag-less system in action, we haven't found a call to tag anything; yet.

-Rezzing: All healers have at least two options for rezzing. A "call" for +mana or a "rez" for +xp. In the case of shammies/druids this isn't so much of an option as a requirement, use call in combat, rez after. Added an option to define your Battle Rez spell and OOC rez spell seprate like. I will be adding a "do not rez if player is already in zone" option, soon, too. Because it sucks having rebuffed and run back only to have auto-rez start ya over.

-DPS/Buffs Interrupt- I like my healers to have some utility to them, and to use spells other than healing spells to keep the group in good shape (DI, twin-heal nukes, stuns, etc.). But I'm unwilling to allow them to cast these spells at the cost of a group member going down. So, yeah; being able to monitor the health of at least Self and MA, if not the entire group, and duck-out of a DPS or Buff in order to cast a heal is a must IMO. This requires going back to MQ2Cast and using while loops. The aforementioned whiles are based on advice garnered here.

-Mana Buffs, in combat: These were eating up more time than I felt the bot could afford to use on them, but at the same time the bot needs mana now and then. Pulled out the delays and smoothed the transition back in to the heal loop.

-Breaking Invis: I often run from place to place with my boxes in-tow. When doing so; I want them to support me if I get in to a fight, but I do not want them breaking invis and starting a fight. Added a condition to CastWhat that prevents casting if invis and is no mob exists on Xtarget.

-That's all that I remember off top my head, at the moment. I'll attach a functional example called "RaidAssist", at the bottom. Now, on to the code:

Rich (BB code):
| ************************* Heals ***************************************|
    /call LoadIni Heals Help                    string      "Format Spell|% to heal at i.e. Devout Light Rk. II|50"
    /call LoadIni Heals HealsOn                 int         0
    /if (${Select[${Me.Class.ShortName},CLR,SHM,DRU,PAL,ENC]})  {
        /declare Heals[20]                      string      outer
    } else {
        /declare Heals[5]                       string      outer
    }
    /call LoadIni Heals Heals                   string      NULL        Heals
    /call LoadIni Heals XTarHeal                int         0
    /call LoadIni Heals InterruptHP             int         "At What HP% for Me/MA to abort casting and heal. 0=OFF"
    /if (${Select[${Me.Class.ShortName},CLR,NEC,SHM,DRU,PAL]}) {
        /call LoadIni Heals AutoRezOn           int         0
        /call LoadIni Heals AutoRezWith         string      "Your Battle Rez Item/AA/Spell"
	/call LoadIni Heals OOCRezWith          string      "Your OOC Rez Item/AA/Spell"
    }
| ************************* Cures ***************************************|

Rich (BB code):
	/declare TaskGiver 				string 		outer
	/declare HealAgain				int         outer       0
	/declare ManyHurt               int         outer       0
    
    | Set AA DurationMod for various timer from Spell Casting Reinforcement AA
    /if (${Me.AltAbility[Spell Casting Reinforcement]}==6)     /varset DurationMod 1.15

Rich (BB code):
| ----------------------------------------------------------------------------
| SUB: CheckHealth
| ----------------------------------------------------------------------------
    Sub CheckHealth
        /if (!${HealsOn}) /return
        /if (${DebugHeal}) /echo Sub CheckHealth enter
		/declare x                  int         local       1
		/declare i                  int         local       0
		/declare j                  int         local       1
		/declare NewHaters          int         local       0
        /declare MostHurtName       string      local
        /declare MostHurtType       string      local
        /declare MostHurtID         int         local       0
        /declare MostHurtHP         int         local       100
        /declare MostHurtNo         int         local       0
        /declare GroupHealthAvg     string      local       0
		:CheckAgain
		/varset MostHurtName
		/varset MostHurtType
		/varset MostHurtID
		/varset MostHurtHP 100
		/varset MostHurtNo	0
		/varset HealAgain	0
		/varset GroupHealthAvg 0
		| Group Heal Check only call for those clases that can group heal
        /if (${Select[${Me.Class.ShortName},BST,CLR,SHM,DRU,PAL,ENC]}) {
            /call GroupHealthCheck
            /varset GroupHealthAvg ${Macro.Return}
            /if (${DebugHeal}) /echo Group Health Average ${GroupHealthAvg}
            | Check for group heals
            /if (${GroupHealthAvg} < 100 && ${Group} && ${ManyHurt}>1) {
				/call DoGrouopHealStuff ${GroupHealthAvg}
				/if (${HealAgain}) {
					/delay 5
					/goto :CheckAgain
				}
			}
        }
        | Check self health
        /if (${Me.PctHPs} < 100) {
			/call SingleHeal "${Me}" PC ${Me.PctHPs} 0
			/if (${HealAgain}) {
				/delay 5
				/goto :CheckAgain
			}
		}
        | Call group health check for only those that can heal others
        /if (${Select[${Me.Class.ShortName},BST,CLR,SHM,DRU,RNG,PAL,ENC]}) {
            | This is to target Main Assist out of group if class can heal
            /if (${Select[${HealsOn},1,3]} && !${Spawn[${MainAssist} ${MainAssistType} group].ID} && ${Spawn[${MainAssist} ${MainAssistType}].ID} && ${Spawn[${MainAssist} ${MainAssistType}].Type.NotEqual[corpse]} && ${Spawn[${MainAssist}].ID}!=${Me.Pet.ID} && ${Spawn[${MainAssist}].ID}!=${Me.ID}) {
               | Skip targeting tank if MA is defined to watch for heals in XTarget
               | /if (!${XTarHeal} || ${XTarHeal} && ${Me.XTarget[${XTarHeal}].ID}!=${Spawn[${MainAssist} ${MainAssistType}].ID}) {
               |     /target id ${Spawn[${MainAssist} ${MainAssistType}].ID}
               |     /delay 5
               | }
                /if (${DebugHeal}) /echo Tank OOG: ${Spawn[${MainAssist}].PctHPs} ${Spawn[${MainAssist} ${MainAssistType}].ID}  ${Spawn[${MainAssist} ${MainAssistType}].Type.NotEqual[corpse]}
                /if (${Spawn[${MainAssist} ${MainAssistType}].PctHPs} < 100) {
					/call SingleHeal "${MainAssist}" "${MainAssistType}" ${Spawn[${MainAssist} ${MainAssistType}].PctHPs} 6
					/if (${HealAgain}) {
						/delay 5
						/goto :CheckAgain
					}
				}
            } else {
                /if (${Select[${HealsOn},3]} ${Spawn[${MainAssist} ${MainAssistType}].PctHPs} < 100) /call SingleHeal "${MainAssist}" "${MainAssistType}" ${Spawn[${MainAssist} ${MainAssistType}].PctHPs} 6
				/if (${HealAgain}) {
					/delay 5
					/goto :CheckAgain
				}
            }
           | Who is the most hurt
            /if (${Select[${HealsOn},1,2]} && ${Group} && !${JustZoned} && !${JoinedParty}) {
                /for i 0 to ${Group}
                    /if (${Group.Member[${i}].ID}==${Spawn[${MainAssist} ${MainAssistType}].ID}) /goto :NextGMember
                    /if (${Group} && ${Group.Member[${i}].ID} && ${Group.Member[${i}].Type.NotEqual[corpse]} && ${Group.Member[${i}].PctHPs}>=1) {
                    /if (${DebugHeal}) /echo -- Most Hurt:${i} ${MostHurtNo} ${MostHurtName} ${MostHurtID} ${MostHurtHP}
                        /if (${Group.Member[${i}].PctHPs} < ${MostHurtHP}) {
                            /varset MostHurtName ${Group.Member[${i}].CleanName}
                            /varset MostHurtType ${Group.Member[${i}].Type}
                            /varset MostHurtID ${Group.Member[${i}].ID}
                            /varset MostHurtHP ${Group.Member[${i}].PctHPs}
                            /varset MostHurtNo ${i}
                        }
                    }
                :NextGMember
                /next i
                /if (${MostHurtHP} < 100) {
					/call SingleHeal "${MostHurtName}" "${MostHurtType}" ${MostHurtHP} ${MostHurtNo}
					/if (${HealAgain}) {
						/delay 5
						/goto :CheckAgain
					}
				}
            }
        }
		| Check xtarget health if on.
		/if (${XTarHeal}) {
			/varset NewHaters 0
			/for j 1 to ${XSlotTotal}
			/if (${NewHaters}==0 && ${Me.XTarget[${j}].TargetType.Equal[Auto Hater]}) {
				/varcalc NewHaters ${NewHaters}+1
				/varset XTSlot ${j}
			}
			/next j            
			/for x 1 to ${XSlotTotal}
            /if (${Select[${Spawn[${Me.XTarget[${x}].ID}].Type},PC,NPC,Pet]} && ${Me.XTarget[${x}].ID} && ${Spawn[${Me.XTarget[${x}].ID}].PctHPs}<100) {
                /call SingleHeal "${Spawn[${Me.XTarget[${x}].ID}]}" "${Spawn[${Me.XTarget[${x}].ID}].Type}" ${Spawn[${Me.XTarget[${x}].ID}].PctHPs} 7
                /if (${DebugHeal}) /echo Sub CheckHealth XtargetHeal "${Spawn[${Me.XTarget[${x}].ID}].CleanName}" "${Spawn[${Me.XTarget[${x}].ID}].Type}" ${Spawn[${Me.XTarget[${x}].ID}].PctHPs} 7
				/if (${HealAgain}) {
					/delay 5
					/goto :CheckAgain
				}
            }
			/next x
        }
        /if (${AutoRezOn}) /call RezCheck
        /if (${PetOn} && ${Me.Pet.ID} && ${Me.Pet.PctHPs} < 100) /call DoPetHealStuff
        /if (${DebugHeal}) /echo Sub CheckHealth leave
		/if (${HealAgain}) {
			/delay 5
			/goto :CheckAgain
		}
    /return	
	
|----------------------------------------------------------------------------

Rich (BB code):
| ----------------------------------------------------------------------------
| SUB: Group Health Check
| ----------------------------------------------------------------------------
    Sub GroupHealthCheck
        /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS GroupHealthCheck Enter
        /declare j                  int     local   0
        /declare GroupHealthTl      float   local   .1
        /declare GroupHealthPct     float   local   0
        /declare NotDead            int     local   0
	/varset  ManyHurt 0
        /for j 0 to ${Group}
            /if (${Group} && ${Group.Member[${j}].ID} && ${Group.Member[${j}].Type.NotEqual[corpse]}) {
                | Calculate total group health for group heal spells
                /if (${Group.Member[${j}].Distance}<100) {
                    /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS GroupHealthCheck Group Health: GM:${j} Health:${Group.Member[${j}].PctHPs}
                    /varcalc GroupHealthTl ${GroupHealthTl}+${Group.Member[${j}].PctHPs}
                    /varcalc NotDead ${NotDead}+1
                    /varcalc GroupHealthPct ${GroupHealthTl}/${NotDead}
		    /if (${Group.Member[${j}].PctHPs}<100) /varcalc ManyHurt ${ManyHurt}+1
                }
            }
        /next j
            /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS GroupHealthCheck Leave ${GroupHealthPct}
    /return ${GroupHealthPct}
| ----------------------------------------------------------------------------

Rich (BB code):
|----------------------------------------------------------------------------
| SUB: Single Heals
|----------------------------------------------------------------------------
    Sub SingleHeal(SHealName, SHealType, int SHealHPs, int WhoNum)
        /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal !${HealsOn} || ${Me.Moving} || ${Window[RespawnWnd]} || !${Spawn[${SHealName} ${SHealType}].ID} || !${Select[${SHealType},PC,Pet,Mercenary]} 
        /if (!${HealsOn} || ${Me.Moving} || ${Window[RespawnWnd]} || !${Spawn[${SHealName} ${SHealType}].ID} || !${Select[${SHealType},PC,Pet,Mercenary]}) /return
        /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal ${SHealName} ${SHealType} ${SHealHPs} ${WhoNum}
        /doevents
        /declare i               int     local   0
        /declare SHealSpell      string  local
        /declare SHealPct        int     local
        /declare SHealTag        string  local
        /declare SHealThem       int     local   ${Spawn[${SHealName} ${SHealType}].ID}
        /declare MainAssistID    int     local   ${Spawn[=${MainAssist}].ID}
        /declare SHealRange      int     local   0
        | Set MA Id to 6 to keep spell durations correct
        /if (${WhoNum}!=6 && ${SHealThem}==${MainAssistID}) /varset WhoNum 6
        /for i 1 to ${SingleHeal.Size}
            | If heal is null or off |0 or spell/aa/item not ready skip it
            /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal Spell ${i}: ${SingleHeal[${i}]}  ${SingleHeal[${i}].Arg[1,|]}   ${SingleHeal[${i}].Arg[2,|]}   ${SingleHeal[${i}].Arg[3,|]}
            /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal SpellSkip: !${SingleHeal[${i}].Length} || ${SingleHeal[${i}].Arg[2,|].Equal[0]}}
            /if (!${SingleHeal[${i}].Length} || ${SingleHeal[${i}].Arg[2,|].Equal[0]}) /goto :SNextHeal
			/if ((!${IAmABard} && !${Cast.Ready[${SingleHeal[${i}]}]}) && (${Me.SpellReady[${Me.Gem[1].Name}]} || ${Me.SpellReady[${Me.Gem[2].Name}]} || ${Me.SpellReady[${Me.Gem[3].Name}]} || ${Me.SpellReady[${Me.Gem[4].Name}]} || ${Me.SpellReady[${Me.Gem[5].Name}]} || ${Me.SpellReady[${Me.Gem[6].Name}]} || ${Me.SpellReady[${Me.Gem[7].Name}]} || ${Me.SpellReady[${Me.Gem[8].Name}]})) /goto :SNextHeal
            /varset SHealSpell   ${SingleHeal[${i}].Arg[1,|]}
            /varset SHealPct     ${SingleHeal[${i}].Arg[2,|]}
            /varset SHealTag     ${SingleHeal[${i}].Arg[3,|]}
            /varset SHealRange ${Spell[${SHealSpell}].Range}
            /if (${Spell[SHealSpell].TargetType.Find[Group]})  /varset SHealRange ${Spell[${SHealSpell}].AERange}
            /if (!${SHealRange}) /varset SHealRange 100
			| Check Heal Tags and skip as needed. 
            /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal TAG: ${SHealTag.Equal[MA]} && ${SHealThem}!=${MainAssistID} || ${SHealTag.Equal[!MA]} && ${SHealThem}==${MainAssistID}
			/if (${SHealTag.Equal[pet]}) /goto :SNextHeal
			/if (${SHealTag.Equal[Me]}  && ${SHealThem}!=${Me.ID}) /goto :SNextHeal
			/if (${SHealTag.Equal[!MA]} && ${SHealThem}==${MainAssistID}) /goto :SNextHeal
			/if (${SHealTag.Equal[Mob]} && ${SHealThem}!=${MainAssistID}) /goto :SNextHeal
			/if (${SHealTag.Equal[MA]}  && ${SHealThem}!=${MainAssistID})  /goto :SNextHeal
			/if (${SHealTag.Equal[XT]}  && ${SHealThem}!=${Me.XTarget[1].ID} && ${SHealThem}!=${Me.XTarget[2].ID} && ${SHealThem}!=${Me.XTarget[3].ID} && ${SHealThem}!=${Me.XTarget[4].ID} && ${SHealThem}!=${Me.XTarget[5].ID} && ${SHealThem}!=${Me.XTarget[6].ID} && ${SHealThem}!=${Me.XTarget[7].ID} && ${SHealThem}!=${Me.XTarget[8].ID}) /goto :SNextHeal
            | Cleric Divine Arbitration and Epics do not work on pets
            /if ((${Spawn[${SHealThem}].Type.Equal[Pet]} || !${Spawn[${SHealName} ${SHealType} group].ID}) && (${HealSpell.Find[Aegis of Superior Divinity]} || ${HealSpell.Find[Harmony of the Soul]} ||  ${HealSpell.Find[Divine Arbitration]})) /goto :SNextHeal
            | Check For Life Taps
            /if (${SHealTag.Find[Tap]}) {
                /if (!${Pulled} && ${CombatStart} && ${Me.PctHPs}<=${SHealPct} && ${Spawn[${MyTargetID}].ID} && ${Spawn[${MyTargetID}].Distance}<=${SHealRange} && ${Spell${i}GM0}==0) {
                    /call CastWhat "${SHealSpell}" ${Spawn[${MyTargetID}].ID} Heal
                    /if (${Macro.Return.Equal[CAST_SUCCESS]}) {
                        /call BroadCast ${IRCOn} ${EQBCOn} o "${SHealSpell} for  >> ${Me.CleanName} <<"
                        /varcalc Spell${i}GM0 (${Spell[${SHealSpell}].Duration.TotalSeconds}*${DurationMod})*10
                        /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal Assign Timer:Spell${i}GM0 (${Spell[${SHealSpell}].Duration.TotalSeconds}*${DurationMod}) ${Spell${i}GM0}
						/varset HealAgain	1
                        /return
                    }
                } else {
                    /goto :SNextHeal
                }
            }
			| Check For Nuke Heals
            /if (${SHealTag.Find[Mob]}) {
				/if (!${AggroTargetID}) /goto :SNextHeal
				/doevents Switch
				/if (!${MyTargetID} || ${Spawn[${MyTargetID}].Type.Equal[Corpse]}) /call Assist Heals
                /if (${MyTargetID} && ${Spawn[${MainAssist}].PctHPs}<=${SHealPct} && ${Spawn[${MyTargetID}].LineOfSight} && ${Spawn[${MyTargetID}].Distance}<=${SHealRange} && !${Spawn[${MyTargetID}].Type.Equal[Corpse]}) {
                    /call CastWhat "${SHealSpell}" ${Spawn[${MyTargetID}].ID} Heal
                    /if (${Macro.Return.Equal[CAST_SUCCESS]}) {
                        /call BroadCast ${IRCOn} ${EQBCOn} o "${SHealSpell} for ${SHealThem} >> Heal Nuke << aginst ${Spawn[${MyTargetID}]} "
						/varset HealAgain	1
                        /return
                    }
                } else {
                    /goto :SNextHeal
                }
            }
            | Check conditons for heals
            /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal ${SHealHPs}<=${SHealPct} && ${Spawn[${SHealName} ${SHealType}].Distance}<=${SHealRange} && ${Spell${i}GM${WhoNum}}==0
            /if (${SHealHPs}<=${SHealPct} && ${Spawn[${SHealName} ${SHealType}].Distance}<=${SHealRange} && ${Spell${i}GM${WhoNum}}==0) {
                /if (${Select[${EverQuest.Server},zek]} && ${Select[${Target.Type},PC]} && ${Me.Combat}) {
                    /attack off
                    /delay 25 !${Me.Combat}
                }
                /call CastWhat "${SHealSpell}" ${SHealThem} Heal
                /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal MR: ${Macro.Return}
                /if (${Macro.Return.Equal[CAST_SUCCESS]}) {
                    /call BroadCast ${IRCOn} ${EQBCOn} o "${SHealSpell} on  >> ${Spawn[${SHealName} ${SHealType}].CleanName} <<"
                    /varcalc Spell${i}GM${WhoNum} (${Spell[${SHealSpell}].Duration.TotalSeconds}*${DurationMod})*10
                    /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal Assign Timer:Spell${i}GM${WhoNum} ${Spell[${SHealSpell}].Duration.TotalSeconds}*${DurationMod} ${Spell${i}GM${WhoNum}}
					/varset HealAgain	1
                    /return
                }
            }
        :SNextHeal
        /next i
        /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS SingleHeal Leave
    /return

Rich (BB code):
| Wait for global cooldown active
            :Waitforcooldown
            /if (!${IAmABard} && !${Cast.Ready[${castWhat}]} && !${Me.SpellReady[${Me.Gem[1].Name}]} && !${Me.SpellReady[${Me.Gem[2].Name}]} && !${Me.SpellReady[${Me.Gem[3].Name}]} && !${Me.SpellReady[${Me.Gem[4].Name}]} && !${Me.SpellReady[${Me.Gem[5].Name}]} && !${Me.SpellReady[${Me.Gem[6].Name}]} && !${Me.SpellReady[${Me.Gem[7].Name}]} && !${Me.SpellReady[${Me.Gem[8].Name}]}) {
                /delay 1
                /goto :Waitforcooldown     
            }
            /if (${Cast.Ready[${castWhat}]} && !${IAmABard}) {
                /casting "${castWhat}"
			|Monitor MA/Me HP While Casting. Abort if InterruptHP is hit.
				:MonitorHPWhileCasting
				/if (${sentFrom.NotEqual[Heal]} && ${sentFrom.NotEqual[Mez]} && ${HealsOn} && ${Spawn[${MainAssist} ${MainAssistType}].PctHPs}<=${InterruptHP}) {
					/docommand /stopcast
					/echo ${sentFrom} spell ${castWhat} ABORTED to cast a heal!
					/call CheckHealth
				}
				/if (${sentFrom.Equal[Heal]} && ${HealsOn} && ${${Cast.Status}.Equal[C]}) {
					/delay 1
					/goto :MonitorHPWhileCasting
				}
				:Stillcasting
				/if (${${Cast.Status}.Equal[C]}) {
					/delay 1
					/goto :Stillcasting
				}
                /varset CastResult ${Cast.Return}
				/if (${Debug}) /echo DEBUG CastWhat cast Spell result: ${Macro.Return}
                /doevents
                /call CheckCasting 50
            }
            /if (${IAmABard}) {
                /squelch /twist once ${Me.Gem[${castWhat}]}
                /varset CastResult CAST_SUCCESS
            }
        }
        /if (${WasTwisting} && !${Twist}) /squelch /twist
        /if (${Debug}) /echo  DEBUG CastWhat Leave ${CastResult}
    /return ${CastResult}

Rich (BB code):
| -------------------------------------------------------------------------------------
| SUB: Rez Check
| -------------------------------------------------------------------------------------
    Sub RezCheck
    /if (!${AutoRezOn} || ${DMZ} || ${Me.Hovering}) /return
    /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS RezCheck Enter
    /declare i int local
    /declare j int local
    /declare CorpseCount int local
    /declare RezMeID int local 
    /declare RezID int local
    /declare RezRadius int local 150
    | Does Group Member have a corpse?
    /for i 1 to ${Group}
        /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS RezCheck ${BattleRezTimer${i}}==0 && ${Spawn[${Group.Member[${i}].CleanName} corpse].Distance}<${RezRadius} ${Spawn[${Group.Member[${i}].CleanName} corpse].Deity.ID}  || !${Cast.Ready[${AutoRezWith}]}
        /if (!${Spawn[${Group.Member[${i}].CleanName} pccorpse].ID}  || !${Cast.Ready[${AutoRezWith}]}) /goto :NextChar
        | Check for group member corpses and battle rez
        /if (${BattleRezTimer${i}}==0 && ${Spawn[${Group.Member[${i}].CleanName} corpse].Distance}<${RezRadius}) {
            /squelch /tar id ${Spawn[${Group.Member[${i}].CleanName} corpse].ID}
            /delay 10 ${Target.ID}
            /if (${Target.Distance}<100) {
                /if (${Target.Distance}>${CampRadius} && !${Target.CleanName.Find[${MainAssist}]}) /corpse
                /delay 10
                /call CastWhat "${AutoRezWith}" ${Target.ID}
                /if (${Macro.Return.Equal[CAST_SUCCESS]}) {
                    /call BroadCast ${IRCOn} ${EQBCOn} o "BATTLE REZZED =>> ${Group.Member[${i}]} <<="
                    /varset BattleRezTimer${i} 3m
                } else {
                    /if (${Group.Member[${i}].Name.NotEqual[${MainAssist}]}) /varset BattleRezTimer${i} 1m
                }
            }
        }
        :NextChar
    /next i
    | Out of Combat Rez | 
    /varset CorpseCount ${SpawnCount[corpse radius ${RezRadius} zradius 50]}
    /if (${CorpseCount}>0 && !${CombatStart}) {
		| Do I have a Corpse
		/varset RezMeID ${Spawn[corpse ${Me} radius ${RezRadius} zradius 50].ID}
		/if (${RezMeID} && ${OOCRezTimer${RezMeID}}==0 && ${Cast.Ready[${OOCRezWith}]}) {
			/if (!${Defined[OOCRezTimer${RezMeID}]}) /declare OOCRezTimer${RezMeID} timer outer 1m
			/target id ${RezMeID}
			/delay 10 ${Target.ID}
			/if (${Target.Distance}>${CampRadius}) /corpse
			/delay 10
			/call  CastWhat "${OOCRezWith}" ${Target.ID}
			/if (${Macro.Return.Equal[CAST_SUCCESS]}) /varset OOCRezTimer${RezMeID} 3m
		}
        /for j 1 to ${CorpseCount}
            /varset RezID ${NearestSpawn[${j},pccorpse radius ${RezRadius} zradius 50].ID}
            /if (${Spawn[${RezID}].Type.Equal[corpse]} && ${OOCRezTimer${RezID}}==0 && ${Cast.Ready[${OOCRezWith}]} && (${Spawn[${RezID}].Guild.Equal[${Me.Guild}]} || ${Spawn[${Me.Fellowship.Member[${Spawn[${RezID}].CleanName.Left[-9]}]} pccorpse].ID} || ${XTarHeal} && ${Spawn[${RezID}].ID}==${Me.XTarget[${XTarHeal}].ID})) {
                /target id ${RezID}
                /delay 10 ${Target.ID}==${RezID}
                /if (!${Defined[OOCRezTimer${RezID}]}) /declare OOCRezTimer${RezID} timer outer 1m
                /if (${Target.Distance}<=${RezRadius}) {
                    /call  CastWhat "${OOCRezWith}" ${Target.ID}
                    /if (${Macro.Return.Equal[CAST_SUCCESS]}) {
                        /call BroadCast ${IRCOn} ${EQBCOn} o "Rezzing =>> ${Target.CleanName} <<="
                        /varset OOCRezTimer${RezID} 5m
                        /delay 30 !${Me.Casting.ID}
                    }
                }
            }
        /next j
    }
    /if (${DebugHeal} || ${DebugAll}) /echo DEBUGHEALS RezCheck Leave
/Return
| -------------------------------------------------------------------------------------

Rich (BB code):
| Check and Cast mana type spells/aas/items - Canni/Paragon/Harvest
            /if (${2ndPart.Equal[Mana]} && ${Buff${i}GM${j}}==0) {
				/if (${Me.Class.Name.Equal[Bard]} && ${Me.PctMana}<=${3rdPart}) {
					/if (${DebugBuffs}) /echo DEBUGBUFFS Bard Mana
					/call CastWhat "${1stPart}" ${Me.ID} Buffs
					/if (${Macro.Return.Equal[CAST_SUCCESS]}) {
						/echo Casting >> ${1stPart} << for mana
						/varcalc Buff${i}GM${j} (${Spell[${1stPart}].RecastTime})*10+35
					}
                    | Combat check to return - no other buffing allowed
                    /goto :SkipBuff
                }
                /if (${Me.PctMana}<=${3rdPart} && ${Me.PctHPs}>${4thPart} && ${Cast.Ready[${1stPart}]}) {
                    /if (${DebugBuffs}) /echo DEBUGBUFFS Canni/Paragon/Harvest/Bear
					| Check for stupid druid bear
					/if (${Me.Class.Name.Equal[Druid]} && ${1stPart.Find[Nurturing Growth]} && (${Me.Buff[Nurturing Growth].ID} || ${Me.Buff[Nurturing Growth RK. II].ID} || ${Me.Buff[Nurturing Growth Rk. III].ID})) /goto :SkipBuff
                    /call CastWhat "${1stPart}" ${Me.ID} Buffs
                    /if (${Macro.Return.Equal[CAST_SUCCESS]}) {
						/echo Casting >> ${1stPart} << for mana
						/varcalc Buff${i}GM${j} (${Spell[${1stPart}].Duration.TotalSeconds}*${DurationMod})*10
					}
                    | Combat check to return - no other buffing allowed
                    /goto :SkipBuff
                }
            }

Rich (BB code):
Sub CastWhat(string castWhat,int castTargetID,string sentFrom)
        /if (${Debug}) /echo  DEBUG CastWhat: Enter castWhat - ${castWhat} castTargetID - ${castTargetID}
        /declare WasTwisting bool local ${Twist}
        /varset CastResult CAST_NO_RESULT
		/if (${Me.Invis} && !${AggroTargetID}) {
			/varset CastResult CAST_IM_INVIS
			/return ${CastResult}
		}

- - - Updated - - -

Example of my old cleric [Heals]

Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Fifteenth Emblem Rk. III|45
Heals2=Burst of Life|45
Heals3=Beacon of Life|45
Heals4=Graceful Remedy Rk. III|45|!MA
Heals5=Forceful Rejuvenation|45
Heals6=Graceful Remedy Rk. III|95|MA
Heals7=Virtuous Intervention Rk. III|95
Heals8=Virtuous Contravention|95|Mob
Heals9=Fraught Renewal Rk. II|95|MA
Heals10=Fervent Renewal|95|MA
Heals11=Frenzied Renewal Rk. II|95|MA
Heals12=Graceful Remedy Rk. III|95|XT
Heals13=Virtuous Intervention Rk. III|95|XT
Heals14=Fraught Renewal Rk. II|95|XT
Heals15=Fervent Renewal|95|XT
Heals16=Frenzied Renewal Rk. II|95|XT
Heals17=Word of Reformation|99
Heals18=Frenzied Renewal Rk. II|99
XTarHeal=8
AutoRezOn=1
AutoRezWith=Blessing of Resurrection
OOCRezWith=Blessing of Resurrection
InterruptHP=55

And: my new cleric [Heals] after the above code changes.

Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Fifteenth Emblem Rk. III|45
Heals2=Burst of Life|45
Heals3=Beacon of Life|85
Heals4=Graceful Remedy Rk. III|95
Heals5=Forceful Rejuvenation|45
Heals6=Virtuous Intervention Rk. III|95
Heals7=Fraught Renewal Rk. II|95
Heals8=Fervent Renewal|95
Heals9=Frenzied Renewal Rk. II|95
Heals10=Word of Reformation Rk. III|99
Heals11=NULL
Heals12=NULL
Heals13=NULL
Heals14=NULL
Heals15=NULL
Heals16=NULL
Heals17=NULL
Heals18=NULL
Heals19=NULL
Heals20=NULL
XTarHeal=1
AutoRezOn=0
AutoRezWith=Blessing of Resurrection
OOCRezWith=Blessing of Resurrection
InterruptHP=55
 

Attachments

Last edited:
This looks awesome man. Just got it all loaded up and running. Working great so far (using it in my bot group). Thanks for all of your hard work on this.

Rob
 
Last edited:
Forgot to mention the stupid druid bear, Nurturing Growth: This can safely be used as |mana buff in the above code. Without the above check in Sub CheckBuffs, that stupid bear will lock a druid up something awful.
 
Interesting changes. Kiss was strictly written for only a group environment not raids so I can see where some of these changes would be needed. Some things reading through quick.

Why do you have ENC (enchanters) included for 20 heals?
Rich (BB code):
    /if (${Select[${Me.Class.ShortName},CLR,SHM,DRU,PAL,ENC]})  {
This mess is your hacked version and not Kiss
Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Fifteenth Emblem Rk. III|45
Heals2=Burst of Life|45
Heals3=Beacon of Life|45
Heals4=Graceful Remedy Rk. III|45|!MA
Heals5=Forceful Rejuvenation|45
Heals6=Graceful Remedy Rk. III|95|MA
Heals7=Virtuous Intervention Rk. III|95
Heals8=Virtuous Contravention|95|Mob
Heals9=Fraught Renewal Rk. II|95|MA
Heals10=Fervent Renewal|95|MA
Heals11=Frenzied Renewal Rk. II|95|MA
Heals12=Graceful Remedy Rk. III|95|XT
Heals13=Virtuous Intervention Rk. III|95|XT
Heals14=Fraught Renewal Rk. II|95|XT
Heals15=Fervent Renewal|95|XT
Heals16=Frenzied Renewal Rk. II|95|XT
Heals17=Word of Reformation|99
Heals18=Frenzied Renewal Rk. II|99
XTarHeal=8
AutoRezOn=1
AutoRezWith=Blessing of Resurrection
OOCRezWith=Blessing of Resurrection
InterruptHP=55
This is a normal Kiss ini for 100 lv cleric
Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Faithful Remedy|55
Heals2=Zealous Light|75
Heals3=Zealous Elixir|90
Heals4=Celestial Regeneration|70
Heals5=Divine Arbitration|35
Heals6=Word of Rehabilitation|85
Heals7=Promised Restitution|90|MA
Heals8=Fourteenth Catalyst|40
Heals9=Beacon of Life|80
Heals10=Burst of Life|45
Tossing healing code into the middle of the spell casting engine. not a good idea. I would find a way to sub it out and use the interrupt check built into MQ2cast.
Rich (BB code):
			|Monitor MA/Me HP While Casting. Abort if InterruptHP is hit.
				:MonitorHPWhileCasting
				/if (${sentFrom.NotEqual[Heal]} && ${sentFrom.NotEqual[Mez]} && ${HealsOn} && ${Spawn[${MainAssist} ${MainAssistType}].PctHPs}<=${InterruptHP}) {
					/docommand /stopcast
					/echo ${sentFrom} spell ${castWhat} ABORTED to cast a heal!
					/call CheckHealth
				}
				/if (${sentFrom.Equal[Heal]} && ${HealsOn} && ${${Cast.Status}.Equal[C]}) {
					/delay 1
					/goto :MonitorHPWhileCasting
				}
				:Stillcasting
				/if (${${Cast.Status}.Equal[C]}) {
					/delay 1
					/goto :Stillcasting
				}

Already in Works
New Heal tags |Mob and |Me are coming in 7.5
The druid/shammy out of combat rez is coming in 7.5

I like the idea of checking if multiple people are hurt as an additional check for group heals. I am so stealing that.

Epic work though some good ideas.
 
I do a LOT of open raids where anyone can join instead of checking guild everywhere check raid, i just recently added that flag to searchspawn so now you can do stuff like ${SpawnCount[pccorpse raid radius 100 loc ${Me.X} ${Me.Y}]}

Will be trying this out.
 
I do a LOT of open raids where anyone can join instead of checking guild everywhere check raid, i just recently added that flag to searchspawn so now you can do stuff like ${SpawnCount[pccorpse raid radius 100 loc ${Me.X} ${Me.Y}]}

Will be trying this out.

What I need is an easier way to find out what task step you're on and how many kills you got left to complete it :)
 
I opened up heals for enchanters who like to chain rune. The extra space was for multi entries of the same spell with different tags and thresholds. Some of them fellers put together some rather complicated chains that rune like mad and generate almost no aggro. But they needed more space to do it in.

Yeah, that "mess" was getting outta control in my various modded experiments. Which is what prompted the heal reflow beginning with group heal. However, this was true in both the official version and my playthings. At least in regards to the fact that extensive tagging was needed to get the heals to fire in what I would call a more logical manner.

Say; if anyone is willing to put together another way of interrupting the cast to go to heals, I'm all ears. Don't seem to much matter how, so long as it's effective in doing what it needs to do: Keep an eye on the HP while a casting bar is present and interrupt the cast to go to heals when needed.

- - - Updated - - -

Example of my previous official version cleric ini:

Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Fifteenth Emblem Rk. III|45
Heals2=Burst of Life|45
Heals3=Beacon of Life|45
Heals4=Graceful Remedy Rk. III|45|!MA
Heals5=Forceful Rejuvenation|45
Heals6=Graceful Remedy Rk. III|95|MA
Heals7=Virtuous Intervention Rk. III|95|MA
Heals8=Fraught Renewal Rk. II|95|MA
Heals9=Fervent Renewal|95|MA
Heals10=Frenzied Renewal Rk. II|95|MA
Heals11=Word of Reformation|99

- - - Updated - - -

This shouldn't work in any version. If it does, there's a problem.

Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Faithful Remedy|55
Heals2=Zealous Light|75 <-- No recast delay |75 threshold.
Heals3=Zealous Elixir|90
Heals4=Celestial Regeneration|70 <--- |70 < |75 and the |75 got parsed 1st. This should never fire as written. Applies to other entries, as well.
Heals5=Divine Arbitration|35 <--- |35 < |75 and the |75 got parsed 1st. This should never fire as written. Applies to other entries, as well.
Heals6=Word of Rehabilitation|85
Heals7=Promised Restitution|90|MA
Heals8=Fourteenth Catalyst|40 <--- |40 < |75 and the |75 got parsed 1st. This should never fire as written. Applies to other entries, as well.
Heals9=Beacon of Life|80
Heals10=Burst of Life|45 <--- |45 < |75 and the |75 got parsed 1st. This should never fire as written. Applies to other entries, as well.

- - - Updated - - -

I prolly shoulda mentioned, too, that even this mod of KA requires at least one auto-hater slot on the xtarget list to function properly. It doesn't matter which slot you leave open or if you change which slot is open. But, at any given time there needs be at least one auto-hater somewhere on yer xtarget list.
 
Noticed another error in my OP. Heal-Nukes still require a |Mob tag and are only good for the MA. I'm looking forward to seeing what Maskoi has in store for the |Mob tag. I'd like to see this go mobile; but haven't figured out all the Target's Target TLO's to make this work, yet.

- - - Updated - - -

Hmm... Xtarget healing should be on a "most hurt" basis, shouldn't it? Currently I have it rigged as a priority list, from top to bottom...
 
Noticed another error in my OP. Heal-Nukes still require a |Mob tag and are only good for the MA. I'm looking forward to seeing what Maskoi has in store for the |Mob tag. I'd like to see this go mobile; but haven't figured out all the Target's Target TLO's to make this work, yet.

why would Heal-Nuke need a |mob tag and not the |MA tag, the spell are designed to Heal the target (PC/Pet) and Nuke that target's target for damage?
 
Heal-Nukes, Nuke-heals, meh that can get confusing quick. The reason here is that the mob needs be targeted to heal the player. Nuke the mob, heal the target's target.

- - - Updated - - -

But, yeah, in regards to spells that heal the target and nuke the target's target; those need no tags at all.

- - - Updated - - -

Virtuous Contravention is a good example of a spell that needs be cast at the mob to heal the player (thus requiring a |mob tag)
 
so i been testing Raidassist on my cleric in raids, noticed that if a NPC's pet a is on the etw it will heal that NPC's pet as the raid is killing it.

here is my healing section of the cleric's ini
Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Fifteenth Emblem Rk. III|45
Heals2=Burst of Life|45
Heals3=Beacon of Life|85
Heals4=Graceful Remedy Rk. III|90
Heals5=Ward of Certitude Rk. III|40
Heals6=Virtuous Intervention Rk. III|0
Heals7=Fraught Renewal Rk. III|85
Heals8=Fervent Renewal Rk. III|85
Heals9=Frenzied Renewal Rk. III|85
Heals10=Word of Reformation Rk. III|75
Heals11=Reverent Light Rk. III|70
Heals12=NULL
Heals13=NULL
Heals14=NULL
Heals15=NULL
Heals16=NULL
Heals17=NULL
Heals18=NULL
Heals19=NULL
Heals20=NULL
XTarHeal=2

it seem to be casting Reverent Light mostly, which is fine for mana effiency but if i want to keep the 4 warriors in the MT group i need the faster heals to fire.
 
Say; you're getting to Reverent Light for lack of enough heals to create a full chain. We need enough heals to get us through the 30 second recast delay on Intervention and Renewal spells. I only just noticed that Intervention spells do not share a timer with one another. So; this is my current line up. I might play with the order a bit. This; due to there being only a .3 sec difference between Intervention and Renewal. There is a larger mana difference, tho, meaning that if we fire more Intervention spells, we use less mana... will have to play with this a bit to reach the proper mana/speed balance.

Rich (BB code):
[Memorized Spells]
Gem1=Graceful Remedy Rk. III
Gem2=Virtuous Intervention Rk. III
Gem3=Elysian Intervention
Gem4=Fraught Renewal Rk. II
Gem5=Fervent Renewal
Gem6=Celestial Intervention
Gem7=Fifteenth Emblem Rk. III
Gem8=Syllable of Renewal Rk. III
Gem9=Word of Reformation Rk. III
Gem10=Abrogate Corruption
Gem11=Divine Interposition Rk. III
Gem12=NULL

Rich (BB code):
[Heals]
Help=Format Spell|% to heal at i.e. Devout Light Rk. II|50
HealsOn=1
Heals1=Fifteenth Emblem Rk. III|45
Heals2=Burst of Life|45
Heals3=Beacon of Life|85
Heals4=Graceful Remedy Rk. III|95
Heals5=Forceful Rejuvenation|45
Heals6=Virtuous Intervention Rk. III|95
Heals7=Elysian Intervention|95
Heals8=Fraught Renewal Rk. II|95
Heals9=Fervent Renewal|95
Heals10=Celestial Intervention|95
Heals11=Syllable of Renewal Rk. III|99
Heals12=Word of Reformation Rk. III|99

The idea being that the .5 sec heal (Graceful, backed by Fifteenth) is both our 1st response heal and our "main heal". The fire order, under consistent pressure, should be "Graceful -> Intervention1 -> Graceful ->Intervention2 -> Graceful ->Renewal1 ->Graceful -> Renewal2 -> Graceful -> Intervention3". Then the chain is complete and can start over again and never need Reverent Light at all.

We can apply this, in some small manner, to group heals as well. By parsing 'Syllable of Renewal' before 'Word of Reformation'; we can use the "fast" group heal, when it's avail, and Word when we have to.

A word on Word: in a full group, any average threshold below 83.5 may allow for one of your group members to be dead before the spell fires. And; we really don't want "Beacon of Life|85" with it's 15 min cooldown to fire when "Word of Reformation Rk. III|75" would be acceptable.

As to trying to heal a hostile NPC's pet... Well; that's just a silly thing to be doing, isn't it? I'll look for this. Lemme know if a fix strikes ya.

- - - Updated - - -

A 1000 cast sample from tonight's CoTF T2 Group Mission lock-outs:

Rich (BB code):
A skirth ripper, A gehein soulcrusher, Grundehl, Lanys T`Vyl, Borleoth on 7/27/2014

Cleric - 1067
   --- Abrogate Corruption - 38
   --- Armor of the Reverent Rk. II - 1
   --- Bastion of Vie Rk. III - 2
   --- Beacon of Life - 16  <--- Used when getting close to that "group member could be dead" emergency threshold.
   --- Blessing of Resurrection - 1
   --- Burst of Life - 1
   --- Celestial Blessing - 4
   --- Celestial Intervention - 12  <--- It takes a lot of pressure to get this far down the parse order. But the chain did complete and recycle, as desired, when this happened
   --- Celestial Rapidity - 4
   --- Celestial Regeneration - 5
   --- Channeling the Divine - 4
   --- Divine Guardian - 1
   --- Divine Peace - 1
   --- Elysian Intervention - 70
   --- Fervent Renewal - 16
   --- Fifteenth Emblem Rk. III - 3
   --- Flurry of Life - 4
   --- Focused Celestial Regeneration - 4
   --- Fraught Renewal Rk. II - 49
   --- Glyph of Lost Secrets - 1
   --- Graceful Remedy Rk. III - 411  <--- .5 sec heal fired more than anything else, by a long shot.
   --- Group Purify Soul - 2
   --- Healing Frenzy - 4
   --- Quiet Miracle - 3
   --- Radiant Cure - 16
   --- Shining Bastion Rk. II - 1
   --- Syllable of Renewal Rk. III - 162  <--- Fast-group fired more than Word of Reformation, even with it's 8 sec recast delay.
   --- Third Spire of Divinity - 4
   --- Veturika's Perseverance - 3
   --- Virtuous Intervention Rk. III - 88  <--- As we go down the parse order, the heals fired in the expected declining frequency.
   --- Word of Reformation Rk. III - 132
   --- Yaulp - 4

Produced by GamParse v1.0.5

411 Graceful's. 235 Renewl's/Intervention's. That's pretty close to 50:50; which is what we're looking for in this lineup. The ~29 exceptions may indicate some small gap in the chain. Or; that Graceful got sent to CastWhat while still on cool-down (not global), thusly "skipped". I've put in a few preemptive blocks to prevent most of the latter (as this occurs in all versions of KA), but those still need a little work.
 
Last edited:
how does yr RA cleric setup hold up in the DH Xuluos prime encounter with cures and all?
Also think you could post your entire .ini?
 
Nomad could u post your entire ini im intreged to see it , i been playing with this alot and i must say i am in love with it
 
Fork / Mod Optimzations for Healers (Mostly)

Users who are viewing this thread

Back
Top
Cart