コード例 #1
0
        protected FightParticipant AddParticipant(string name)
        {
            if (Target.Name == name)
            {
                return(Target);
            }

            FightParticipant p = null;

            for (int i = 0; i < Participants.Count; i++)
            {
                if (Participants[i].Name == name)
                {
                    p = Participants[i];
                    break;
                }
            }

            if (p == null)
            {
                p      = new FightParticipant();
                p.Name = name;
                Participants.Add(p);
            }
            return(p);
        }
コード例 #2
0
 public FightInfo(string name)
 {
     ID     = Guid.NewGuid().ToString();
     Name   = name;
     Target = new FightParticipant()
     {
         Name = name
     };
 }
コード例 #3
0
        /// <summary>
        /// Merges damage, heals and spells from a pet into this participant.
        /// Tanking is not merged.
        /// All data will be prefixed with "pet:" to distinguish it from the owner. e.g. "pet:slash" vs "slash"
        /// </summary>
        public void MergePet(FightParticipant pet)
        {
            foreach (var at in pet.AttackTypes)
            {
                at.Type = "pet:" + at.Type;
                //owner.AttackTypes.Add(hit);
                var match = AttackTypes.FirstOrDefault(x => x.Type == at.Type);
                if (match != null)
                {
                    match.Merge(at);
                }
                else
                {
                    AttackTypes.Add(at);
                }
            }

            foreach (var spell in pet.Spells.Where(x => x.Type == "hit"))
            {
                spell.Name = "pet:" + spell.Name;
                var match = Spells.FirstOrDefault(x => x.Type == spell.Type && x.Name == spell.Name);
                if (match != null)
                {
                    match.Merge(spell);
                }
                else
                {
                    Spells.Add(spell);
                }
            }

            OutboundHitCount  += pet.OutboundHitCount;
            OutboundHitSum    += pet.OutboundHitSum;
            OutboundMissCount += pet.OutboundMissCount;

            // merges DPS and HPS intervals (but not TankDPS or InboundHPS)
            for (var i = 0; i < pet.DPS.Count; i++)
            {
                while (DPS.Count <= i)
                {
                    DPS.Add(0);
                }
                DPS[i] += pet.DPS[i];
            }

            for (var i = 0; i < pet.HPS.Count; i++)
            {
                while (HPS.Count <= i)
                {
                    HPS.Add(0);
                }
                HPS[i] += pet.HPS[i];
            }

            // removing the pet has the downside of hiding pet tanking
            //Participants.Remove(pet);

            // clear the damage on the pet but keep it for tanking stats
            pet.OutboundHitCount  = 0;
            pet.OutboundHitSum    = 0;
            pet.OutboundMissCount = 0;
            pet.AttackTypes.Clear();
            //pet.Spells.Clear();
            pet.Spells.RemoveAll(x => x.Type == "hit"); // leave heals on pet so it shows on the healer list
            pet.DPS.Clear();
            pet.HPS.Clear();
        }
コード例 #4
0
        /// <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 });
            //}
        }
