Example #1
0
        internal static void UpdateStats(PlayerSubStats stats, HitRecord record, double beginTime)
        {
            switch (record.Type)
            {
            case Labels.BANE:
                stats.BaneHits++;
                stats.Hits += 1;
                break;

            case Labels.MISS:
                stats.Misses++;
                stats.MeleeAttempts += 1;
                break;

            case Labels.PROC:
            case Labels.DOT:
            case Labels.DD:
            case Labels.HOT:
            case Labels.HEAL:
            case Labels.DS:
                stats.Hits += 1;
                break;

            default:
                stats.Hits += 1;
                stats.MeleeHits++;
                stats.MeleeAttempts += 1;
                break;
            }

            if (record.Total > 0)
            {
                stats.Total += record.Total;
                stats.Max    = Math.Max(stats.Max, record.Total);
            }

            if (record.Total > 0 && record.OverTotal > 0)
            {
                stats.Extra += (record.OverTotal - record.Total);
            }

            LineModifiersParser.Parse(record, stats);

            stats.BeginTime = double.IsNaN(stats.BeginTime) ? beginTime : stats.BeginTime;
            stats.LastTime  = beginTime;
        }
Example #2
0
        private static DamageRecord ParseDamage(string actionPart)
        {
            DamageRecord record    = null;
            ParseType    parseType = ParseType.UNKNOWN;

            string withoutMods    = actionPart;
            int    modifiersIndex = -1;

            if (actionPart[actionPart.Length - 1] == ')')
            {
                // using 4 here since the shortest modifier should at least be 3 even in the future. probably.
                modifiersIndex = actionPart.LastIndexOf('(', actionPart.Length - 4);
                if (modifiersIndex > -1)
                {
                    withoutMods = actionPart.Substring(0, modifiersIndex);
                }
            }

            int  pointsIndex = -1;
            int  forIndex    = -1;
            int  fromIndex   = -1;
            int  byIndex     = -1;
            int  takenIndex  = -1;
            int  hitIndex    = -1;
            int  extraIndex  = -1;
            int  isAreIndex  = -1;
            bool nonMelee    = false;

            List <string> nameList = new List <string>();
            StringBuilder builder  = new StringBuilder();
            var           data     = withoutMods.Split(' ');

            SpellResist resist = SpellResist.UNDEFINED;

            for (int i = 0; i < data.Length; i++)
            {
                switch (data[i])
                {
                case "taken":
                    takenIndex = i;

                    int test1 = i - 1;
                    if (test1 > 0 && data[test1] == "has")
                    {
                        parseType = ParseType.HASTAKEN;

                        int test2 = i + 2;
                        if (data.Length > test2 && data[test2] == "extra" && data[test2 - 1] == "an")
                        {
                            extraIndex = test2;
                        }
                    }
                    else if (test1 >= 1 && data[test1] == "have" && data[test1 - 1] == "You")
                    {
                        parseType = ParseType.YOUHAVETAKEN;
                    }
                    break;

                case "by":
                    byIndex = i;
                    break;

                case "non-melee":
                    nonMelee = true;
                    break;

                case "is":
                case "are":
                    isAreIndex = i;
                    break;

                case "for":
                    int next = i + 1;
                    if (data.Length > next && data[next].Length > 0 && char.IsNumber(data[next][0]))
                    {
                        forIndex = i;
                    }
                    break;

                case "from":
                    fromIndex = i;
                    break;

                case "points":
                    int ofIndex = i + 1;
                    if (ofIndex < data.Length && data[ofIndex] == "of")
                    {
                        parseType   = ParseType.POINTSOF;
                        pointsIndex = i;

                        int resistIndex = ofIndex + 1;
                        if (resistIndex < data.Length && SpellResistMap.TryGetValue(data[resistIndex], out SpellResist value))
                        {
                            resist   = value;
                            nonMelee = true;
                        }
                    }
                    break;

                default:
                    if (HitMap.ContainsKey(data[i]))
                    {
                        hitIndex = i;
                    }
                    break;
                }
            }

            if (parseType == ParseType.POINTSOF && forIndex > -1 && forIndex < pointsIndex && hitIndex > -1)
            {
                record = ParsePointsOf(data, nonMelee, forIndex, byIndex, hitIndex, builder, nameList);
            }
            else if (parseType == ParseType.HASTAKEN && takenIndex < fromIndex && fromIndex > -1)
            {
                record = ParseHasTaken(data, takenIndex, fromIndex, byIndex, builder);
            }
            else if (parseType == ParseType.POINTSOF && extraIndex > -1 && takenIndex > -1 && takenIndex < fromIndex)
            {
                record = ParseExtra(data, takenIndex, extraIndex, fromIndex, nameList);
            }
            // there are more messages without a specificied attacker or spell but do these first
            else if (parseType == ParseType.YOUHAVETAKEN && takenIndex > -1 && fromIndex > -1 && byIndex > fromIndex)
            {
                record = ParseYouHaveTaken(data, takenIndex, fromIndex, byIndex, builder);
            }
            else if (parseType == ParseType.POINTSOF && isAreIndex > -1 && byIndex > isAreIndex && forIndex > byIndex)
            {
                record = ParseDS(data, isAreIndex, byIndex, forIndex);
            }

            if (record != null && modifiersIndex > -1)
            {
                record.ModifiersMask = LineModifiersParser.Parse(actionPart.Substring(modifiersIndex + 1, actionPart.Length - 1 - modifiersIndex - 1));
            }

            return(ValidateDamage(record, resist));
        }
