public void AddHit(FightHitEvent hit) { if (hit.Source == Name) { SourceHitCount += 1; SourceHitSum += hit.Amount; var at = AttackTypes.FirstOrDefault(x => x.Type == hit.Type); if (at == null) { at = new CombatantHit(); at.Type = hit.Type; AttackTypes.Add(at); } at.NormalHitCount += 1; at.NormalHitSum += hit.Amount; //if (hit.Amount > ht.MaxHit) // ht.MaxHit = hit.Amount; } else if (hit.Target == Name) { TargetHitCount += 1; TargetHitSum += hit.Amount; } }
public void FightHit_Nuke() { FightHitEvent hit = null; var parser = new LogParser(PLAYER); parser.OnFightHit += (args) => hit = args; // outgoing (personal name is always shown like a 3rd party) parser.ParseLine("[Thu May 12 17:11:52 2016] Rumstil hit A singedbones skeleton for 37469 points of non-melee damage."); //parser.ParseLine("[Thu May 12 17:11:52 2016] You deliver a critical blast! (37469)"); //parser.ParseLine("[Thu May 12 17:11:52 2016] A singedbones skeleton is caught in a hot summer's storm."); Assert.NotNull(hit); Assert.Equal(37469, hit.Amount); Assert.Equal("Rumstil", hit.Source); Assert.Equal("A singedbones skeleton", hit.Target); Assert.Equal("nuke", hit.Type); // incoming hit = null; parser.ParseLine("[Sun Nov 08 21:50:16 2015] A vicious shadow bites at your soul. You have taken 1138 points of damage."); Assert.NotNull(hit); Assert.Equal(1138, hit.Amount); Assert.Null(hit.Source); Assert.Equal(PLAYER, hit.Target); Assert.Equal("A vicious shadow bites at your soul.", hit.Spell); Assert.Equal("nuke", hit.Type); // todo: incoming 3rd party }
public void FightHit_DoT() { FightHitEvent hit = null; var parser = new LogParser(PLAYER); parser.OnFightHit += (args) => hit = args; // personal DoT hit = null; parser.ParseLine("[Sun Nov 08 19:41:40 2015] A corricaux echo has taken 3936 damage from your Glistenwing Swarm."); Assert.NotNull(hit); Assert.Equal(3936, hit.Amount); Assert.Equal(PLAYER, hit.Source); Assert.Equal("A corricaux echo", hit.Target); Assert.Equal("Glistenwing Swarm", hit.Spell); Assert.Equal("dot", hit.Type); // 3rd party DoT hit = null; parser.ParseLine("[Wed Nov 04 20:26:51 2015] Warpriest Poxxil has taken 14841 damage from Fourier by Mental Contortion V."); Assert.NotNull(hit); Assert.Equal(14841, hit.Amount); Assert.Equal("Fourier", hit.Source); Assert.Equal("Warpriest Poxxil", hit.Target); Assert.Equal("Mental Contortion V", hit.Spell); Assert.Equal("dot", hit.Type); // 3rd party DoT from dead caster or trap hit = null; parser.ParseLine("[Wed Nov 04 20:26:51 2015] Warpriest Poxxil has taken 14841 damage by Mental Contortion V."); Assert.NotNull(hit); Assert.Equal(14841, hit.Amount); Assert.Null(hit.Source); Assert.Equal("Warpriest Poxxil", hit.Target); Assert.Equal("Mental Contortion V", hit.Spell); Assert.Equal("dot", hit.Type); // incoming DoT hit = null; parser.ParseLine("[Wed Nov 04 20:26:51 2015] You have taken 3251 damage from Deadly Screech by The Cliknar Queen"); Assert.NotNull(hit); Assert.Equal(3251, hit.Amount); Assert.Equal("The Cliknar Queen", hit.Source); Assert.Equal(PLAYER, hit.Target); Assert.Equal("Deadly Screech", hit.Spell); Assert.Equal("dot", hit.Type); // incoming DoT from dead caster or trap hit = null; parser.ParseLine("[Wed Nov 04 20:26:51 2015] You have taken 3251 damage from Deadly Screech"); Assert.NotNull(hit); Assert.Equal(3251, hit.Amount); Assert.Null(hit.Source); Assert.Equal(PLAYER, hit.Target); Assert.Equal("Deadly Screech", hit.Spell); Assert.Equal("dot", hit.Type); }
public virtual void TrackFightHit(FightHitEvent hit) { var f = AddFight(hit); if (f == null) { return; } var source = f.Participants.First(x => x.Name == hit.Source); source.AddHit(hit); var target = f.Participants.First(x => x.Name == hit.Target); target.AddHit(hit); // there are no crit notifications for DoTs but we can guess when they occur by // treating everything that does 125% more damage than the minimum as a crit // todo: do DoTs have partial resists? if (hit.Type == "dot" && hit.Spell != null) { int min; if (!MinDoTDamage.TryGetValue(hit.Spell, out min) || min > hit.Amount) { MinDoTDamage[hit.Spell] = min = hit.Amount; } if (hit.Amount >= min * 2.25) { LastCritical = new FightCritEvent { Timestamp = hit.Timestamp, Source = hit.Source, Amount = hit.Amount, Sequence = FightCritEventSequence.BeforeHit } } ; } // update hit for crit notification that occured before hit if (LastCritical != null && LastCritical.Sequence == FightCritEventSequence.BeforeHit && LastCritical.Source == hit.Source) { var ht = source.AttackTypes.First(x => x.Type == hit.Type); ht.NormalHitCount -= 1; ht.NormalHitSum -= hit.Amount; ht.CritHitCount += 1; ht.CritHitSum += hit.Amount; } LastFight = f; LastHit = hit; LastCritical = null; }
public void FightHit_DS() { FightHitEvent hit = null; var parser = new LogParser(PLAYER); parser.OnFightHit += (args) => hit = args; parser.ParseLine("[Thu May 12 15:49:46 2016] A soldier is pierced by YOUR thorns for 703 points of non-melee damage."); Assert.NotNull(hit); Assert.Equal(703, hit.Amount); Assert.Equal(PLAYER, hit.Source); Assert.Equal("A soldier", hit.Target); Assert.Equal("dmgshield", hit.Type); }
// runes are currently handled by FightMiss but perhaps they should also be hits for 0 damage? //private static readonly Regex RuneRegex = new Regex(@"^(.+?) (?:try|tries) to (\w+) (.+?), but .*? magical skin absorbs the blow!$", RegexOptions.Compiled | RegexOptions.RightToLeft); //[EventParser] private void CheckFightHit(LogLine line) { if (OnFightHit == null) { return; } var m = MeleeHitRegex.Match(line.RawText); if (m.Success) { var type = m.Groups[2].Value; if (type == "frenzy on" || type == "frenzies on") { type = "frenzy"; } var hit = new FightHitEvent() { Timestamp = line.Timestamp, Source = FixName(m.Groups[1].Value), Type = type, Target = FixName(m.Groups[3].Value), Amount = Int32.Parse(m.Groups[4].Value) }; OnFightHit(hit); return; } m = RampageRegex.Match(line.RawText); if (m.Success) { var type = m.Groups[4].Value; if (type == "Rampage") { type = "rampage"; } if (type == "Wild Rampage") { type = "wildramp"; } var hit = new FightHitEvent() { Timestamp = line.Timestamp, Source = FixName(m.Groups[1].Value), Target = FixName(m.Groups[2].Value), Amount = Int32.Parse(m.Groups[3].Value), Type = type }; OnFightHit(hit); return; } /* * m = MiscHitRegex.Match(line.Text); * if (m.Success) * { * var hit = new FightHit() * { * Timestamp = line.Timestamp, * Target = FixName(m.Groups[1].Value), * Amount = Int32.Parse(m.Groups[2].Value), * Type = "hit", * }; * OnFightHit(hit); * return; * } */ m = NukeDamageRegex.Match(line.RawText); if (m.Success) { var hit = new FightHitEvent() { Timestamp = line.Timestamp, Source = FixName(m.Groups[1].Value), Target = FixName(m.Groups[2].Value), Amount = Int32.Parse(m.Groups[3].Value), Type = "nuke" }; OnFightHit(hit); return; } m = IncNukeDamageRegex.Match(line.RawText); if (m.Success) { var hit = new FightHitEvent() { Timestamp = line.Timestamp, Target = Player.Name, Spell = m.Groups[1].Value, Amount = Int32.Parse(m.Groups[2].Value), Type = "nuke" }; OnFightHit(hit); return; } m = DoTDamageRegex.Match(line.RawText); if (m.Success) { var hit = new FightHitEvent() { Timestamp = line.Timestamp, Target = FixName(m.Groups[1].Value), Amount = Int32.Parse(m.Groups[2].Value), Source = FixName(Coalesce(m.Groups[3], m.Groups[4])), SourceIsCorpse = m.Groups[4].Value.EndsWith(CorpseSuffix), Spell = m.Groups[5].Value, Type = "dot" }; OnFightHit(hit); return; } m = IncDoTDamageRegex.Match(line.RawText); if (m.Success) { var hit = new FightHitEvent() { Timestamp = line.Timestamp, Target = Player.Name, Amount = Int32.Parse(m.Groups[1].Value), Spell = m.Groups[2].Value, Source = FixName(m.Groups[3].Value), SourceIsCorpse = m.Groups[3].Value.EndsWith(CorpseSuffix), Type = "dot" }; OnFightHit(hit); return; } m = DamageShieldRegex.Match(line.RawText); if (m.Success) { var hit = new FightHitEvent() { Timestamp = line.Timestamp, Source = Player.Name, Target = m.Groups[1].Value, Amount = Int32.Parse(m.Groups[2].Value), Type = "dmgshield" }; OnFightHit(hit); return; } #if DEBUG //m = UnknownHitRegex.Match(line.RawText); //if (m.Success) //{ // Console.Error.WriteLine(line.RawText); // OnFightHit(new FightHitEvent { Timestamp = line.Timestamp, Target = "N/A", Source = "N/A", Type = line.RawText }); //} #endif }
public void FightHit_Melee() { FightHitEvent hit = null; var parser = new LogParser(PLAYER); parser.OnFightHit += (args) => hit = args; // personal hit hit = null; parser.ParseLine("[Wed Apr 20 18:36:59 2016] You pierce A skeletal minion for 1424 points of damage."); Assert.NotNull(hit); Assert.Equal(1424, hit.Amount); Assert.Equal(PLAYER, hit.Source); Assert.Equal("A skeletal minion", hit.Target); Assert.Equal("pierce", hit.Type); // 3rd party hit hit = null; parser.ParseLine("[Sun May 08 20:13:09 2016] Jonekab frenzies on An aggressive corpse for 429 points of damage."); Assert.NotNull(hit); Assert.Equal(429, hit.Amount); Assert.Equal("Jonekab", hit.Source); Assert.Equal("An aggressive corpse", hit.Target); Assert.Equal("frenzy", hit.Type); // incoming hit hit = null; parser.ParseLine("[Wed Apr 27 09:46:20 2016] A ghoul hits YOU for 3551 points of damage."); Assert.NotNull(hit); Assert.Equal(3551, hit.Amount); Assert.Equal("A ghoul", hit.Source); Assert.Equal(PLAYER, hit.Target); Assert.Equal("hit", hit.Type); // rampage hit = null; parser.ParseLine("[Wed Apr 27 09:46:20 2016] Praetor Ledalus Thaddaeus slashes Rumstil for 9456 points of damage. (Rampage)"); Assert.NotNull(hit); Assert.Equal(9456, hit.Amount); Assert.Equal("Praetor Ledalus Thaddaeus", hit.Source); Assert.Equal("Rumstil", hit.Target); Assert.Equal("rampage", hit.Type); // frenzy on - 2 word attack skill hit = null; parser.ParseLine("[Wed Apr 27 09:46:20 2016] A ghoul frenzies on YOU for 3551 points of damage."); Assert.NotNull(hit); Assert.Equal(3551, hit.Amount); Assert.Equal("A ghoul", hit.Source); Assert.Equal(PLAYER, hit.Target); Assert.Equal("frenzy", hit.Type); // make sure the extra non-melee message from archery and other skill attacks is not processed twice // this was also the format used by old damage shield messages // [Thu May 19 10:37:29 2016] a fright funnel was hit by non-melee for 186844 points of damage. // [Thu May 19 10:37:29 2016] You gain party experience!! // [Thu May 19 10:37:29 2016] You hit a fright funnel for 186844 points of damage. hit = null; parser.ParseLine("[Thu May 12 17:11:55 2016] A singedbones skeleton was hit by non-melee for 246657 points of damage."); Assert.Null(hit); }