コード例 #5
0
        /// <summary>
        /// Merge data from another fight into this fight.
        /// The supplied fight must have started after any previously merged fights.
        /// </summary>
        public virtual void Merge(FightInfo f)
        {
            if (Target == null || String.IsNullOrEmpty(Target.Name))
            {
                Target = new FightParticipant()
                {
                    Name = "X"
                };
                Name      = "X";
                Zone      = f.Zone;
                Party     = f.Party;
                Player    = f.Player;
                Server    = f.Server;
                StartedOn = f.StartedOn;
                UpdatedOn = f.UpdatedOn;
                Status    = FightStatus.Merged;
                Duration  = 1;
            }

            MobCount += 1;
            fights.Add(f);

            if (Zone != f.Zone)
            {
                Zone = "Multiple Zones";
            }

            if (Party == "Group" && f.Party == "Raid")
            {
                Party = "Raid";
            }

            //Target.Merge(f.Target, 0);

            if (StartedOn > f.StartedOn && intervals.Count == 1)
            {
                StartedOn = f.StartedOn;
            }
            else if (StartedOn > f.StartedOn)
            {
                throw new Exception("Fights must be merged in order of start time.");
            }

            if (UpdatedOn < f.UpdatedOn)
            {
                UpdatedOn = f.UpdatedOn;
            }


            /*
             * for single fights each tick has a 1 to 1 mapping to intervals.
             * however when merging multiple fights together we have to deal with
             * ticks that may overlap intervals (which we need to merge) and
             * gaps between fights (which we want to remove).
             *
             * here are some scenarios that will occur:
             *
             *         1111
             * 12345678  90123   -- intervals we want to assign
             * ---------------   -- the tick timeline
             * 1111              -- first fight
             * 22222          -- 2nd overlaps with 1st
             *        33333   -- 3rd has gap after 2nd
             *         44     -- 4th ends before 3rd
             *
             * fights must be sorted in starting order for this algorithm to work
             */

            // starting interval
            var interval = 0;
            // get tick relative to first tick of first fight
            var head = GetTick(f.StartedOn);
            var tail = GetTick(f.UpdatedOn);

            Debug.Assert(tail >= head);

            // has this tick already been seen?
            // if so backtrack so we can find where it belongs
            if (head <= intervals[^ 1])
            {
                interval = intervals.Count - 1;
                while (intervals[interval] > head)
                {
                    interval--;
                }
            }
            // if it hasn't been seen then add it as a new interval
            else
            {
                intervals.Add(head);
                interval = intervals.Count - 1;
            }

            // handle the tail
            var current = intervals[^ 1];
コード例 #6
0
        /// <summary>
        /// Trim the long tail of participants that fall under a low threshold of activity to make the data structure smaller.
        /// These players will be consolidated into an "*Other" entry.
        /// This should be done after all other merging -- possibly just on the server side.
        /// </summary>
        public void TrimParticipants()
        {
            var other = new FightParticipant();

            other.FirstAction = StartedOn;
            other.LastAction  = UpdatedOn;
            other.Name        = "*Other";

            // damage: anyone that does less than 5% of top damage dealer
            var min = Participants.Max(x => x.OutboundHitSum) * 0.05;

            foreach (var p in Participants.Where(x => x.OutboundHitSum < min))
            {
                // participant names will be anonymized at this point
                //other.AttackTypes.Add(new FightHit { Type = p.Name, HitCount = p.OutboundHitCount, HitSum = (int)p.OutboundHitSum });
                other.OutboundHitSum   += p.OutboundHitSum;
                p.OutboundHitSum        = 0;
                other.OutboundHitCount += p.OutboundHitCount;
                p.OutboundHitCount      = 0;
                p.DPS.Clear();
                p.AttackTypes.Clear();
                p.Spells.RemoveAll(x => x.Type == "hit");
            }

            // tanking: anyone that does less than 10% of the top tank
            // this just ends up being filled with swarm pets and rampage targets
            min = Participants.Max(x => x.InboundMeleeSum) * 0.1;
            foreach (var p in Participants.Where(x => x.InboundMeleeSum < min))
            {
                other.InboundMeleeSum   += p.InboundMeleeSum;
                p.InboundMeleeSum        = 0;
                other.InboundMeleeCount += p.InboundMeleeCount;
                other.InboundMissCount  += p.InboundMissCount;
                p.InboundMeleeCount      = 0;
                p.InboundMissCount       = 0;
                p.TankDPS.Clear();
                p.InboundHPS.Clear();
                p.DefenseTypes.Clear();
            }

            // healing: anyone that does less than 10% of top healer
            min = Participants.Max(x => x.OutboundHealSum) * 0.1;
            foreach (var p in Participants.Where(x => x.OutboundHealSum < min))
            {
                other.OutboundHealSum += p.OutboundHealSum;
                p.OutboundHealSum      = 0;
                p.HPS.Clear();
                foreach (var h in p.Heals)
                {
                    var ot = other.Heals.Find(x => x.Target == h.Target);
                    if (ot == null)
                    {
                        ot = new FightHeal()
                        {
                            Target = h.Target
                        };
                        other.Heals.Add(h);
                    }
                    ot.HitSum   += h.HitSum;
                    ot.HitCount += h.HitCount;
                }
                p.Heals.Clear();
                p.Spells.RemoveAll(x => x.Type == "heal");
            }


            if (other.OutboundHitSum > 0 || other.OutboundHealSum > 0 || other.InboundMeleeSum > 0)
            {
                Participants.Add(other);
            }

            Participants.RemoveAll(x => x.OutboundHealSum == 0 && x.OutboundHitSum == 0 && x.InboundHitSum == 0 && !x.DPS.Any(y => y > 0));
        }