Beispiel #1
0
        private static DamageRecord ParseDS(string[] data, int isAreIndex, int byIndex, int forIndex)
        {
            DamageRecord record = null;

            string defender = string.Join(" ", data, 0, isAreIndex);
            uint   damage   = StatsUtil.ParseUInt(data[forIndex + 1]);

            string attacker;

            if (data[byIndex + 1] == "YOUR")
            {
                attacker = "you";
            }
            else
            {
                attacker = string.Join(" ", data, byIndex + 1, forIndex - byIndex - 2);
                attacker = attacker.Substring(0, attacker.Length - 2);
            }

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

            if (attacker != null && defender != null)
            {
                record = BuildRecord(attacker, defender, damage, attackerOwner, defenderOwner, Labels.DS, Labels.DS);
            }

            return(record);
        }
Beispiel #2
0
        private static DamageRecord ParseHasTaken(string[] data, int takenIndex, int fromIndex, int byIndex, StringBuilder builder)
        {
            DamageRecord record = null;

            uint   damage   = StatsUtil.ParseUInt(data[takenIndex + 1]);
            string defender = string.Join(" ", data, 0, takenIndex - 1);

            string spell    = null;
            string attacker = null;

            if (byIndex > -1 && fromIndex < byIndex)
            {
                spell    = string.Join(" ", data, fromIndex + 1, byIndex - fromIndex - 1);
                attacker = ReadStringToPeriod(data, byIndex, builder);
            }
            else if (data[fromIndex + 1] == "your")
            {
                spell    = ReadStringToPeriod(data, fromIndex + 1, builder);
                attacker = "you";
            }

            if (attacker != null && spell != null)
            {
                // check for pets
                HasOwner(attacker, out string attackerOwner);
                HasOwner(defender, out string defenderOwner);

                if (attacker != null && defender != null)
                {
                    record = BuildRecord(attacker, defender, damage, attackerOwner, defenderOwner, spell, GetTypeFromSpell(spell, Labels.DOT));
                }
            }

            return(record);
        }
Beispiel #3
0
        private static DamageRecord ParseExtra(string[] data, int takenIndex, int extraIndex, int fromIndex, List <string> nameList)
        {
            DamageRecord record = null;

            uint   damage   = StatsUtil.ParseUInt(data[extraIndex + 1]);
            string defender = string.Join(" ", data, 0, takenIndex - 1);

            string attacker = null;
            string spell    = null;

            if (data.Length > fromIndex + 1)
            {
                int person = fromIndex + 1;
                if (data[person] == "your")
                {
                    attacker = "you";
                }
                else
                {
                    int len = data[person].Length;
                    if (len > 2 && data[person][len - 2] == '\'' && data[person][len - 1] == 's')
                    {
                        attacker = data[person].Substring(0, len - 2);
                    }
                }

                if (attacker != null)
                {
                    nameList.Clear();
                    for (int i = person + 1; i < data.Length; i++)
                    {
                        if (data[i] == "spell.")
                        {
                            break;
                        }
                        else
                        {
                            nameList.Add(data[i]);
                        }
                    }

                    spell = string.Join(" ", nameList);
                }
            }

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

            if (attacker != null && defender != null)
            {
                record = BuildRecord(attacker, defender, damage, attackerOwner, defenderOwner, spell, Labels.BANE);
            }

            return(record);
        }
        private static DamageRecord ParseHasTaken(string[] data, int takenIndex, int fromIndex, int byIndex, StringBuilder builder)
        {
            DamageRecord record = null;

            uint   damage   = StatsUtil.ParseUInt(data[takenIndex + 1]);
            string defender = string.Join(" ", data, 0, takenIndex - 1);

            string spell    = null;
            string attacker = null;

            if (byIndex > -1 && fromIndex < byIndex)
            {
                attacker = ReadStringToPeriod(data, byIndex, builder);

                if (fromIndex > -1)
                {
                    spell = string.Join(" ", data, fromIndex + 1, byIndex - fromIndex - 1);
                }
                else
                {
                    spell = attacker;
                    var spellData = DataManager.Instance.GetSpellByName(spell);
                    if (spellData != null && ((spellData.ClassMask > 0 && spellData.Level < 255) || spellData.NameAbbrv != spellData.Name))
                    {
                        attacker = Labels.UNK;
                    }
                }
            }
            else if (fromIndex > -1 && data[fromIndex + 1] == "your")
            {
                spell    = ReadStringToPeriod(data, fromIndex + 1, builder);
                attacker = "you";
            }

            if (attacker != null && spell != null)
            {
                // check for pets
                HasOwner(attacker, out string attackerOwner);
                HasOwner(defender, out string defenderOwner);

                if (attacker != null && defender != null)
                {
                    record = BuildRecord(attacker, defender, damage, attackerOwner, defenderOwner, spell, GetTypeFromSpell(spell, Labels.DOT));
                }
            }

            return(record);
        }