Example #3
0
        private static DamageRecord ParseMiss(string actionPart, int index)
        {
            // [Mon Aug 05 02:05:12 2019] An enchanted Syldon stalker tries to crush YOU, but misses! (Strikethrough)
            // [Sat Aug 03 00:20:57 2019] You try to crush a Kar`Zok soldier, but miss! (Riposte Strikethrough)
            DamageRecord record = null;

            string withoutMods    = actionPart;
            int    modifiersIndex = -1;

            if (actionPart[actionPart.Length - 1] == ')')
            {
                // using 4 here since the shortest modifier should at least be 3 even in the future. probably.
                modifiersIndex = actionPart.LastIndexOf('(', actionPart.Length - 4);
                if (modifiersIndex > -1)
                {
                    withoutMods = actionPart.Substring(0, modifiersIndex);
                }
            }

            int tryStartIndex;
            int hitStartIndex = -1;
            int missesIndex   = index - LineParsing.ACTIONINDEX;

            if (withoutMods[0] == 'Y' && withoutMods[1] == 'o' && withoutMods[2] == 'u')
            {
                tryStartIndex = 3;
                hitStartIndex = 11;
            }
            else
            {
                tryStartIndex = withoutMods.IndexOf(" tries to ", StringComparison.Ordinal);
                if (tryStartIndex > -1)
                {
                    hitStartIndex = tryStartIndex + 10;
                }
            }

            if (tryStartIndex > -1 && hitStartIndex > -1 && tryStartIndex < missesIndex)
            {
                int hitEndIndex = withoutMods.IndexOf(" ", hitStartIndex, StringComparison.Ordinal);
                if (hitEndIndex > -1)
                {
                    string hit = withoutMods.Substring(hitStartIndex, hitEndIndex - hitStartIndex);

                    string subType = GetTypeFromHit(hit, out bool additional);
                    if (subType != null)
                    {
                        int hitLength = hit.Length + (additional ? 3 : 0);

                        // check for pets
                        string attacker  = withoutMods.Substring(0, tryStartIndex);
                        int    defStart  = hitStartIndex + hitLength + 1;
                        int    missesEnd = missesIndex - defStart;

                        if (missesEnd > 0)
                        {
                            string defender = withoutMods.Substring(defStart, missesEnd);
                            HasOwner(attacker, out string attackerOwner);
                            HasOwner(defender, out string defenderOwner);

                            if (attacker != null && defender != null)
                            {
                                record = BuildRecord(attacker, defender, 0, attackerOwner, defenderOwner, subType, Labels.MISS);
                            }

                            if (record != null && modifiersIndex > -1)
                            {
                                record.ModifiersMask = LineModifiersParser.Parse(actionPart.Substring(modifiersIndex + 1, actionPart.Length - 1 - modifiersIndex - 1));
                            }
                        }
                    }
                }
            }

            return(ValidateDamage(record));
        }
