Beispiel #1
0
        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;
                        }
                    }
                }
            }

            // 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;

            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("Storing {0} as last spell 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;

            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, e.Spell);
                    }
                }
                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, e.Spell);
                    }

                    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":
                if (StyxWoW.Me.CurrentTarget != null && e.DestGuid == StyxWoW.Me.CurrentTarget.Guid)
                {
                    Spell.LastSpellCast = "";
                }

                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)
        {
            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;
            }
        }