private static void CombatLogEventHandler(string id, List <string> args) { if (id == "PLAYER_DEAD") { RotationSpellVerifier.ForceClearVerification(); } if (id == "COMBAT_LOG_EVENT_UNFILTERED") { RotationSpellVerifier.NotifyCombatLog(args); } if (id == "UNIT_SPELLCAST_FAILED" || id == "UNIT_SPELLCAST_INTERRUPTED" || id == "UNIT_SPELLCAST_FAILED_QUIET") { string luaUnitId = args[0]; string spellName = args[1]; if (luaUnitId == "player" && RotationSpellVerifier.IsSpellWaitingForVerification(spellName)) { RotationSpellVerifier.ForceClearVerification(spellName); } } if (id == "UNIT_SPELLCAST_SUCCEEDED" || id == "UNIT_SPELLCAST_SENT") { string luaUnitId = args[0]; string spellName = args[1]; // we're creating a fake combat log event to notify that a spell has successfully finished casting // SPELL_CAST_SUCCESS otherwise only fires for instant spells if (luaUnitId == "player" && RotationSpellVerifier.IsSpellWaitingForVerification(spellName)) { List <string> combatLogEvent = new List <string> { "0", "SPELL_CAST_SUCCESS", _luaPlayerGuid, _playerName, "0x0000000000000000", "0x0000000000000000", "nil", "0x0000000000000000", "0", spellName, "0x00" }; RotationSpellVerifier.NotifyCombatLog(combatLogEvent); } } //fake combat log event to clear help with force clearing verifications if (id == "UNIT_COMBAT") { List <string> combatLogEvent = new List <string> { "0", "NONE", _luaPlayerGuid, _playerName, "0x0000000000000000", "0x0000000000000000", "nil", "0x0000000000000000" }; RotationSpellVerifier.NotifyCombatLog(combatLogEvent); } if (id == "COMBAT_TEXT_UPDATE") { } // this error is not found through casting or combatlog events because it's caused by the client checking IsSpellInRange when using CastSpellByName // we could technically execute this check ourselves in CombatLogUtil but usually the client-side range check (memory based GetDistance) is enough) and cheaper! // therefore we're listening to error messages and executing this check lazily if (id == "UI_ERROR_MESSAGE" && (args[0] == "Out of range." || args[0] == "You are too far away!")) { RotationSpellVerifier.ClearIfOutOfRange(); } }
public static bool CastSpell(RotationSpell spell, WoWUnit unit, bool force = false) { // still waiting to make sure last spell was casted successfully, this can be interrupted // by interrupting the current cast to cast something else (which will clear the verification) if (RotationSpellVerifier.IsWaitingForVerification() && !force) { return(false); } // no need to check for spell availability // already wanding, don't turn it on again! if (spell.Spell.Name == "Shoot" && IsAutoRepeating("Shoot")) { return(true); } // targetfinder function already checks that they are in LoS and RotationStep takes care of the range check if (unit != null && spell.IsKnown() && spell.CanCast()) { Lua.LuaDoString("if IsMounted() then Dismount() end"); if (spell.Spell.CastTime > 0) { if (spell.Verification != RotationSpell.VerificationType.NONE) { //setting this for delegates, so we don't miss events //SetFocusGuid(unit.Guid); RotationSpellVerifier.QueueVerification(spell.Spell.Name, unit, spell.Verification); } //force iscast so we don't have to wait for client updates RotationFramework.IsCast = true; //ObjectManager.Me.ForceIsCast = true; } if (AreaSpells.Contains(spell.Spell.Name)) { SpellManager.CastSpellByIDAndPosition(spell.Spell.Id, unit.Position); } else { if (unit.Guid != RotationFramework.Me.Guid && unit.Guid != RotationFramework.Target.Guid) { MovementManager.Face(unit); } ExecuteActionOnUnit <object>(unit, (luaUnitId => { RotationLogger.Fight($"Casting {spell.FullName()} ({spell.Spell.Name} on {luaUnitId} with guid {unit.Guid}"); //MovementManager.StopMoveTo(false, (int) spell.CastTime()); Lua.LuaDoString($@" if {force.ToString().ToLower()} then SpellStopCasting() end CastSpellByName(""{spell.FullName()}"", ""{luaUnitId}""); --CombatTextSetActiveUnit(""{luaUnitId}""); FocusUnit(""{luaUnitId}""); " ); return(null); })); } return(true); } return(false); }