Example #4
0
        private static HealRecord HandleHealed(ProcessLine pline)
        {
            // [Sun Feb 24 21:00:58 2019] Foob's promised interposition is fulfilled Foob healed himself for 44238 hit points by Promised Interposition Heal V. (Lucky Critical)
            // [Sun Feb 24 21:01:01 2019] Rowanoak is soothed by Brell's Soothing Wave. Farzi healed Rowanoak for 524 hit points by Brell's Sacred Soothing Wave.
            // [Sun Feb 24 21:00:52 2019] Kuvani healed Tolzol over time for 11000 hit points by Spirit of the Wood XXXIV.
            // [Sun Feb 24 21:00:52 2019] Kuvani healed Foob over time for 9409 (11000) hit points by Spirit of the Wood XXXIV.
            // [Sun Feb 24 21:00:58 2019] Fllint healed Foob for 11820 hit points by Blessing of the Ancients III.
            // [Sun Feb 24 21:01:00 2019] Tolzol healed itself for 548 hit points.
            // [Sun Feb 24 21:01:01 2019] Piemastaj`s pet has been healed for 15000 hit points by Enhanced Theft of Essence Effect X.
            // [Sun Feb 24 23:30:51 2019] Piemastaj`s pet glows with holy light. Findawenye healed Piemastaj`s pet for 2823 (78079) hit points by Mending Splash Rk. III. (Critical)
            // [Mon Feb 18 21:21:12 2019] Nylenne has been healed over time for 8211 hit points by Roar of the Lion 6.
            // [Mon Feb 18 21:20:39 2019] You have been healed over time for 1063 (8211) hit points by Roar of the Lion 6.
            // [Mon Feb 18 21:17:35 2019] Snowzz healed Malkatar over time for 8211 hit points by Roar of the Lion 6.
            // [Wed Nov 06 14:19:54 2019] Your ward heals you as it breaks! You healed Niktaza for 8970 (86306) hit points by Healing Ward. (Critical)

            HealRecord record   = null;
            string     part     = pline.ActionPart;
            int        optional = pline.OptionalIndex;
            string     test     = part.Substring(0, optional);

            bool   done     = false;
            string healer   = "";
            string healed   = "";
            string spell    = null;
            string type     = Labels.HEAL;
            uint   heal     = 0;
            uint   overHeal = 0;

            int previous = test.Length >= 2 ? test.LastIndexOf(" ", test.Length - 2, StringComparison.Ordinal) : -1;

            if (previous > -1)
            {
                if (test.IndexOf("are ", previous + 1, StringComparison.Ordinal) > -1)
                {
                    done = true;
                }
                else if (previous - 1 >= 0 && (test[previous - 1] == '.' || test[previous - 1] == '!') || previous - 9 > 0 && test.IndexOf("fulfilled", previous - 9, StringComparison.Ordinal) > -1)
                {
                    healer = test.Substring(previous + 1);
                }
                else if (previous - 4 >= 0 && test.IndexOf("has been", previous - 3, StringComparison.Ordinal) > -1)
                {
                    healed = test.Substring(0, previous - 4);

                    if (part.Length > optional + 17 && part.IndexOf("over time", optional + 8, 9, StringComparison.Ordinal) > -1)
                    {
                        type = Labels.HOT;
                    }
                }
                else if (previous - 5 >= 0 && test.IndexOf("have been", previous - 4, StringComparison.Ordinal) > -1)
                {
                    healed = test.Substring(0, previous - 5);

                    if (part.Length > optional + 17 && part.IndexOf("over time", optional + 8, 9, StringComparison.Ordinal) > -1)
                    {
                        type = Labels.HOT;
                    }
                }
            }
            else
            {
                healer = test.Substring(0, optional);
            }

            if (!done)
            {
                int amountIndex = -1;
                if (healed.Length == 0)
                {
                    int afterHealed = optional + 8;
                    int forIndex    = part.IndexOf(" for ", afterHealed, StringComparison.Ordinal);

                    if (forIndex > 1)
                    {
                        if (forIndex - 9 >= 0 && part.IndexOf("over time", forIndex - 9, StringComparison.Ordinal) > -1)
                        {
                            type   = Labels.HOT;
                            healed = part.Substring(afterHealed, forIndex - afterHealed - 10);
                        }
                        else
                        {
                            healed = part.Substring(afterHealed, forIndex - afterHealed);
                        }

                        amountIndex = forIndex + 5;
                    }
                }
                else
                {
                    if (type == Labels.HEAL)
                    {
                        amountIndex = optional + 12;
                    }
                    else if (type == Labels.HOT)
                    {
                        amountIndex = optional + 22;
                    }
                }

                if (amountIndex > -1)
                {
                    int amountEnd = part.IndexOf(" ", amountIndex, StringComparison.Ordinal);
                    if (amountEnd > -1)
                    {
                        uint value = StatsUtil.ParseUInt(part.Substring(amountIndex, amountEnd - amountIndex));
                        if (value != uint.MaxValue)
                        {
                            heal = value;
                        }

                        int overEnd = -1;
                        if (part.Length > amountEnd + 1 && part[amountEnd + 1] == '(')
                        {
                            overEnd = part.IndexOf(")", amountEnd + 2, StringComparison.Ordinal);
                            if (overEnd > -1)
                            {
                                uint value2 = StatsUtil.ParseUInt(part.Substring(amountEnd + 2, overEnd - amountEnd - 2));
                                if (value2 != uint.MaxValue)
                                {
                                    overHeal = value2;
                                }
                            }
                        }

                        int rest    = overEnd > -1 ? overEnd : amountEnd;
                        int byIndex = part.IndexOf(" by ", rest, StringComparison.Ordinal);
                        if (byIndex > -1)
                        {
                            int periodIndex = part.LastIndexOf(".", StringComparison.Ordinal);
                            if (periodIndex > -1 && periodIndex - byIndex - 4 > 0)
                            {
                                spell = part.Substring(byIndex + 4, periodIndex - byIndex - 4);
                            }
                        }
                    }
                }

                if (healed.Length > 0)
                {
                    // check for pets
                    int possessive = healed.IndexOf("`s ", StringComparison.Ordinal);
                    if (possessive > -1)
                    {
                        if (PlayerManager.Instance.IsVerifiedPlayer(healed.Substring(0, possessive)))
                        {
                            PlayerManager.Instance.AddVerifiedPet(healed);
                        }

                        // dont count swarm pets
                        healer = "";
                        heal   = 0;
                    }

                    if (healer.Length > 0 && heal != 0)
                    {
                        record = new HealRecord()
                        {
                            Total         = heal,
                            OverTotal     = overHeal,
                            Healer        = string.Intern(healer),
                            Healed        = string.Intern(healed),
                            Type          = string.Intern(type),
                            ModifiersMask = -1
                        };

                        record.SubType = string.IsNullOrEmpty(spell) ? Labels.SELFHEAL : string.Intern(spell);

                        if (part[part.Length - 1] == ')')
                        {
                            // using 4 here since the shortest modifier should at least be 3 even in the future. probably.
                            int firstParen = part.LastIndexOf('(', part.Length - 4);
                            if (firstParen > -1)
                            {
                                record.ModifiersMask = LineModifiersParser.Parse(part.Substring(firstParen + 1, part.Length - 1 - firstParen - 1));
                                if (LineModifiersParser.IsTwincast(record.ModifiersMask))
                                {
                                    PlayerManager.Instance.AddVerifiedPlayer(record.Healer);
                                }
                            }
                        }
                    }
                }
            }

            return(record);
        }
        private static bool CreateDamageRecord(LineData lineData, string[] split, int stop, string attacker, string defender,
                                               uint damage, string type, string subType, SpellResist resist = SpellResist.UNDEFINED, bool attackerIsSpell = false)
        {
            bool success = false;

            if (damage != uint.MaxValue && !string.IsNullOrEmpty(type) && !string.IsNullOrEmpty(subType) && !InIgnoreList(defender))
            {
                // Needed to replace 'You' and 'you', etc
                defender = PlayerManager.Instance.ReplacePlayer(defender, defender);

                if (string.IsNullOrEmpty(attacker))
                {
                    attacker = subType;
                }
                else if (attacker.EndsWith("'s corpse", StringComparison.Ordinal))
                {
                    attacker = attacker.Substring(0, attacker.Length - 9);
                }
                else
                {
                    // Needed to replace 'You' and 'you', etc
                    attacker = PlayerManager.Instance.ReplacePlayer(attacker, attacker);
                }

                if (resist != SpellResist.UNDEFINED && ConfigUtil.PlayerName == attacker && defender != attacker)
                {
                    DataManager.Instance.UpdateNpcSpellResistStats(defender, resist);
                }

                // check for pets
                HasOwner(attacker, out string attackerOwner);
                HasOwner(defender, out string defenderOwner);

                DamageRecord record = new DamageRecord
                {
                    Attacker      = string.Intern(FixName(attacker)),
                    Defender      = string.Intern(FixName(defender)),
                    Type          = string.Intern(type),
                    SubType       = string.Intern(subType),
                    Total         = damage,
                    AttackerOwner = attackerOwner != null?string.Intern(attackerOwner) : null,
                                        DefenderOwner = defenderOwner != null?string.Intern(defenderOwner) : null,
                                                            ModifiersMask   = -1,
                                                            AttackerIsSpell = attackerIsSpell
                };

                var currentTime = DateUtil.ParseLogDate(lineData.Line, out string timeString);

                if (split.Length > stop + 1)
                {
                    // improve this later so maybe the string doesn't have to be re-joined
                    string modifiers = string.Join(" ", split, stop + 1, split.Length - stop - 1);
                    record.ModifiersMask = LineModifiersParser.Parse(record.Attacker, modifiers.Substring(1, modifiers.Length - 2), currentTime);
                }

                if (!double.IsNaN(currentTime))
                {
                    // handle old style crits for eqemu
                    if (LastCrit != null && LastCrit.Attacker == record.Attacker && LastCrit.LineData.LineNumber == (lineData.LineNumber - 1))
                    {
                        var critTime = DateUtil.ParseLogDate(LastCrit.LineData.Line, out string _);
                        if (!double.IsNaN(critTime) && (currentTime - critTime) <= 1)
                        {
                            record.ModifiersMask = (record.ModifiersMask == -1) ? LineModifiersParser.CRIT : record.ModifiersMask | LineModifiersParser.CRIT;
                        }

                        LastCrit = null;
                    }

                    CheckSlainQueue(currentTime);

                    DamageProcessedEvent e = new DamageProcessedEvent()
                    {
                        Record = record, OrigTimeString = timeString, BeginTime = currentTime
                    };
                    EventsDamageProcessed?.Invoke(record, e);
                    success = true;

                    if (record.Type == Labels.DD && SpecialCodes.Keys.FirstOrDefault(special => !string.IsNullOrEmpty(record.SubType) && record.SubType.Contains(special)) is string key &&
                        !string.IsNullOrEmpty(key))
                    {
                        DataManager.Instance.AddSpecial(new SpecialSpell()
                        {
                            Code = SpecialCodes[key], Player = record.Attacker, BeginTime = currentTime
                        });
                    }
                }
            }

            return(success);
        }