Beispiel #1
0
        private void MenuItemExportHTMLClick(object sender, RoutedEventArgs e)
        {
            var tables = new Dictionary <string, SummaryTable>();

            if (DamageWindow?.Content is DamageSummary damageSummary && DamageWindow?.IsOpen == true)
            {
                tables.Add(DamageWindow.Title, damageSummary);
            }

            if (HealingWindow?.Content is HealingSummary healingSummary && HealingWindow?.IsOpen == true)
            {
                tables.Add(HealingWindow.Title, healingSummary);
            }

            if (TankingWindow?.Content is TankingSummary tankingSummary && TankingWindow?.IsOpen == true)
            {
                tables.Add(TankingWindow.Title, tankingSummary);
            }

            if (tables.Count > 0)
            {
                TextFormatUtils.ExportAsHTML(tables);
            }
            else
            {
                _ = MessageBox.Show("Nothing to Save. Display a Summary View and Try Again.", Properties.Resources.FILEMENU_EXPORT_SUMMARY, MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }
Beispiel #2
0
        internal Fight GetFight(string name)
        {
            Fight result = null;

            if (!string.IsNullOrEmpty(name))
            {
                if (!ActiveFights.TryGetValue(name, out result))
                {
                    ActiveFights.TryGetValue(TextFormatUtils.FlipCase(name), out result);
                }
            }
            return(result);
        }
Beispiel #3
0
        private void CopyCsvClick(object sender, RoutedEventArgs e)
        {
            if (LastSortedValues != null)
            {
                try
                {
                    List <string> header = new List <string> {
                        "Seconds", choicesList.SelectedValue as string, "Name"
                    };

                    var data = new List <List <object> >();
                    LastSortedValues.Where(values => LastFilter == null || LastFilter(values.First())).ToList().ForEach(sortedValue =>
                    {
                        foreach (var chartData in sortedValue)
                        {
                            double chartValue = 0;
                            if (CurrentConfig == CONFIG_AVG)
                            {
                                chartValue = chartData.Avg;
                            }
                            else if (CurrentConfig == CONFIG_CRIT_RATE)
                            {
                                chartValue = chartData.CritRate;
                            }
                            else if (CurrentConfig == CONFIG_TOTAL)
                            {
                                chartValue = chartData.Total;
                            }
                            else if (CurrentConfig == CONFIG_VPS)
                            {
                                chartValue = chartData.VPS;
                            }

                            data.Add(new List <object> {
                                chartData.CurrentTime, chartValue, chartData.Name
                            });
                            Clipboard.SetDataObject(TextFormatUtils.BuildCsv(header, data, titleLabel.Content as string));
                        }
                    });
                }
                catch (ExternalException ex)
                {
                    LOG.Error(ex);
                }
            }
        }
 private void CopyCsvClick(object sender, RoutedEventArgs e)
 {
     try
     {
         var    export = BuildExportData();
         string result = TextFormatUtils.BuildCsv(export.Item1, export.Item2);
         Clipboard.SetDataObject(result);
     }
     catch (ArgumentNullException ane)
     {
         Clipboard.SetDataObject("EQ Log Parser Error: Failed to create BBCode\r\n");
         LOG.Error(ane);
     }
     catch (ExternalException ex)
     {
         LOG.Error(ex);
     }
 }
 private void CopyGamparseClick(object sender, RoutedEventArgs e)
 {
     try
     {
         var    export = DataGridUtils.BuildExportData(dataGrid);
         string result = TextFormatUtils.BuildGamparseList(export.Item1, export.Item2, titleLabel.Content as string);
         Clipboard.SetDataObject(result);
     }
     catch (ArgumentNullException ane)
     {
         Clipboard.SetDataObject("EQ Log Parser Error: Failed to create BBCode\r\n");
         LOG.Error(ane);
     }
     catch (ExternalException ex)
     {
         LOG.Error(ex);
     }
 }
Beispiel #6
0
 internal static void CopyCsvFromTable(DataGrid dataGrid, string title)
 {
     try
     {
         var    export = BuildExportData(dataGrid);
         string result = TextFormatUtils.BuildCsv(export.Item1, export.Item2, title);
         Clipboard.SetDataObject(result);
     }
     catch (ArgumentNullException ane)
     {
         Clipboard.SetDataObject("EQ Log Parser Error: Failed to create CSV\r\n");
         LOG.Error(ane);
     }
     catch (ExternalException ex)
     {
         LOG.Error(ex);
     }
 }
        private void CopyCsvClick(object sender, RoutedEventArgs e)
        {
            try
            {
                var header = new List <string> {
                    "Hit Value", "Frequency", "Difference"
                };

                List <List <object> > data = new List <List <object> >();
                for (int i = 0; i < YValues.Count; i++)
                {
                    data.Add(new List <object> {
                        XValues[i], YValues[i], XValuesDiff[i]
                    });
                }

                Clipboard.SetDataObject(TextFormatUtils.BuildCsv(header, data));
            }
            catch (ExternalException ex)
            {
                LOG.Error(ex);
            }
        }
Beispiel #8
0
        private DataManager()
        {
            DictionaryListHelper <string, SpellData> helper = new DictionaryListHelper <string, SpellData>();
            var spellList = new List <SpellData>();

            ConfigUtil.ReadList(@"data\spells.txt").ForEach(line =>
            {
                try
                {
                    var spellData = TextFormatUtils.ParseCustomSpellData(line);
                    if (spellData != null)
                    {
                        spellList.Add(spellData);
                        SpellsNameDB[spellData.Name] = spellData;

                        if (!SpellsAbbrvDB.ContainsKey(spellData.NameAbbrv))
                        {
                            SpellsAbbrvDB[spellData.NameAbbrv] = spellData;
                        }
                        else if (string.Compare(SpellsAbbrvDB[spellData.NameAbbrv].Name, spellData.Name, true, CultureInfo.CurrentCulture) < 0)
                        {
                            // try to keep the newest version
                            SpellsAbbrvDB[spellData.NameAbbrv] = spellData;
                        }

                        if (spellData.LandsOnOther.StartsWith("'s ", StringComparison.Ordinal))
                        {
                            spellData.LandsOnOther = spellData.LandsOnOther.Substring(3);
                            helper.AddToList(PosessiveLandsOnOthers, spellData.LandsOnOther, spellData);
                        }
                        else if (spellData.LandsOnOther.Length > 1)
                        {
                            spellData.LandsOnOther = spellData.LandsOnOther.Substring(1);
                            helper.AddToList(NonPosessiveLandsOnOthers, spellData.LandsOnOther, spellData);
                        }

                        if (spellData.LandsOnYou.Length > 0) // just do stuff in common
                        {
                            helper.AddToList(LandsOnYou, spellData.LandsOnYou, spellData);
                        }
                    }
                }
                catch (OverflowException ex)
                {
                    LOG.Error("Error reading spell data", ex);
                }
            });

            // sort by duration for the timeline to pick better options
            foreach (var key in NonPosessiveLandsOnOthers.Keys)
            {
                NonPosessiveLandsOnOthers[key].Sort((a, b) =>
                {
                    int result = b.Duration.CompareTo(a.Duration);
                    return(result != 0 ? result : b.ID.CompareTo(a.ID));
                });
            }

            foreach (var key in PosessiveLandsOnOthers.Keys)
            {
                PosessiveLandsOnOthers[key].Sort((a, b) =>
                {
                    int result = b.Duration.CompareTo(a.Duration);
                    return(result != 0 ? result : b.ID.CompareTo(a.ID));
                });
            }

            foreach (var key in LandsOnYou.Keys)
            {
                LandsOnYou[key].Sort((a, b) =>
                {
                    int result = b.Duration.CompareTo(a.Duration);
                    return(result != 0 ? result : b.ID.CompareTo(a.ID));
                });
            }

            Dictionary <string, byte> keepOut = new Dictionary <string, byte>();
            var classEnums = Enum.GetValues(typeof(SpellClass)).Cast <SpellClass>().ToList();

            spellList.ForEach(spell =>
            {
                // exact match meaning class-only spell that are of certain target types
                var tgt = (SpellTarget)spell.Target;
                if ((tgt == SpellTarget.SELF || (spell.Level <= 250 && (tgt == SpellTarget.SINGLETARGET || tgt == SpellTarget.LOS))) && classEnums.Contains((SpellClass)spell.ClassMask))
                {
                    // these need to be unique and keep track if a conflict is found
                    if (SpellsToClass.ContainsKey(spell.Name))
                    {
                        SpellsToClass.Remove(spell.Name);
                        keepOut[spell.Name] = 1;
                    }
                    else if (!keepOut.ContainsKey(spell.Name))
                    {
                        SpellsToClass[spell.Name] = (SpellClass)spell.ClassMask;
                    }
                }
            });

            // load NPCs
            ConfigUtil.ReadList(@"data\npcs.txt").ForEach(line => AllNpcs[line.Trim()] = 1);

            PlayerManager.Instance.EventsNewTakenPetOrPlayerAction += (sender, name) => RemoveFight(name);
            PlayerManager.Instance.EventsNewVerifiedPlayer         += (sender, name) => RemoveFight(name);
            PlayerManager.Instance.EventsNewVerifiedPet            += (sender, name) => RemoveFight(name);
        }
Beispiel #9
0
 internal bool IsLifetimeNpc(string name) => LifetimeFights.ContainsKey(name) || LifetimeFights.ContainsKey(TextFormatUtils.FlipCase(name));
Beispiel #10
0
        private DataManager()
        {
            DictionaryListHelper <string, SpellData> helper = new DictionaryListHelper <string, SpellData>();
            var spellList = new List <SpellData>();

            // build ranks cache
            Enumerable.Range(1, 9).ToList().ForEach(r => RanksCache[r.ToString(CultureInfo.CurrentCulture)] = "");
            Enumerable.Range(1, 200).ToList().ForEach(r => RanksCache[TextFormatUtils.IntToRoman(r)]        = "");
            RanksCache["Third"]  = "Root";
            RanksCache["Fifth"]  = "Root";
            RanksCache["Octave"] = "Root";

            ConfigUtil.ReadList(@"data\spells.txt").ForEach(line =>
            {
                try
                {
                    var spellData = ParseCustomSpellData(line);
                    if (spellData != null)
                    {
                        spellList.Add(spellData);
                        SpellsNameDB[spellData.Name] = spellData;

                        if (!SpellsAbbrvDB.ContainsKey(spellData.NameAbbrv))
                        {
                            SpellsAbbrvDB[spellData.NameAbbrv] = spellData;
                        }
                        else if (string.Compare(SpellsAbbrvDB[spellData.NameAbbrv].Name, spellData.Name, true, CultureInfo.CurrentCulture) < 0)
                        {
                            // try to keep the newest version
                            SpellsAbbrvDB[spellData.NameAbbrv] = spellData;
                        }

                        if (spellData.LandsOnOther.StartsWith("'s ", StringComparison.Ordinal))
                        {
                            spellData.LandsOnOther = spellData.LandsOnOther.Substring(3);
                            helper.AddToList(PosessiveLandsOnOthers, spellData.LandsOnOther, spellData);
                        }
                        else if (!string.IsNullOrEmpty(spellData.LandsOnOther))
                        {
                            spellData.LandsOnOther = spellData.LandsOnOther.Substring(1);
                            helper.AddToList(NonPosessiveLandsOnOthers, spellData.LandsOnOther, spellData);
                        }

                        if (!string.IsNullOrEmpty(spellData.LandsOnYou)) // just do stuff in common
                        {
                            helper.AddToList(LandsOnYou, spellData.LandsOnYou, spellData);
                        }
                    }
                }
                catch (OverflowException ex)
                {
                    LOG.Error("Error reading spell data", ex);
                }
            });

            // sort by duration for the timeline to pick better options
            NonPosessiveLandsOnOthers.Values.ToList().ForEach(value => value.Sort((a, b) => DurationCompare(a, b)));
            PosessiveLandsOnOthers.Values.ToList().ForEach(value => value.Sort((a, b) => DurationCompare(a, b)));
            LandsOnYou.Values.ToList().ForEach(value => value.Sort((a, b) => DurationCompare(a, b)));

            var keepOut    = new Dictionary <string, byte>();
            var classEnums = Enum.GetValues(typeof(SpellClass)).Cast <SpellClass>().ToList();

            spellList.ForEach(spell =>
            {
                // exact match meaning class-only spell that are of certain target types
                var tgt = (SpellTarget)spell.Target;
                if ((tgt == SpellTarget.SELF || (spell.Level <= 250 && (tgt == SpellTarget.SINGLETARGET || tgt == SpellTarget.LOS))) && classEnums.Contains((SpellClass)spell.ClassMask))
                {
                    // these need to be unique and keep track if a conflict is found
                    if (SpellsToClass.ContainsKey(spell.Name))
                    {
                        SpellsToClass.Remove(spell.Name);
                        keepOut[spell.Name] = 1;
                    }
                    else if (!keepOut.ContainsKey(spell.Name))
                    {
                        SpellsToClass[spell.Name] = (SpellClass)spell.ClassMask;
                    }
                }
            });

            // load NPCs
            ConfigUtil.ReadList(@"data\npcs.txt").ForEach(line => AllNpcs[line.Trim()] = 1);

            // Load Adps
            AdpsKeys.ForEach(adpsKey => AdpsActive[adpsKey] = new Dictionary <string, uint>());
            AdpsKeys.ForEach(adpsKey => AdpsValues[adpsKey] = new Dictionary <string, uint>());

            string key = null;

            foreach (var line in ConfigUtil.ReadList(@"data\adpsMeter.txt"))
            {
                if (!string.IsNullOrEmpty(line) && line.Trim() is string trimmed && trimmed.Length > 0)
                {
                    if (trimmed[0] != '#' && !string.IsNullOrEmpty(key))
                    {
                        if (trimmed.Split('|') is string[] multiple && multiple.Length > 0)
                        {
                            foreach (var spellLine in multiple)
                            {
                                if (spellLine.Split('=') is string[] list && list.Length == 2 && uint.TryParse(list[1], out uint rate))
                                {
                                    if (SpellsAbbrvDB.TryGetValue(list[0], out SpellData spellData) || SpellsNameDB.TryGetValue(list[0], out spellData))
                                    {
                                        AdpsValues[key][spellData.NameAbbrv] = rate;

                                        if (!AdpsWearOff.TryGetValue(spellData.WearOff, out HashSet <SpellData> wearOffList))
                                        {
                                            AdpsWearOff[spellData.WearOff] = new HashSet <SpellData>();
                                        }

                                        AdpsWearOff[spellData.WearOff].Add(spellData);

                                        if (!AdpsLandsOn.TryGetValue(spellData.LandsOnYou, out HashSet <SpellData> landsOnList))
                                        {
                                            AdpsLandsOn[spellData.LandsOnYou] = new HashSet <SpellData>();
                                        }

                                        AdpsLandsOn[spellData.LandsOnYou].Add(spellData);
                                    }
                                }
                            }
                        }
                    }
                    else if (AdpsKeys.Contains(trimmed))
                    {
                        key = trimmed;
                    }
                }
            }

            PlayerManager.Instance.EventsNewTakenPetOrPlayerAction += (sender, name) => RemoveFight(name);
            PlayerManager.Instance.EventsNewVerifiedPlayer         += (sender, name) => RemoveFight(name);
            PlayerManager.Instance.EventsNewVerifiedPet            += (sender, name) => RemoveFight(name);

            int DurationCompare(SpellData a, SpellData b)
            {
                if (b.Duration.CompareTo(a.Duration) is int result && result == 0)
                {
                    if (int.TryParse(a.ID, out int aInt) && int.TryParse(b.ID, out int bInt) && aInt != bInt)
                    {
                        result = aInt > bInt ? -1 : 1;
                    }
                }

                return(result);
            }
        }
        private void Load()
        {
            Helpers.SetBusy(true);

            var npcStatsRows = new Dictionary <string, NpcStatsRow>();

            foreach (var kv in DataManager.Instance.GetNpcResistStats())
            {
                if (!PlayerManager.Instance.IsPetOrPlayer(kv.Key) && !PlayerManager.Instance.IsPetOrPlayer(TextFormatUtils.ToUpper(kv.Key)))
                {
                    var row = new NpcStatsRow {
                        Name = TextFormatUtils.CapitalizeNpc(kv.Key)
                    };
                    foreach (var resists in kv.Value)
                    {
                        var rate = GetRate(resists.Value.Landed, resists.Value.Resisted);

                        switch (resists.Key)
                        {
                        case SpellResist.AVERAGE:
                            row.Average      = rate.Item1;
                            row.AverageText  = rate.Item2;
                            row.AverageTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.COLD:
                            row.Cold      = rate.Item1;
                            row.ColdText  = rate.Item2;
                            row.ColdTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.CORRUPTION:
                            row.Corruption      = rate.Item1;
                            row.CorruptionText  = rate.Item2;
                            row.CorruptionTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.DISEASE:
                            row.Disease      = rate.Item1;
                            row.DiseaseText  = rate.Item2;
                            row.DiseaseTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.FIRE:
                            row.Fire      = rate.Item1;
                            row.FireText  = rate.Item2;
                            row.FireTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.LOWEST:
                            row.Lowest      = rate.Item1;
                            row.LowestText  = rate.Item2;
                            row.LowestTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.MAGIC:
                            row.Magic      = rate.Item1;
                            row.MagicText  = rate.Item2;
                            row.MagicTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.PHYSICAL:
                            row.Physical      = rate.Item1;
                            row.PhysicalText  = rate.Item2;
                            row.PhysicalTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;

                        case SpellResist.POISON:
                            row.Poison      = rate.Item1;
                            row.PoisonText  = rate.Item2;
                            row.PoisonTotal = resists.Value.Landed + resists.Value.Resisted;
                            break;
                        }
                    }

                    npcStatsRows[kv.Key] = row;
                }
            }

            foreach (var kv in DataManager.Instance.GetNpcTotalSpellCounts())
            {
                if (!npcStatsRows.TryGetValue(kv.Key, out NpcStatsRow updateRow))
                {
                    updateRow = new NpcStatsRow {
                        Name = TextFormatUtils.CapitalizeNpc(kv.Key)
                    };
                }

                var rate = GetRate(kv.Value.Landed, kv.Value.Reflected);
                updateRow.Reflected      = rate.Item1;
                updateRow.ReflectedText  = rate.Item2;
                updateRow.ReflectedTotal = kv.Value.Landed + kv.Value.Reflected;
            }

            dataGrid.ItemsSource = npcStatsRows.Values.OrderBy(row => row.Name).ToList();
            titleLabel.Content   = npcStatsRows.Values.Count == 0 ? NODATA : "Your Spell Stats for " + npcStatsRows.Count + " Unique NPCs";
            Helpers.SetBusy(false);

            Tuple <double, string> GetRate(uint landed, uint notLanded)
            {
                Tuple <double, string> results;
                double computed = 0.0;
                uint   total    = landed + notLanded;

                if (landed == 0 && total > 0)
                {
                    computed = 1.0;
                }
                else if (total > 0)
                {
                    computed = notLanded / (double)total;
                }

                if (total > 0)
                {
                    computed = Math.Round(computed * 100, 2);
                    string computedString = string.Format(CultureInfo.CurrentCulture, "{0} ({1}/{2})", computed, notLanded, total);
                    results = new Tuple <double, string>(computed, computedString);
                }
                else
                {
                    results = new Tuple <double, string>(0.0, "-");
                }

                return(results);
            }
        }
        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);
        }