private static void HandleCombatLog(object sender, LuaEventArgs args) { var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); //Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName); switch (e.Event) { case "SPELL_AURA_APPLIED": case "SPELL_CAST_SUCCESS": if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Update the last spell we cast. So certain classes can 'switch' their logic around. Spell.LastSpellCast = e.SpellName; //Logger.WriteDebug("Successfully cast " + Spell.LastSpellCast); // Force a wait for all summoned minions. This prevents double-casting it. if (SingularRoutine.MyClass == WoWClass.Warlock && e.SpellName.StartsWith("Summon ")) { StyxWoW.SleepForLagDuration(); } break; case "SPELL_MISSED": if (e.Args[14].ToString() == "EVADE") { Logger.Write("Mob is evading. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } break; } }
private static void GetDrFromCombatLog(object sender, LuaEventArgs args) { var clog = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); if ((clog.Event != null && (clog.Event.Equals("SPELL_AURA_REFRESH") || clog.Event.Equals("SPELL_AURA_APPLIED"))) && clog.DestUnit != null && !clog.DestUnit.IsFriendly && (Instance._disorientationSpells.Contains(clog.Spell) || Instance._stunSpells.Contains(clog.Spell) || Instance._rootsSpells.Contains(clog.Spell) || Instance._incapacitatesSpells.Contains(clog.Spell) || Instance._silenceSpells.Contains(clog.Spell))) { if (Instance._disorientationSpells.Contains(clog.Spell)) { Instance.AddDr(clog.DestUnit, DrCategory.Disoriented); return; } if (Instance._stunSpells.Contains(clog.Spell)) { Instance.AddDr(clog.DestUnit, DrCategory.Stun); return; } if (Instance._rootsSpells.Contains(clog.Spell)) { Instance.AddDr(clog.DestUnit, DrCategory.Root); return; } if (Instance._incapacitatesSpells.Contains(clog.Spell)) { Instance.AddDr(clog.DestUnit, DrCategory.Incapacitate); return; } if (Instance._silenceSpells.Contains(clog.Spell)) { Instance.AddDr(clog.DestUnit, DrCategory.Silence); return; } } }
private static void HandleEvadeBuggedMob(LuaEventArgs args, CombatLogEventArgs e) { WoWUnit unit = e.DestUnit; ulong guid = e.DestGuid; if (unit == null && StyxWoW.Me.CurrentTarget != null) { unit = StyxWoW.Me.CurrentTarget; guid = StyxWoW.Me.CurrentTargetGuid; Logger.Write("Evade: bugged mob guid:{0}, so assuming current target instead", args.Args[7]); } if (unit != null) { if ( !MobsThatEvaded.ContainsKey( unit.Guid )) MobsThatEvaded.Add( unit.Guid, 0); MobsThatEvaded[unit.Guid]++; if (MobsThatEvaded[unit.Guid] <= 5) { Logger.Write("Mob {0} has evaded {1} times. Keeping an eye on {2:X0} for now!", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid); } else { const int MinutesToBlacklist = 5; if (Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) Logger.Write(Color.LightGoldenrodYellow, "Mob {0} has evaded {1} times. Previously blacklisted {2:X0} for {3} minutes!", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid, MinutesToBlacklist); else { Logger.Write(Color.LightGoldenrodYellow, "Mob {0} has evaded {1} times. Blacklisting {2:X0} for {3} minutes!", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid, MinutesToBlacklist); Blacklist.Add(unit.Guid, BlacklistFlags.Combat, TimeSpan.FromMinutes(MinutesToBlacklist)); if (!Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logger.Write(Color.Pink, "error: blacklist does not contain entry for {0} so adding {1}", unit.SafeName(), unit.Guid); } } if (BotPoi.Current.Guid == unit.Guid) { Logger.Write("EvadeHandling: Current BotPOI type={0} is Evading, clearing now...", BotPoi.Current.Type); BotPoi.Clear("Singular recognized Evade bugged mob"); } if (StyxWoW.Me.CurrentTargetGuid == guid) { foreach (var target in Targeting.Instance.TargetList) { if (target.IsAlive && Unit.ValidUnit(target) && !Blacklist.Contains(target, BlacklistFlags.Combat)) { Logger.Write(Color.Pink, "Setting target to {0} to get off evade bugged mob!", target.SafeName()); target.Target(); return; } } Logger.Write(Color.Pink, "BotBase has 0 entries in Target list not blacklisted -- nothing else we can do at this point!"); // StyxWoW.Me.ClearTarget(); } } } /// line below was originally in Evade logic, but commenting to avoid Sleeps // StyxWoW.SleepForLagDuration(); }
private static void HandleCombatLog(object sender, LuaEventArgs args) { // Since we hooked this in ctor, make sure we are the selected CC if (RoutineManager.Current.Name != SingularRoutine.Instance.Name) return; var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); if (e.SourceGuid != StyxWoW.Me.Guid) return; // Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName); switch (e.Event) { default: if ( SingularSettings.Debug ) Logger.WriteDebug("[CombatLog] filter out this event -- " + e.Event + " - " + e.SourceName + " - " + e.SpellName); break; // spell_cast_failed only passes filter in Singular debug mode case "SPELL_CAST_FAILED": if ( !SingularSettings.Debug) Logger.WriteFile("[CombatLog] {0} {1}#{2} failure: '{3}'", e.Event, e.Spell.Name, e.SpellId, e.Args[14] ); else Logger.WriteDebug("[CombatLog] {0} {1}#{2} failure: '{3}'", e.Event, e.Spell.Name, e.SpellId, e.Args[14]); if ( e.Args[14].ToString() == LocalizedLineOfSightFailure ) { ulong guid; try { LastLineOfSightTarget = e.DestUnit; guid = LastLineOfSightTarget == null ? 0 : LastLineOfSightTarget.Guid; } catch { LastLineOfSightTarget = StyxWoW.Me.CurrentTarget; guid = StyxWoW.Me.CurrentTargetGuid; } LastLineOfSightFailure = DateTime.Now; Logger.WriteFile("[CombatLog] cast failed due to los reported at {0} on target {1:X}", LastLineOfSightFailure.ToString("HH:mm:ss.fff"), e.DestGuid ); } else if (!MovementManager.IsMovementDisabled && StyxWoW.Me.Class == WoWClass.Warrior && e.Args[14].ToString() == LocalizedNoPathAvailableFailure) { LastNoPathFailure = DateTime.Now; LastNoPathTarget = StyxWoW.Me.CurrentTargetGuid; Logger.WriteFile("[CombatLog] cast failed due to no path available to current target"); } else if (!SingularRoutine.IsManualMovementBotActive && (StyxWoW.Me.Class == WoWClass.Druid || StyxWoW.Me.Class == WoWClass.Shaman)) { if (LocalizedShapeshiftMessages.ContainsKey(e.Args[14].ToString())) { string symbolicName = LocalizedShapeshiftMessages[e.Args[14].ToString()]; SuppressShapeshiftUntil = DateTime.Now.Add( TimeSpan.FromSeconds(30)); Logger.Write(Color.White, "/cancel{0} - due to Shapeshift Error '{1}' on cast, suppress form until {2}!", StyxWoW.Me.Shapeshift.ToString().CamelToSpaced(), symbolicName, SuppressShapeshiftUntil.ToString("HH:mm:ss.fff")); Lua.DoString("CancelShapeshiftForm()"); } } else if (StyxWoW.Me.Class == WoWClass.Rogue && SingularSettings.Instance.Rogue().UsePickPocket) { if (e.Args[14].ToString() == LocalizedNoPocketsToPickFailure) { // args on this event don't match standard SPELL_CAST_FAIL // -- so, Singular only casts on current target so use that assumption WoWUnit unit = StyxWoW.Me.CurrentTarget; if (unit == null) Logger.WriteFile("[CombatLog] has no pockets event did not have a valid unit"); else { Logger.WriteDebug("[CombatLog] {0} has no pockets, blacklisting from pick pocket for 2 minutes", unit.SafeName()); Blacklist.Add(unit.Guid, BlacklistFlags.Node, TimeSpan.FromMinutes(2)); } } } break; #if SOMEONE_USES_LAST_SPELL_AT_SOME_POINT case "SPELL_AURA_APPLIED": case "SPELL_CAST_SUCCESS": if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Update the last spell we cast. So certain classes can 'switch' their logic around. Spell.LastSpellCast = e.SpellName; //Logger.WriteDebug("Successfully cast " + Spell.LastSpellCast); // following commented block should not be needed since rewrite of Pet summon // //// Force a wait for all summoned minions. This prevents double-casting it. //if (StyxWoW.Me.Class == WoWClass.Warlock && e.SpellName.StartsWith("Summon ")) //{ // StyxWoW.SleepForLagDuration(); //} break; #endif case "SWING_MISSED": if (e.Args[11].ToString() == "EVADE") { HandleEvadeBuggedMob(args, e); } else if (e.Args[11].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to Physical spell school", unit.Name); SpellImmunityManager.Add(unit.Entry, WoWSpellSchool.Physical ); } } break; case "SPELL_MISSED": case "RANGE_MISSED": // Why log misses? Because users of classes with DoTs testing on training dummies // .. that they don't have enough +Hit for will get DoT spam. This allows easy // .. diagnosis of false reports of rotation issues where a user simply isn't geared // .. this happens more at the beginning of an expansion especially if (SingularSettings.Debug) { Logger.WriteDebug( "[CombatLog] {0} {1}#{2} {3}", e.Event, e.Spell.Name, e.SpellId, e.Args[14] ); } if (e.Args[14].ToString() == "EVADE") { HandleEvadeBuggedMob(args, e); } else if (e.Args[14].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; } }
private static void LogUndesirableEvent(string p, CombatLogEventArgs e) { if (SingularSettings.Debug) { string sourceName; string destName; try { sourceName = e.SourceUnit.SafeName(); } catch { sourceName = "unknown"; } try { destName = e.DestUnit.SafeName(); } catch { destName = "unknown"; } Logger.WriteDiagnostic("Programmer Error - Combat Log Event {0}: filter out {1} - {2} {3} - {4} {5} on {6} {7}", p, e.EventName, e.SourceGuid, sourceName, e.SpellName, e.SpellId, e.DestGuid, destName ); } }
private static void HandleCombatLog(object sender, LuaEventArgs args) { // Since we hooked this in ctor, make sure we are the selected CC if (RoutineManager.Current.Name != SingularRoutine.Instance.Name) return; // convert args to usable form var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); bool itWasDamage = false; if (TrackDamage || SingularRoutine.CurrentWoWContext == WoWContext.Normal) { if (e.DestGuid == StyxWoW.Me.Guid && e.SourceGuid != StyxWoW.Me.Guid) { long damageAmount = 0; switch (e.EventName) { case "SWING_DAMAGE": itWasDamage = true; damageAmount = (long)e.Args[11]; Logger.WriteDebug("HandleCombatLog(Damage): {0} = {1}", e.EventName, damageAmount); break; case "SPELL_DAMAGE": case "SPELL_PERIODIC_DAMAGE": case "RANGE_DAMAGE": itWasDamage = true; damageAmount = (long)e.Args[14]; break; } if (TrackDamage) { if (itWasDamage) Logger.WriteDebug("HandleCombatLog(Damage): {0} = {1}", e.EventName, damageAmount); else LogUndesirableEvent("On Character", e); if (damageAmount > 0) { DamageHistory.Enqueue(new Damage(DateTime.UtcNow, damageAmount)); } } if (itWasDamage && SingularRoutine.CurrentWoWContext == WoWContext.Normal) { WoWUnit enemy = e.SourceUnit; if (Unit.ValidUnit(enemy) && enemy.IsPlayer) { Logger.WriteDiagnostic("GankDetect: received {0} src={1} dst={2}", args.EventName, e.SourceGuid, e.DestGuid); // if (guidLastEnemy != enemy.Guid || (TimeLastAttackedByEnemyPlayer - DateTime.UtcNow).TotalSeconds > 30) { guidLastEnemy = enemy.Guid; string extra = ""; if (e.Args.GetUpperBound(0) >= 12) extra = string.Format(" using {0}", e.SpellName); AttackedWithSpellSchool = WoWSpellSchool.None; if (e.Args.GetUpperBound(0) >= 12) AttackedWithSpellSchool = e.SpellSchool; Logger.WriteDiagnostic("GankDetect: attacked by Level {0} {1}{2}", enemy.Level, enemy.SafeName(), extra); if (SingularSettings.Instance.TargetWorldPvpRegardless && (BotPoi.Current == null || BotPoi.Current.Guid != enemy.Guid)) { Logger.Write(LogColor.Hilite, "GankDetect: setting {0} as BotPoi Kill Target", enemy.SafeName()); BotPoi.Current = new BotPoi(enemy, PoiType.Kill); } } AttackingEnemyPlayer = enemy; TimeLastAttackedByEnemyPlayer = DateTime.UtcNow; } } } return; } // Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName); switch (e.Event) { default: LogUndesirableEvent( "From Character", e ); break; // spell_cast_failed only passes filter in Singular debug mode case "SPELL_CAST_FAILED": Logger.WriteDiagnostic("[CombatLog] {0} {1}#{2} failure: '{3}'", e.Event, e.Spell.Name, e.SpellId, e.Args[14] ); if ( e.Args[14].ToString() == LocalizedLineOfSightFailure ) { WoWGuid guid = WoWGuid.Empty; try { LastLineOfSightTarget = e.DestUnit; guid = LastLineOfSightTarget == null ? WoWGuid.Empty : LastLineOfSightTarget.Guid; } catch { } if (!guid.IsValid) { Logger.WriteFile("[CombatLog] no valid destunit so using CurrentTarget"); LastLineOfSightTarget = StyxWoW.Me.CurrentTarget; guid = StyxWoW.Me.CurrentTargetGuid; } LastLineOfSightFailure = DateTime.UtcNow; Logger.WriteFile("[CombatLog] cast failed due to los reported at {0} on target {1:X}", LastLineOfSightFailure.ToString("HH:mm:ss.fff"), e.DestGuid ); } else if (e.Args[14].ToString() == LocalizedUnitNotInfrontFailure ) { WoWGuid guid = e.DestGuid; LastUnitNotInfrontFailure = DateTime.UtcNow; if (guid.IsValid && guid != WoWGuid.Empty) { LastUnitNotInfrontGuid = guid; Logger.WriteFile("[CombatLog] not facing SpellTarget [{0}] at {1}", LastUnitNotInfrontGuid, LastUnitNotInfrontFailure.ToString("HH:mm:ss.fff")); } else { LastUnitNotInfrontGuid = Spell.LastSpellTarget; Logger.WriteFile("[CombatLog] not facing LastTarget [{0}] at {1}", LastUnitNotInfrontGuid, LastUnitNotInfrontFailure.ToString("HH:mm:ss.fff"), guid); } } else if (!MovementManager.IsMovementDisabled && StyxWoW.Me.Class == WoWClass.Warrior && e.Args[14].ToString() == LocalizedNoPathAvailableFailure) { LastNoPathFailure = DateTime.UtcNow; LastNoPathGuid = StyxWoW.Me.CurrentTargetGuid; if (!StyxWoW.Me.GotTarget()) Logger.WriteFile("[CombatLog] cast failed - no path available to current target"); else Logger.WriteFile("[CombatLog] cast failed - no path available to {0}, heightOffGround={1}, pos={2}", StyxWoW.Me.CurrentTarget.SafeName(), StyxWoW.Me.CurrentTarget.HeightOffTheGround(), StyxWoW.Me.CurrentTarget.Location ); } else if (!SingularRoutine.IsManualMovementBotActive && (StyxWoW.Me.Class == WoWClass.Druid || StyxWoW.Me.Class == WoWClass.Shaman)) { if (LocalizedShapeshiftMessages.ContainsKey(e.Args[14].ToString())) { string symbolicName = LocalizedShapeshiftMessages[e.Args[14].ToString()]; SuppressShapeshiftUntil = DateTime.UtcNow.Add( TimeSpan.FromSeconds(30)); Logger.Write(LogColor.Cancel, "/cancel{0} - due to Shapeshift Error '{1}' on cast, suppress form for {2:F1} seconds", StyxWoW.Me.Shapeshift.ToString().CamelToSpaced(), symbolicName, (SuppressShapeshiftUntil - DateTime.UtcNow).TotalSeconds); Lua.DoString("CancelShapeshiftForm()"); } } else if (StyxWoW.Me.Class == WoWClass.Rogue && SingularSettings.Instance.Rogue().UsePickPocket) { if (e.Args[14].ToString() == LocalizedNoPocketsToPickFailure) { HandleRogueNoPocketsError(); } } break; #if SOMEONE_USES_LAST_SPELL_AT_SOME_POINT case "SPELL_AURA_APPLIED": case "SPELL_CAST_SUCCESS": if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Update the last spell we cast. So certain classes can 'switch' their logic around. Spell.LastSpellCast = e.SpellName; //Logger.WriteDebug("Successfully cast " + Spell.LastSpellCast); // following commented block should not be needed since rewrite of Pet summon // //// Force a wait for all summoned minions. This prevents double-casting it. //if (StyxWoW.Me.Class == WoWClass.Warlock && e.SpellName.StartsWith("Summon ")) //{ // StyxWoW.SleepForLagDuration(); //} break; #endif case "SWING_MISSED": if (e.Args[11].ToString() == "EVADE") { HandleEvadeBuggedMob(args, e); } else if (e.Args[11].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to Physical spell school", unit.Name); SpellImmunityManager.Add(unit.Entry, WoWSpellSchool.Physical ); } } break; case "SPELL_MISSED": case "RANGE_MISSED": // Why log misses? Because users of classes with DoTs testing on training dummies // .. that they don't have enough +Hit for will get DoT spam. This allows easy // .. diagnosis of false reports of rotation issues where a user simply isn't geared // .. this happens more at the beginning of an expansion especially if (SingularSettings.Debug) { Logger.WriteDebug( "[CombatLog] {0} {1}#{2} {3}", e.Event, e.Spell.Name, e.SpellId, e.Args[14] ); } if (e.Args[14].ToString() == "EVADE") { HandleEvadeBuggedMob(args, e); } else if (e.Args[14].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } if (StyxWoW.Me.Class == WoWClass.Rogue && e.SpellId == 6770) { WoWUnit unitImmune = unit; if (unitImmune == null) unitImmune = ObjectManager.GetObjectByGuid<WoWUnit>(Singular.ClassSpecific.Rogue.Common.lastSapTarget); Singular.ClassSpecific.Rogue.Common.AddEntryToSapImmuneList(unitImmune); } } break; case "UNIT_DIED": try { WoWUnit corpse = e.SourceUnit; WoWPartyMember pm = Unit.GroupMemberInfos.First( m => m.Guid == corpse.Guid); Logger.WriteDiagnostic( "Combat Log: UNIT_DIED - Role={0} {1}", pm.Role & (~WoWPartyMember.GroupRole.Leader), corpse.SafeName()); } catch { } break; } }
private static void HandleCombatLog(object sender, LuaEventArgs args) { var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); if (e.SourceGuid != StyxWoW.Me.Guid) return; // Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName); switch (e.Event) { default: Logger.WriteDebug("[CombatLog] filter out this event -- " + e.Event + " - " + e.SourceName + " - " + e.SpellName); break; case "SPELL_CAST_FAILED": if (SingularSettings.Instance.EnableDebugLogging) { Logger.WriteDebug("[CombatLog] {0}:{1} cast of {2}#{3} on {4}:{5} failed: '{6}'", e.SourceName, e.SourceGuid, e.SpellName, e.SpellId, e.DestName, e.DestGuid); } break; case "SPELL_AURA_APPLIED": case "SPELL_CAST_SUCCESS": if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Update the last spell we cast. So certain classes can 'switch' their logic around. Spell.LastSpellCast = e.SpellName; //Logger.WriteDebug("Successfully cast " + Spell.LastSpellCast); // Force a wait for all summoned minions. This prevents double-casting it. if (StyxWoW.Me.Class == WoWClass.Warlock && e.SpellName.StartsWith("Summon ")) { StyxWoW.SleepForLagDuration(); } break; case "SWING_MISSED": if (e.Args[11].ToString() == "EVADE") { Logger.Write("Mob is evading swing. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } else if (e.Args[11].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; case "SPELL_MISSED": case "RANGE_MISSED": // DoT casting spam can occur when running on test dummy with low +hit // .. and multiple misses occurring. this should help troubleshoot // .. false reports of flawed rotation if (SingularSettings.Instance.EnableDebugLogging) { Logging.WriteToFileSync(LogLevel.Diagnostic, "[CombatLog] {0} {1}#{2} {3}", e.Event, e.SpellName, e.SpellId, e.Args[14] ); } if (e.Args[14].ToString() == "EVADE") { Logger.Write("Mob is evading ranged attack. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } else if (e.Args[14].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; } }
private static void HandleEvadeBuggedMob(LuaEventArgs args, CombatLogEventArgs e) { WoWUnit unit = e.DestUnit; ulong guid = e.DestGuid; if (unit == null && StyxWoW.Me.CurrentTarget != null) { unit = StyxWoW.Me.CurrentTarget; guid = StyxWoW.Me.CurrentTargetGuid; Logging.WriteDiagnostic("Evade: bugged mob guid:{0}, so assuming current target instead", args.Args[7]); } if (unit != null) { if (!MobsThatEvaded.ContainsKey(unit.Guid)) { MobsThatEvaded.Add(unit.Guid, 0); } MobsThatEvaded[unit.Guid]++; if (MobsThatEvaded[unit.Guid] <= 5) { Logging.WriteDiagnostic("Mob {0} has evaded {1} times. Keeping an eye on {2:X0} for now!", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid); } else { const int MinutesToBlacklist = 5; if (Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logging.WriteDiagnostic("Mob {0} has evaded {1} times. Previously blacklisted {2:X0} for {3} minutes!", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid, MinutesToBlacklist); } else { Logging.Write("Mob {0} has evaded {1} times. Blacklisting {2:X0} for {3} minutes!", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid, MinutesToBlacklist); Blacklist.Add(unit.Guid, BlacklistFlags.Combat, TimeSpan.FromMinutes(MinutesToBlacklist)); if (!Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logging.Write("error: blacklist does not contain entry for {0} so adding {1}", unit.SafeName(), unit.Guid); } } if (BotPoi.Current.Guid == unit.Guid) { Logging.WriteDiagnostic("EvadeHandling: Current BotPOI type={0} is Evading, clearing now...", BotPoi.Current.Type); BotPoi.Clear("Singular recognized Evade bugged mob"); } if (StyxWoW.Me.CurrentTargetGuid == guid) { foreach (var target in Targeting.Instance.TargetList) { if (target.IsAlive && Unit.ValidUnit(target) && !Blacklist.Contains(target, BlacklistFlags.Combat)) { Logging.Write("Setting target to {0} to get off evade bugged mob!", target.SafeName()); target.Target(); return; } } Logging.Write("BotBase has 0 entries in Target list not blacklisted -- nothing else we can do at this point!"); // StyxWoW.Me.ClearTarget(); } } } /// line below was originally in Evade logic, but commenting to avoid Sleeps // StyxWoW.SleepForLagDuration(); }
private static void HandleCombatLog(object sender, LuaEventArgs args) { if (RoutineManager.Current.Name != AdvancedAI.Instance.Name) { return; } var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName); switch (e.Event) { // spell_cast_failed only passes filter in Singular debug mode case "SPELL_CAST_FAILED": Logging.WriteDiagnostic("[CombatLog] {0} {1}#{2} failure: '{3}'", e.Event, e.Spell.Name, e.SpellId, e.Args[14]); if (e.Args[14].ToString() == LocalizedLineOfSightFailure) { ulong guid; try { LastLineOfSightTarget = e.DestUnit; guid = LastLineOfSightTarget == null ? 0 : LastLineOfSightTarget.Guid; } catch { LastLineOfSightTarget = StyxWoW.Me.CurrentTarget; guid = StyxWoW.Me.CurrentTargetGuid; } LastLineOfSightFailure = DateTime.Now; Logging.WriteDiagnostic("[CombatLog] cast fail due to los reported at {0} on target {1:X}", LastLineOfSightFailure.ToString("HH:mm:ss.fff"), e.DestGuid); } else if (StyxWoW.Me.Class == WoWClass.Druid) { if (LocalizedShapeshiftMessages.ContainsKey(e.Args[14].ToString())) { string symbolicName = LocalizedShapeshiftMessages[e.Args[14].ToString()]; LastShapeshiftFailure = DateTime.Now; Logging.WriteDiagnostic("[CombatLog] cast fail due to shapeshift error '{0}' while questing reported at {1}", symbolicName, LastShapeshiftFailure.ToString("HH:mm:ss.fff")); } } else if (StyxWoW.Me.Class == WoWClass.Rogue) { if (e.Args[14].ToString() == LocalizedNoPocketsToPickFailure) { // args on this event don't match standard SPELL_CAST_FAIL // -- so, Singular only casts on current target so use that assumption WoWUnit unit = StyxWoW.Me.CurrentTarget; if (unit == null) { Logging.WriteDiagnostic("[CombatLog] has no pockets event did not have a valid unit"); } else { Logging.WriteDiagnostic("[CombatLog] {0} has no pockets, blacklisting from pick pocket for 2 minutes", unit.SafeName()); Blacklist.Add(unit.Guid, BlacklistFlags.Node, TimeSpan.FromMinutes(2)); } } } break; #if SOMEONE_USES_LAST_SPELL_AT_SOME_POINT case "SPELL_AURA_APPLIED": case "SPELL_CAST_SUCCESS": if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Update the last spell we cast. So certain classes can 'switch' their logic around. Spell.LastSpellCast = e.SpellName; //Logger.WriteDebug("Successfully cast " + Spell.LastSpellCast); // following commented block should not be needed since rewrite of Pet summon // //// Force a wait for all summoned minions. This prevents double-casting it. //if (StyxWoW.Me.Class == WoWClass.Warlock && e.SpellName.StartsWith("Summon ")) //{ // StyxWoW.SleepForLagDuration(); //} break; #endif case "SWING_MISSED": if (e.Args[11].ToString() == "EVADE") { HandleEvadeBuggedMob(args, e); } else if (e.Args[11].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logging.WriteDiagnostic("{0} is immune to Physical spell school", unit.Name); SpellImmunityManager.Add(unit.Entry, WoWSpellSchool.Physical); } } break; case "SPELL_MISSED": case "RANGE_MISSED": if (e.Args[14].ToString() == "EVADE") { HandleEvadeBuggedMob(args, e); } else if (e.Args[14].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logging.WriteDiagnostic("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; } }