Beispiel #5
0
        private static DamageRecord ParseYouHaveTaken(string[] data, int takenIndex, int fromIndex, int byIndex, StringBuilder builder)
        {
            DamageRecord record = null;

            string defender = "you";
            string attacker = ReadStringToPeriod(data, byIndex, builder);
            string spell    = string.Join(" ", data, fromIndex + 1, byIndex - fromIndex - 1);
            uint   damage   = StatsUtil.ParseUInt(data[takenIndex + 1]);

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

            if (attacker != null && defender != null)
            {
                record = BuildRecord(attacker, defender, damage, attackerOwner, null, spell, GetTypeFromSpell(spell, Labels.DD));
            }

            return(record);
        }
        private static bool ParseCurrency(string[] pieces, int startIndex, int toIndex, out string item, out uint count)
        {
            bool parsed = true;

            item  = null;
            count = 0;

            List <string> tmp = new List <string>();

            for (int i = startIndex; i < toIndex; i += 2)
            {
                if (pieces[i] == "and")
                {
                    i -= 1;
                    continue;
                }

                if (StatsUtil.ParseUInt(pieces[i]) is uint value && Currency.FirstOrDefault(curr => pieces[i + 1].StartsWith(curr, StringComparison.OrdinalIgnoreCase)) is string type)
                {
                    tmp.Add(pieces[i] + " " + type);
                    count += value * Rates[pieces[i + 1][0]];
                }
        private static DamageRecord ParseYouHaveTaken(string[] data, int takenIndex, int fromIndex, int byIndex, StringBuilder builder)
        {
            DamageRecord record = null;

            string defender = "you";
            string attacker = null;
            string spell    = null;

            if (byIndex == -1)
            {
                spell = ReadStringToPeriod(data, fromIndex, builder);
                var spellData = DataManager.Instance.GetSpellByName(spell);
                if (spellData != null && ((spellData.ClassMask > 0 && spellData.Level < 255) || spellData.NameAbbrv != spellData.Name))
                {
                    defender = null;
                }
                else
                {
                    attacker = spell;
                }
            }
            else
            {
                attacker = ReadStringToPeriod(data, byIndex, builder);
                spell    = string.Join(" ", data, fromIndex + 1, byIndex - fromIndex - 1);
            }

            uint damage = StatsUtil.ParseUInt(data[takenIndex + 1]);

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

            if (attacker != null && defender != null)
            {
                record = BuildRecord(attacker, defender, damage, attackerOwner, null, spell, GetTypeFromSpell(spell, Labels.DD));
            }

            return(record);
        }
Beispiel #8
0
        private static DamageRecord ParsePointsOf(string[] data, bool isNonMelee, int forIndex, int byIndex, int hitIndex, StringBuilder builder, List <string> nameList)
        {
            DamageRecord record   = null;
            uint         damage   = StatsUtil.ParseUInt(data[forIndex + 1]);
            string       type     = null;
            string       subType  = null;
            string       attacker = null;

            if (byIndex > 1)
            {
                // possible spell
                subType = ReadStringToPeriod(data, byIndex, builder);
            }

            // before hit
            nameList.Clear();
            for (int i = hitIndex - 1; i >= 0; i--)
            {
                if (data[hitIndex].EndsWith(".", StringComparison.Ordinal))
                {
                    break;
                }
                else
                {
                    nameList.Insert(0, data[i]);
                }
            }

            if (nameList.Count > 0)
            {
                attacker = string.Join(" ", nameList);
            }

            if (!isNonMelee)
            {
                subType = GetTypeFromHit(data[hitIndex], out bool additional);
                if (subType != null)
                {
                    type = Labels.MELEE;

                    if (additional)
                    {
                        hitIndex++; // multi-word hit value
                    }
                }
            }

            if (!string.IsNullOrEmpty(subType) && isNonMelee)
            {
                type = GetTypeFromSpell(subType, Labels.DD);
            }


            string defender = string.Join(" ", data, hitIndex + 1, forIndex - hitIndex - 1);

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

            // some new special cases
            if (!string.IsNullOrEmpty(subType) && subType.StartsWith("Elemental Conversion", StringComparison.Ordinal))
            {
                PlayerManager.Instance.AddVerifiedPet(defender);
            }
            else if (!string.IsNullOrEmpty(attacker) && !string.IsNullOrEmpty(defender))
            {
                record = BuildRecord(attacker, defender, damage, attackerOwner, defenderOwner, subType, type);
            }

            return(record);
        }
        public static void Process(LineData lineData)
        {
            bool handled = false;

            try
            {
                string[] split = lineData.Action.Split(' ');

                if (split != null && split.Length >= 2)
                {
                    // [Sun Mar 01 22:20:36 2020] A shaded torch has been awakened by Drogbaa.
                    // [Sun Mar 01 20:35:55 2020] The master looter, Qulas, looted 32426 platinum from the corpse.
                    // [Sun Mar 01 23:51:02 2020] You receive 129 platinum, 2 gold and 1 copper as your split (with a lucky bonus).
                    // [Sun Feb 02 22:43:51 2020] You receive 28 platinum, 7 gold, 2 silver and 5 copper as your split.
                    // [Sun Feb 02 23:31:23 2020] You receive 57 platinum as your split.
                    // [Fri Feb 07 22:01:20 2020] --Kizant has looted a Lesser Engraved Velium Rune from Velden Dragonbane's corpse.--
                    // [Sat Feb 08 01:20:26 2020] --Proximoe has looted a Velium Infused Spider Silk from a restless devourer's corpse.--
                    // [Sat Feb 08 21:21:36 2020] --You have looted a Cold-Forged Cudgel from Queen Dracnia's corpse.--
                    // [Mon Apr 27 22:32:04 2020] Restless Tijoely resisted your Stormjolt Vortex Effect!
                    // [Mon Apr 27 20:51:22 2020] Kazint's Scorching Beam Rk. III spell has been reflected by a shadow reflection.
                    // [Sun Mar 28 19:42:46 2021] A Draconic Lava Chain Feet Ornament was given to Aldryn.

                    string looter          = null;
                    int    awakenedIndex   = -1;
                    int    lootedIndex     = -1;
                    int    masterLootIndex = -1;
                    int    receiveIndex    = -1;
                    int    resistedIndex   = -1;
                    int    isIndex         = -1;

                    for (int i = 0; i < split.Length && !handled; i++)
                    {
                        if (i == 0 && split[0].StartsWith("--", StringComparison.OrdinalIgnoreCase))
                        {
                            looter = split[0] == "--You" ? ConfigUtil.PlayerName : split[0].TrimStart('-');
                        }
                        else
                        {
                            switch (split[i])
                            {
                            case "awakened":
                                awakenedIndex = i;
                                break;

                            case "is":
                                isIndex = i;
                                break;

                            case "looted":
                                lootedIndex = i;
                                break;

                            case "looter,":
                                masterLootIndex = (i == 2 && split[1] == "master" && split[0] == "The") ? masterLootIndex = i + 1 : -1;
                                break;

                            case "receive":
                                receiveIndex = (i == 1 && split[0] == "You") ? i : -1;
                                break;

                            case "reflected":
                                if (split.Length > 6 && i >= 6 && i + 2 < split.Length && split[0].StartsWith(ConfigUtil.PlayerName, StringComparison.Ordinal) &&
                                    split[i - 1] == "been" && split[i - 2] == "has" && split[i - 3] == "spell" && split[i + 1] == "by")
                                {
                                    // var spell = string.Join(" ", split, 1, i - 4);
                                    var npc = string.Join(" ", split, i + 2, split.Length - i - 2).TrimEnd('.');
                                    DataManager.Instance.UpdateNpcSpellReflectStats(npc);
                                    handled = true;
                                }
                                break;

                            case "resisted":
                                resistedIndex = i;
                                break;

                            case "your":
                                if (resistedIndex > 0 && resistedIndex + 1 == i && split.Length > i + 1 && split[split.Length - 1].EndsWith("!", StringComparison.Ordinal))
                                {
                                    string npc   = string.Join(" ", split, 0, resistedIndex);
                                    string spell = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd('!');
                                    DataManager.Instance.AddResistRecord(new ResistRecord()
                                    {
                                        Defender = npc, Spell = spell
                                    }, DateUtil.ParseLogDate(lineData.Line));
                                    handled = true;
                                }
                                break;

                            case "by":
                                if (awakenedIndex > -1 && awakenedIndex == (i - 1) && split.Length > 5 && split[i - 2] == "been" && split[i - 3] == "has")
                                {
                                    string awakened = string.Join(" ", split, 0, i - 3);
                                    string breaker  = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd('.');
                                    DataManager.Instance.AddMiscRecord(new MezBreakRecord {
                                        Breaker = breaker, Awakened = awakened
                                    }, DateUtil.ParseLogDate(lineData.Line));
                                    handled = true;
                                }
                                else if (isIndex > 0 && StruckByTypes.ContainsKey(split[i - 1]))
                                {
                                    // ignore common lines like: is struck by
                                    handled = true;
                                }
                                break;

                            case "from":
                                if (masterLootIndex > -1 && lootedIndex > masterLootIndex && split.Length > lootedIndex + 1 && split.Length > 3)
                                {
                                    string name = split[3].TrimEnd(',');
                                    if (ParseCurrency(split, lootedIndex + 1, i, out string item, out uint count))
                                    {
                                        PlayerManager.Instance.AddVerifiedPlayer(name);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = name, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                else if (!string.IsNullOrEmpty(looter) && lootedIndex == 2 && split.Length > 4)
                                {
                                    // covers "a" or "an"
                                    uint   count = split[3][0] == 'a' ? 1 : StatsUtil.ParseUInt(split[3]);
                                    string item  = string.Join(" ", split, 4, i - 4);
                                    string npc   = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd(LootedFromTrim).Replace("'s corpse", "");

                                    if (count > 0 && count != ushort.MaxValue)
                                    {
                                        PlayerManager.Instance.AddVerifiedPlayer(looter);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = looter, Quantity = count, IsCurrency = false, Npc = npc
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                break;

                            case "given":
                                if (split[i - 1] == "was" && split.Length == (i + 3) && split[i + 1] == "to")
                                {
                                    string player = split[i + 2];
                                    if (player.Length > 3)
                                    {
                                        looter = player.Substring(0, player.Length - 1);
                                        looter = looter.Equals("you", StringComparison.OrdinalIgnoreCase) ? ConfigUtil.PlayerName : looter;
                                        string     item   = string.Join(" ", split, 1, i - 2);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = looter, Quantity = 0, IsCurrency = false, Npc = "Assigned (Not Looted)"
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                break;

                            case "split.":
                            case "split":
                                if (receiveIndex > -1 && split[i - 1] == "your" && split[i - 2] == "as")
                                {
                                    if (ParseCurrency(split, 2, i - 2, out string item, out uint count))
                                    {
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = ConfigUtil.PlayerName, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
            catch (ArgumentNullException ne)
            {
                LOG.Error(ne);
            }
            catch (NullReferenceException nr)
            {
                LOG.Error(nr);
            }
            catch (ArgumentOutOfRangeException aor)
            {
                LOG.Error(aor);
            }
            catch (ArgumentException ae)
            {
                LOG.Error(ae);
            }

            DebugUtil.UnregisterLine(lineData.LineNumber, handled);
        }
Beispiel #10
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);
        }
        public static void Process(LineData lineData)
        {
            try
            {
                string[] split = lineData.Action.Split(' ');

                if (split != null && split.Length > 2)
                {
                    // [Sun Mar 01 22:20:36 2020] A shaded torch has been awakened by Drogbaa.
                    // [Sun Mar 01 22:34:58 2020] You have entered The Eastern Wastes.
                    // [Sun Mar 01 20:35:55 2020] The master looter, Qulas, looted 32426 platinum from the corpse.
                    // [Sun Mar 01 23:51:02 2020] You receive 129 platinum, 2 gold and 1 copper as your split (with a lucky bonus).
                    // [Sun Feb 02 22:43:51 2020] You receive 28 platinum, 7 gold, 2 silver and 5 copper as your split.
                    // [Sun Feb 02 23:31:23 2020] You receive 57 platinum as your split.
                    // [Fri Feb 07 22:01:20 2020] --Kizant has looted a Lesser Engraved Velium Rune from Velden Dragonbane's corpse.--
                    // [Sat Feb 08 01:20:26 2020] --Proximoe has looted a Velium Infused Spider Silk from a restless devourer's corpse.--
                    // [Sat Feb 08 21:21:36 2020] --You have looted a Cold-Forged Cudgel from Queen Dracnia's corpse.--

                    string looter          = null;
                    int    awakenedIndex   = -1;
                    int    lootedIndex     = -1;
                    int    masterLootIndex = -1;
                    int    receiveIndex    = -1;
                    bool   handled         = false;

                    for (int i = 0; i < split.Length && !handled; i++)
                    {
                        if (i == 0 && split[0].StartsWith("--"))
                        {
                            looter = split[0] == "--You" ? ConfigUtil.PlayerName : split[0].TrimStart('-');
                        }
                        else
                        {
                            switch (split[i])
                            {
                            case "awakened":
                                awakenedIndex = i;
                                break;

                            case "looted":
                                lootedIndex = i;
                                break;

                            case "looter,":
                                masterLootIndex = (i == 2 && split[1] == "master" && split[0] == "The") ? masterLootIndex = i + 1 : -1;
                                break;

                            case "receive":
                                receiveIndex = (i == 1 && split[0] == "You") ? i : -1;
                                break;

                            case "by":
                                if (awakenedIndex > -1 && awakenedIndex == (i - 1) && split.Length > 5 && split[i - 2] == "been" && split[i - 3] == "has")
                                {
                                    string awakened = string.Join(" ", split, 0, i - 3);
                                    string breaker  = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd('.');
                                    DataManager.Instance.AddMiscRecord(new MezBreakRecord()
                                    {
                                        Breaker = breaker, Awakened = awakened
                                    }, DateUtil.ParseLogDate(lineData.Line));
                                    handled = true;
                                }
                                break;

                            case "entered":
                                if (i == 2 && split[1] == "have" && split[0] == "You" && split.Length > 2)
                                {
                                    string zone = string.Join(" ", split, 3, split.Length - 3).TrimEnd('.');
                                    DataManager.Instance.AddMiscRecord(new ZoneRecord()
                                    {
                                        Zone = zone
                                    }, DateUtil.ParseLogDate(lineData.Line));
                                    handled = true;
                                }
                                break;

                            case "from":
                                if (masterLootIndex > -1 && lootedIndex > masterLootIndex && split.Length > lootedIndex + 1 && split.Length > 3)
                                {
                                    string name = split[3].TrimEnd(',');
                                    if (ParseCurrency(split, lootedIndex + 1, i, out string item, out uint count))
                                    {
                                        PlayerManager.Instance.AddVerifiedPlayer(name);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = name, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                else if (!string.IsNullOrEmpty(looter) && lootedIndex == 2 && split.Length > 4)
                                {
                                    // covers "a" or "an"
                                    uint   count = split[3][0] == 'a' ? 1 : StatsUtil.ParseUInt(split[3]);
                                    string item  = string.Join(" ", split, 4, i - 4);
                                    string npc   = string.Join(" ", split, i + 1, split.Length - i - 1).TrimEnd(LootedFromTrim).Replace("'s corpse", "");

                                    if (count > 0 && count != ushort.MaxValue)
                                    {
                                        PlayerManager.Instance.AddVerifiedPlayer(looter);
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = looter, Quantity = count, IsCurrency = false, Npc = npc
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                break;

                            case "split":
                                if (receiveIndex > -1 && split[i - 1] == "your" && split[i - 2] == "as")
                                {
                                    if (ParseCurrency(split, 2, i - 2, out string item, out uint count))
                                    {
                                        LootRecord record = new LootRecord()
                                        {
                                            Item = item, Player = ConfigUtil.PlayerName, Quantity = count, IsCurrency = true
                                        };
                                        DataManager.Instance.AddLootRecord(record, DateUtil.ParseLogDate(lineData.Line));
                                        handled = true;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
            catch (ArgumentNullException ne)
            {
                LOG.Error(ne);
            }
            catch (NullReferenceException nr)
            {
                LOG.Error(nr);
            }
            catch (ArgumentOutOfRangeException aor)
            {
                LOG.Error(aor);
            }
            catch (ArgumentException ae)
            {
                LOG.Error(ae);
            }
        }
        public static void Process(LineData lineData)
        {
            bool handled = false;

            try
            {
                string[] split = lineData.Action.Split(' ');

                if (split != null && split.Length >= 2)
                {
                    int stop = split.Length - 1;
                    if (!string.IsNullOrEmpty(split[stop]) && split[stop][split[stop].Length - 1] == ')')
                    {
                        for (int i = stop; i >= 0 && stop > 2; i--)
                        {
                            if (!string.IsNullOrEmpty(split[i]) && split[i][0] == '(')
                            {
                                stop = i - 1;
                                break;
                            }
                        }
                    }

                    // see if it's a died message right away
                    if (split.Length > 1 && stop >= 1 && split[stop] == "died.")
                    {
                        var test = string.Join(" ", split, 0, stop);
                        if (!string.IsNullOrEmpty(test))
                        {
                            UpdateSlain(test, "", lineData);
                            handled = true;
                        }
                    }

                    if (!handled)
                    {
                        int    byIndex = -1, forIndex = -1, pointsOfIndex = -1, endDamage = -1, byDamage = -1, extraIndex = -1;
                        int    fromDamage = -1, hasIndex = -1, haveIndex = -1, hitType = -1, hitTypeAdd = -1, slainIndex = -1;
                        int    takenIndex = -1, tryIndex = -1, yourIndex = -1, isIndex = -1, dsIndex = -1, butIndex = -1;
                        int    missType = -1, nonMeleeIndex = -1;
                        string subType = null;

                        bool found = false;
                        for (int i = 0; i <= stop && !found; i++)
                        {
                            if (!string.IsNullOrEmpty(split[i]))
                            {
                                switch (split[i])
                                {
                                case "healed":
                                    found = true; // short circuit
                                    break;

                                case "but":
                                    butIndex = i;
                                    break;

                                case "is":
                                case "was":
                                    isIndex = i;
                                    break;

                                case "has":
                                    hasIndex = i;
                                    break;

                                case "have":
                                    haveIndex = i;
                                    break;

                                case "by":
                                    byIndex = i;

                                    if (slainIndex > -1)
                                    {
                                        found = true; // short circut
                                    }
                                    else if (i > 4 && split[i - 1] == "damage")
                                    {
                                        byDamage = i - 1;
                                    }
                                    break;

                                case "from":
                                    if (i > 3 && split[i - 1] == "damage")
                                    {
                                        fromDamage = i - 1;
                                        if (pointsOfIndex > -1 && extraIndex > -1)
                                        {
                                            found = true; // short circut
                                        }
                                        else if (stop > (i + 1) && split[i + 1] == "your")
                                        {
                                            yourIndex = i + 1;
                                        }
                                    }
                                    break;

                                case "damage.":
                                    if (i == stop)
                                    {
                                        endDamage = i;
                                    }
                                    break;

                                case "non-melee":
                                    nonMeleeIndex = i;
                                    if (i > 9 && stop == (i + 1) && split[i + 1] == "damage." && pointsOfIndex == (i - 2) && forIndex == (i - 4))
                                    {
                                        dsIndex = i - 5;
                                        found   = true; // short circut
                                    }
                                    break;

                                case "point":
                                case "points":
                                    if (stop >= (i + 1) && split[i + 1] == "of")
                                    {
                                        pointsOfIndex = i;
                                        if (i > 2 && split[i - 2] == "for")
                                        {
                                            forIndex = i - 2;
                                        }
                                    }
                                    break;

                                case "blocks!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 0 : missType;
                                    break;

                                case "shield!":
                                case "staff!":
                                    missType = (i > 5 && stop == i && butIndex > -1 && i > tryIndex && split[i - 2] == "with" &&
                                                split[i - 3].StartsWith("block", StringComparison.OrdinalIgnoreCase)) ? 0 : missType;
                                    break;

                                case "dodge!":
                                case "dodges!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 1 : missType;
                                    break;

                                case "miss!":
                                case "misses!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 2 : missType;
                                    break;

                                case "parries!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 3 : missType;
                                    break;

                                case "INVULNERABLE!":
                                    missType = (stop == i && butIndex > -1 && i > tryIndex) ? 4 : missType;
                                    break;

                                case "slain":
                                    slainIndex = i;
                                    break;

                                case "taken":
                                    if (i > 1 && (hasIndex == (i - 1) || haveIndex == (i - 1)))
                                    {
                                        takenIndex = i - 1;

                                        if (stop > (i + 2) && split[i + 1] == "an" && split[i + 2] == "extra")
                                        {
                                            extraIndex = i + 2;
                                        }
                                    }
                                    break;

                                // Old (EQEMU) crit and crippling blow handling
                                case "hit!":
                                    if (stop == i && split.Length > 4 && split[i - 1] == "critical" && split[i - 3] == "scores")
                                    {
                                        LastCrit = new OldCritData {
                                            Attacker = split[0], LineData = lineData
                                        };
                                    }
                                    break;

                                case "Crippling":
                                    if (stop == (i + 1) && split.Length > 4 && split[i + 1].StartsWith("Blow!") && split[i - 2] == "lands")
                                    {
                                        LastCrit = new OldCritData {
                                            Attacker = split[0], LineData = lineData
                                        };
                                    }
                                    break;

                                default:
                                    if (slainIndex == -1 && i > 0 && string.IsNullOrEmpty(subType) && HitMap.TryGetValue(split[i], out subType))
                                    {
                                        hitType = i;
                                        if (i < stop && HitAdditionalMap.ContainsKey(split[i]))
                                        {
                                            hitTypeAdd = i + i;
                                        }

                                        if (i > 2 && split[i - 1] == "to" && (split[i - 2] == "tries" || split[i - 2] == "try"))
                                        {
                                            tryIndex = i - 2;
                                        }
                                    }
                                    break;
                                }
                            }
                        }

                        // [Sun Apr 18 19:36:39 2021] Tantor is pierced by Tolzol's thorns for 6718 points of non-melee damage.
                        // [Mon Apr 19 22:02:52 2021] Honvar is tormented by Reisil's frost for 7809 points of non-melee damage.
                        // [Sun Apr 25 13:47:12 2021] Test One Hundred Three is burned by YOUR flames for 5224 points of non-melee damage.
                        // [Sun Apr 18 14:16:13 2021] A failed reclaimer is pierced by YOUR thorns for 193 points of non-melee damage.
                        if (dsIndex > -1 && pointsOfIndex > dsIndex && isIndex > -1 && isIndex < dsIndex && byIndex > isIndex)
                        {
                            string attacker = string.Join(" ", split, byIndex + 1, dsIndex - byIndex - 1);
                            if (!string.IsNullOrEmpty(attacker))
                            {
                                var valid = attacker == "YOUR";
                                if (!valid && attacker.EndsWith("'s", StringComparison.OrdinalIgnoreCase))
                                {
                                    attacker = attacker.Substring(0, attacker.Length - 2);
                                    valid    = true;
                                }

                                if (valid)
                                {
                                    string defender = string.Join(" ", split, 0, isIndex);
                                    uint   damage   = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                                    handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.DS, Labels.DS);
                                }
                            }
                        }
                        // [Mon May 10 22:18:46 2021] A dendridic shard was chilled to the bone for 410 points of non-melee damage.
                        else if (dsIndex > -1 && pointsOfIndex > dsIndex && isIndex > -1 && isIndex < dsIndex && byIndex == -1)
                        {
                            string defender = string.Join(" ", split, 0, isIndex);
                            uint   damage   = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                            handled = CreateDamageRecord(lineData, split, stop, Labels.RS, defender, damage, Labels.DS, Labels.DS);
                        }
                        // [Tue Mar 26 22:43:47 2019] a wave sentinel has taken an extra 6250000 points of non-melee damage from Kazint's Greater Fetter spell.
                        else if (extraIndex > -1 && pointsOfIndex == (extraIndex + 2) && fromDamage == (pointsOfIndex + 3) && split[stop] == "spell.")
                        {
                            if (split[fromDamage + 2].EndsWith("'s", StringComparison.OrdinalIgnoreCase))
                            {
                                string      attacker  = split[fromDamage + 2].Substring(0, split[fromDamage + 2].Length - 2);
                                string      defender  = string.Join(" ", split, 0, takenIndex);
                                uint        damage    = StatsUtil.ParseUInt(split[extraIndex + 1]);
                                string      spell     = string.Join(" ", split, fromDamage + 3, stop - fromDamage - 3);
                                var         spellData = DataManager.Instance.GetDamagingSpellByName(spell);
                                SpellResist resist    = spellData != null ? spellData.Resist : SpellResist.UNDEFINED;
                                handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.BANE, spell, resist);
                            }
                        }
                        // [Sun Apr 18 21:26:15 2021] Astralx crushes Sontalak for 126225 points of damage. (Strikethrough Critical)
                        // [Sun Apr 18 20:20:32 2021] Susarrak the Crusader claws Villette for 27699 points of damage. (Strikethrough Wild Rampage)
                        else if (!string.IsNullOrEmpty(subType) && endDamage > -1 && pointsOfIndex == (endDamage - 2) && forIndex > -1 && hitType < forIndex)
                        {
                            int    hitTypeMod = hitTypeAdd > 0 ? 1 : 0;
                            string attacker   = string.Join(" ", split, 0, hitType);
                            string defender   = string.Join(" ", split, hitType + hitTypeMod + 1, forIndex - hitType - hitTypeMod - 1);
                            subType = TextFormatUtils.ToUpper(subType);
                            uint damage = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                            handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.MELEE, subType);
                        }
                        // [Sun Apr 18 20:24:56 2021] Sonozen hit Jortreva the Crusader for 38948 points of fire damage by Burst of Flames. (Lucky Critical Twincast)
                        else if (byDamage > 3 && pointsOfIndex == (byDamage - 3) && byIndex == (byDamage + 1) && forIndex > -1 &&
                                 subType == "hits" && hitType < forIndex && split[stop].Length > 0 && split[stop][split[stop].Length - 1] == '.')
                        {
                            string spell = string.Join(" ", split, byIndex + 1, stop - byIndex);
                            if (!string.IsNullOrEmpty(spell) && spell[spell.Length - 1] == '.')
                            {
                                spell = spell.Substring(0, spell.Length - 1);
                                string      attacker = string.Join(" ", split, 0, hitType);
                                string      defender = string.Join(" ", split, hitType + 1, forIndex - hitType - 1);
                                string      type     = GetTypeFromSpell(spell, Labels.DD);
                                uint        damage   = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                                SpellResist resist   = SpellResist.UNDEFINED;
                                SpellResistMap.TryGetValue(split[byDamage - 1], out resist);

                                // extra way to check for pets
                                if (spell.StartsWith("Elemental Conversion", StringComparison.Ordinal))
                                {
                                    PlayerManager.Instance.AddVerifiedPet(defender);
                                }

                                handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, type, spell, resist);
                            }
                        }
                        // [Sun Apr 18 20:32:39 2021] Dovhesi has taken 173674 damage from Curse of the Shrine by Grendish the Crusader.
                        // [Sun Apr 18 20:32:42 2021] Grendish the Crusader has taken 1003231 damage from Pyre of Klraggek Rk. III by Atvar. (Lucky Critical)
                        // [Thu Mar 18 18:48:10 2021] You have taken 4852 damage from Nectar of Misery by Commander Gartik.
                        // [Thu Mar 18 01:05:46 2021] A gnoll has taken 108790 damage from your Mind Coil Rk. II.
                        // Old (eqemu) [Sat Jan 15 21:09:10 2022] Pixtt Invi Mal has taken 189 damage from Goanna by Tuyen`s Chant of Fire.
                        else if (fromDamage > 3 && takenIndex == (fromDamage - 3) && (byIndex > fromDamage || yourIndex > fromDamage))
                        {
                            string attacker = null;
                            string spell    = null;
                            if (byIndex > -1)
                            {
                                attacker = string.Join(" ", split, byIndex + 1, stop - byIndex);
                                attacker = (!string.IsNullOrEmpty(attacker) && attacker[attacker.Length - 1] == '.') ? attacker.Substring(0, attacker.Length - 1) : null;
                                spell    = string.Join(" ", split, fromDamage + 2, byIndex - fromDamage - 2);
                            }
                            else if (yourIndex > -1)
                            {
                                attacker = split[yourIndex];
                                spell    = string.Join(" ", split, yourIndex + 1, stop - yourIndex);
                                spell    = (!string.IsNullOrEmpty(spell) && spell[spell.Length - 1] == '.') ? spell.Substring(0, spell.Length - 1) : Labels.DOT;
                            }

                            if (!string.IsNullOrEmpty(attacker) && !string.IsNullOrEmpty(spell))
                            {
                                string    type;
                                SpellData spellData = DataManager.Instance.GetDamagingSpellByName(spell);

                                // Old (eqemu) if attacker is actually a spell then swap attacker and spell
                                // Spells dont change on eqemu servers so this should always be a spell even with old spell data
                                if (spellData == null && DataManager.Instance.IsOldSpell(attacker))
                                {
                                    // check that we can't find a spell where the player name is
                                    var temp = attacker;
                                    attacker = spell;
                                    spell    = temp;
                                    type     = Labels.DOT;
                                }
                                else
                                {
                                    type = GetTypeFromSpell(spell, Labels.DOT);
                                }

                                string      defender = string.Join(" ", split, 0, takenIndex);
                                uint        damage   = StatsUtil.ParseUInt(split[fromDamage - 1]);
                                SpellResist resist   = spellData != null ? spellData.Resist : SpellResist.UNDEFINED;
                                handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, type, spell, resist);
                            }
                        }
                        // [Mon Apr 26 21:07:21 2021] Lawlstryke has taken 216717 damage by Wisp Explosion.
                        else if (byDamage > -1 && takenIndex == (byDamage - 3))
                        {
                            string defender = string.Join(" ", split, 0, takenIndex);
                            uint   damage   = StatsUtil.ParseUInt(split[byDamage - 1]);
                            string spell    = string.Join(" ", split, byDamage + 2, stop - byDamage - 1);
                            if (!string.IsNullOrEmpty(spell) && spell[spell.Length - 1] == '.')
                            {
                                spell = spell.Substring(0, spell.Length - 1);
                            }

                            SpellResist resist = SpellResist.UNDEFINED;
                            if (DataManager.Instance.GetDamagingSpellByName(spell) is SpellData spellData && spellData != null)
                            {
                                resist = spellData.Resist;
                            }

                            handled = CreateDamageRecord(lineData, split, stop, "", defender, damage, Labels.DOT, spell, resist, true);
                        }
                        // Old (eqemu direct damage) [Sat Jan 15 21:08:54 2022] Jaun hit Pixtt Invi Mal for 150 points of non-melee damage.
                        else if (hitType > -1 && forIndex > -1 && forIndex < pointsOfIndex && nonMeleeIndex > pointsOfIndex)
                        {
                            int    hitTypeMod = hitTypeAdd > 0 ? 1 : 0;
                            string attacker   = string.Join(" ", split, 0, hitType);
                            string defender   = string.Join(" ", split, hitType + hitTypeMod + 1, forIndex - hitType - hitTypeMod - 1);
                            uint   damage     = StatsUtil.ParseUInt(split[pointsOfIndex - 1]);
                            handled = CreateDamageRecord(lineData, split, stop, attacker, defender, damage, Labels.DD, Labels.DD);
                        }
                        // [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)
                        // [Sat Apr 24 01:08:49 2021] Test One Hundred Three tries to punch Kazint, but misses!
                        // [Sat Apr 24 01:08:49 2021] Test One Hundred Three tries to punch Kazint, but Kazint dodges!
                        // [Sat Apr 24 01:10:17 2021] Test One Hundred Three tries to punch YOU, but YOU dodge!
                        // [Sat Apr 24 01:10:17 2021] Kazint tries to crush Test One Hundred Three, but Test One Hundred Three dodges!
                        // [Sun Apr 18 19:45:21 2021] You try to crush a primal guardian, but a primal guardian parries!
                        // [Mon May 31 20:29:49 2021] A bloodthirsty gnawer tries to bite Vandil, but Vandil parries!
                        // [Sun Apr 25 22:56:22 2021] Romance tries to bash Vulak`Aerr, but Vulak`Aerr parries!
                        // [Sun Jul 28 20:12:46 2019] Drogbaa tries to slash Whirlrender Scout, but misses! (Strikethrough)
                        // [Tue Mar 30 16:43:54 2021] You try to crush a desert madman, but a desert madman blocks!
                        // [Mon Apr 26 22:40:10 2021] An ancient warden tries to hit Reisil, but Reisil blocks with his shield!
                        // [Sun Mar 21 00:11:31 2021] A carrion bat tries to bite YOU, but YOU block with your shield!
                        // [Mon Apr 26 14:51:01 2021] A windchill sprite tries to smash YOU, but YOU block with your staff!
                        // [Mon May 10 22:18:46 2021] Tolzol tries to crush Dendritic Golem, but Dendritic Golem is INVULNERABLE!
                        else if (tryIndex > -1 && butIndex > tryIndex && missType > -1)
                        {
                            string label = null;
                            switch (missType)
                            {
                            case 0:
                                label = Labels.BLOCK;
                                break;

                            case 1:
                                label = Labels.DODGE;
                                break;

                            case 2:
                                label = Labels.MISS;
                                break;

                            case 3:
                                label = Labels.PARRY;
                                break;

                            case 4:
                                label = Labels.INVULNERABLE;
                                break;
                            }

                            if (!string.IsNullOrEmpty(label))
                            {
                                int    hitTypeMod = hitTypeAdd > 0 ? 1 : 0;
                                string defender   = string.Join(" ", split, hitType + hitTypeMod + 1, butIndex - hitType - hitTypeMod - 1);
                                if (!string.IsNullOrEmpty(defender) && defender[defender.Length - 1] == ',')
                                {
                                    defender = defender.Substring(0, defender.Length - 1);
                                    string attacker = string.Join(" ", split, 0, tryIndex);
                                    subType = TextFormatUtils.ToUpper(subType);
                                    handled = CreateDamageRecord(lineData, split, stop, attacker, defender, 0, label, subType);
                                }
                            }
                        }
                        // [Sun Apr 18 21:26:20 2021] Strangle`s pet has been slain by Kzerk!
                        else if (slainIndex > -1 && byIndex == (slainIndex + 1) && hasIndex > 0 && stop > (slainIndex + 1) && split[hasIndex + 1] == "been")
                        {
                            string killer = string.Join(" ", split, byIndex + 1, stop - byIndex);
                            killer = killer.Length > 1 && killer[killer.Length - 1] == '!' ? killer.Substring(0, killer.Length - 1) : killer;
                            string slain = string.Join(" ", split, 0, hasIndex);
                            handled = UpdateSlain(slain, killer, lineData);
                            HasOwner(slain, out string t1);
                            HasOwner(killer, out string t2);
                        }
                        // [Mon Apr 19 02:22:09 2021] You have been slain by an armed flyer!
                        else if (stop > 4 && slainIndex == 3 && byIndex == 4 && split[0] == "You" && split[1] == "have" && split[2] == "been")
                        {
                            string killer = string.Join(" ", split, 5, stop - 4);
                            killer = killer.Length > 1 && killer[killer.Length - 1] == '!' ? killer.Substring(0, killer.Length - 1) : killer;
                            string slain = ConfigUtil.PlayerName;
                            handled = UpdateSlain(slain, killer, lineData);
                        }
                        // [Mon Apr 19 02:22:09 2021] You have slain a failed bodyguard!
                        else if (slainIndex == 2 && split[0] == "You" && split[1] == "have")
                        {
                            string killer = ConfigUtil.PlayerName;
                            string slain  = string.Join(" ", split, 3, stop - 2);
                            slain   = slain.Length > 1 && slain[slain.Length - 1] == '!' ? slain.Substring(0, slain.Length - 1) : slain;
                            handled = UpdateSlain(slain, killer, lineData);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                LOG.Error(e);
            }

            DebugUtil.UnregisterLine(lineData.LineNumber, handled);
        }