/// <summary> /// Merge data from another participant into this participant. /// </summary> public void Merge(FightParticipant p, int intervalOffset = 0, int timeOffset = 0) { OutboundMissCount += p.OutboundMissCount; OutboundHitCount += p.OutboundHitCount; OutboundHitSum += p.OutboundHitSum; OutboundStrikeCount += p.OutboundStrikeCount; InboundMissCount += p.InboundMissCount; InboundHitCount += p.InboundHitCount; InboundHitSum += p.InboundHitSum; InboundMeleeCount += p.InboundMeleeCount; InboundMeleeSum += p.InboundMeleeSum; InboundRiposteSum += p.InboundRiposteSum; //InboundSpellCount += p.InboundSpellCount; //InboundSpellSum += p.InboundSpellSum; InboundStrikeCount += p.InboundStrikeCount; OutboundHealSum += p.OutboundHealSum; InboundHealSum += p.InboundHealSum; InboundFullHealSum += p.InboundFullHealSum; DeathCount += p.DeathCount; // merge intervals starting at 'intervalOffset' base for (var i = 0; i < p.DPS.Count; i++) { while (DPS.Count <= intervalOffset + i) { DPS.Add(0); } DPS[intervalOffset + i] += p.DPS[i]; } for (var i = 0; i < p.TankDPS.Count; i++) { while (TankDPS.Count <= intervalOffset + i) { TankDPS.Add(0); } TankDPS[intervalOffset + i] += p.TankDPS[i]; } for (var i = 0; i < p.HPS.Count; i++) { while (HPS.Count <= intervalOffset + i) { HPS.Add(0); } HPS[intervalOffset + i] += p.HPS[i]; } for (var i = 0; i < p.InboundHPS.Count; i++) { while (InboundHPS.Count <= intervalOffset + i) { InboundHPS.Add(0); } InboundHPS[intervalOffset + i] += p.InboundHPS[i]; } foreach (var at in p.AttackTypes) { var _at = AttackTypes.FirstOrDefault(x => x.Type == at.Type); if (_at == null) { _at = new FightHit(); _at.Type = at.Type; AttackTypes.Add(_at); } _at.Merge(at); } foreach (var dt in p.DefenseTypes) { var _dt = DefenseTypes.FirstOrDefault(x => x.Type == dt.Type); if (_dt == null) { _dt = new FightMiss(); _dt.Type = dt.Type; DefenseTypes.Add(_dt); } _dt.Merge(dt); } foreach (var h in p.Heals) { var _h = Heals.FirstOrDefault(x => x.Target == h.Target); if (_h == null) { _h = new FightHeal(); _h.Target = h.Target; Heals.Add(_h); } _h.Merge(h); } foreach (var s in p.Spells) { var _s = Spells.FirstOrDefault(x => x.Name == s.Name && x.Type == s.Type); if (_s == null) { _s = new FightSpell(); _s.Type = s.Type; _s.Name = s.Name; //_s.Times = // todo Spells.Add(_s); } _s.Merge(s); } // disabled - merging buffs will create duplicates if fights overlap and include the same buff // it would be better to recreate buffs after merging p.Buffs.Clear(); // >= 0 avoids any pre fight buffs //foreach (var b in p.Buffs.Where(x => x.Time >= 0)) //{ // if (timeOffset == 0) // Buffs.Add(b); // else // Buffs.Add(new FightBuff { Name = b.Name, Time = b.Time + timeOffset }); //} }
public void AddHit(LogHitEvent hit, int interval = -1) { if (FirstAction == null) { FirstAction = hit.Timestamp; } LastAction = hit.Timestamp; if (hit.Source == Name) { OutboundHitCount += 1; OutboundHitSum += hit.Amount; if (hit.Spell != null) { //OutboundSpellCount += 1; //OutboundSpellSum += hit.Amount; var spell = AddSpell(hit.Spell, "hit"); spell.HitCount += 1; spell.HitSum += hit.Amount; if (hit.Amount > spell.HitMax) { spell.HitMax = hit.Amount; } if (hit.Mod.HasFlag(LogEventMod.Critical)) { spell.CritCount += 1; spell.CritSum += hit.Amount; } if (hit.Mod.HasFlag(LogEventMod.Twincast)) { spell.TwinCount += 1; //spell.TwinSum += hit.Amount; } } else { //if (hit.Amount > OutboundMaxHit) //{ // OutboundMaxHit = hit.Amount; //} //OutboundMeleeCount += 1; //OutboundMeleeSum += hit.Amount; } var type = hit.Type; // alter the attack type on some special hits if (hit.Mod.HasFlag(LogEventMod.Finishing_Blow)) { type = "finishing"; } else if (hit.Mod.HasFlag(LogEventMod.Headshot)) { type = "headshot"; } else if (hit.Mod.HasFlag(LogEventMod.Assassinate)) { type = "assassinate"; } else if (hit.Mod.HasFlag(LogEventMod.Decapitate)) { type = "decapitate"; } else if (hit.Mod.HasFlag(LogEventMod.Slay_Undead)) { type = "slay"; } //else if (hit.Mod.HasFlag(LogEventMod.Special)) // type += ":special"; else if (hit.Mod.HasFlag(LogEventMod.Riposte)) { type = "riposte"; } var at = AddAttack(type); at.HitCount += 1; at.HitSum += hit.Amount; if (hit.Amount > at.HitMax) { at.HitMax = hit.Amount; } if (hit.Mod.HasFlag(LogEventMod.Critical)) { at.CritCount += 1; at.CritSum += hit.Amount; } if (hit.Mod.HasFlag(LogEventMod.Strikethrough)) { OutboundStrikeCount += 1; } if (interval >= 0) { while (DPS.Count <= interval) { DPS.Add(0); } DPS[interval] += hit.Amount; } } else if (hit.Target == Name) { InboundHitCount += 1; InboundHitSum += hit.Amount; if (hit.Spell != null) { //InboundSpellSum += hit.Amount; } else { InboundMeleeCount += 1; InboundMeleeSum += hit.Amount; if (interval >= 0) { while (TankDPS.Count <= interval) { TankDPS.Add(0); } TankDPS[interval] += hit.Amount; } //TankHits.TryGetValue(hit.Amount, out int count); //TankHits[hit.Amount] = count + 1; } if (hit.Mod.HasFlag(LogEventMod.Riposte)) { InboundRiposteSum += hit.Amount; } if (hit.Mod.HasFlag(LogEventMod.Strikethrough)) { InboundStrikeCount += 1; // strikethroughs are reported on hits and riposte, but other defenses do get not reported on a strikethrough // in order to properly count these defenses we should log a mystery defense that was never reported // i.e. for riposte the log will show this: // [Wed Jan 19 20:54:58 2022] A shadowbone tries to bash YOU, but YOU riposte!(Strikethrough) // [Wed Jan 19 20:54:58 2022] A shadowbone bashes YOU for 5625 points of damage. (Riposte Strikethrough) // but for dodge/parry/etc.. it will only show this: // [Wed Jan 19 20:54:58 2022] A shadowbone bashes YOU for 5625 points of damage. (Strikethrough) if (!hit.Mod.HasFlag(LogEventMod.Riposte)) { AddMiss(new LogMissEvent { Timestamp = hit.Timestamp, Source = hit.Source, Target = hit.Target, Type = "unknown" }); } } } }