internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
        {
            var  attackTargets = combatData.Where(x => x.IsStateChange == ArcDPSEnums.StateChange.AttackTarget).ToList();
            long first         = 0;
            long final         = fightData.FightEnd;

            foreach (CombatItem at in attackTargets)
            {
                AgentItem  hand        = agentData.GetAgent(at.DstAgent, at.Time);
                AgentItem  atAgent     = agentData.GetAgent(at.SrcAgent, at.Time);
                var        attackables = combatData.Where(x => x.IsStateChange == ArcDPSEnums.StateChange.Targetable && x.SrcMatchesAgent(atAgent)).ToList();
                var        attackOn    = attackables.Where(x => x.DstAgent == 1 && x.Time >= first + 2000).Select(x => x.Time).ToList();
                var        attackOff   = attackables.Where(x => x.DstAgent == 0 && x.Time >= first + 2000).Select(x => x.Time).ToList();
                var        posFacingHP = combatData.Where(x => x.SrcMatchesAgent(hand) && (x.IsStateChange == ArcDPSEnums.StateChange.Position || x.IsStateChange == ArcDPSEnums.StateChange.Rotation || x.IsStateChange == ArcDPSEnums.StateChange.MaxHealthUpdate)).ToList();
                CombatItem pos         = posFacingHP.FirstOrDefault(x => x.IsStateChange == ArcDPSEnums.StateChange.Position);
                int        id          = (int)ArcDPSEnums.TrashID.HandOfErosion;
                if (pos != null)
                {
                    (float x, float y, _) = AbstractMovementEvent.UnpackMovementData(pos.DstAgent, 0);
                    if ((Math.Abs(x - 15570.5) < 10 && Math.Abs(y + 693.117) < 10) ||
                        (Math.Abs(x - 14277.2) < 10 && Math.Abs(y + 2202.52) < 10))
                    {
                        id = (int)ArcDPSEnums.TrashID.HandOfEruption;
                    }
                }
                for (int i = 0; i < attackOn.Count; i++)
                {
                    long start = attackOn[i];
                    long end   = final;
                    if (i <= attackOff.Count - 1)
                    {
                        end = attackOff[i];
                    }
                    AgentItem extra = agentData.AddCustomNPCAgent(start, end, hand.Name, hand.Spec, id, false, hand.Toughness, hand.Healing, hand.Condition, hand.Concentration, hand.HitboxWidth, hand.HitboxHeight);
                    foreach (CombatItem c in combatData)
                    {
                        if (extra.InAwareTimes(c.Time))
                        {
                            if (c.SrcMatchesAgent(hand, extensions))
                            {
                                c.OverrideSrcAgent(extra.Agent);
                            }
                            if (c.DstMatchesAgent(hand, extensions))
                            {
                                c.OverrideDstAgent(extra.Agent);
                            }
                        }
                    }
                    foreach (CombatItem c in posFacingHP)
                    {
                        var cExtra = new CombatItem(c);
                        cExtra.OverrideTime(extra.FirstAware);
                        cExtra.OverrideSrcAgent(extra.Agent);
                        combatData.Add(cExtra);
                    }
                }
            }
            ComputeFightTargets(agentData, combatData, extensions);
        }
Exemple #2
0
        internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
        {
            FillSubLogics(agentData);
            foreach (FightLogic logic in _subLogics)
            {
                logic.EIEvtcParse(gw2Build, fightData, agentData, combatData, extensions);
                _targets.AddRange(logic.Targets);
                _trashMobs.AddRange(logic.TrashMobs);
                _nonPlayerFriendlies.AddRange(logic.NonPlayerFriendlies);
            }
            _targets.RemoveAll(x => x.ID == (int)ArcDPSEnums.TargetID.DummyTarget);
            AgentItem dummyAgent = agentData.AddCustomNPCAgent(0, fightData.FightEnd, "Dummy Instance Target", ParserHelper.Spec.NPC, (int)ArcDPSEnums.TargetID.Instance, true);

            ComputeFightTargets(agentData, combatData, extensions);
            _targets.RemoveAll(x => x.LastAware - x.FirstAware < 2200);
            TargetAgents = new HashSet <AgentItem>(_targets.Select(x => x.AgentItem));
        }
Exemple #3
0
        internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
        {
            AgentItem dummyAgent = agentData.AddCustomNPCAgent(0, fightData.FightEnd, _detailed ? "Dummy WvW Agent" : "Enemy Players", ParserHelper.Spec.NPC, (int)ArcDPSEnums.TargetID.WorldVersusWorld, true);

            SolveWvWPlayers(agentData, combatData, extensions);
            if (!_detailed)
            {
                var friendlyAgents   = new HashSet <AgentItem>(NonPlayerFriendlies.Select(x => x.AgentItem));
                var aList            = agentData.GetAgentByType(AgentItem.AgentType.NonSquadPlayer).Where(x => !friendlyAgents.Contains(x)).ToList();
                var enemyPlayerDicts = aList.GroupBy(x => x.Agent).ToDictionary(x => x.Key, x => x.ToList());
                foreach (CombatItem c in combatData)
                {
                    if (c.IsDamage(extensions))
                    {
                        if (enemyPlayerDicts.TryGetValue(c.SrcAgent, out List <AgentItem> srcs))
                        {
                            foreach (AgentItem src in srcs)
                            {
                                if (c.SrcMatchesAgent(src, extensions))
                                {
                                    c.OverrideSrcAgent(dummyAgent.Agent);
                                    break;
                                }
                            }
                        }
                        if (enemyPlayerDicts.TryGetValue(c.DstAgent, out List <AgentItem> dsts))
                        {
                            foreach (AgentItem dst in dsts)
                            {
                                if (c.DstMatchesAgent(dst, extensions))
                                {
                                    c.OverrideDstAgent(dummyAgent.Agent);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            ComputeFightTargets(agentData, combatData, extensions);
        }
Exemple #4
0
        internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
        {
            // make those into npcs
            IReadOnlyList <AgentItem> cas = agentData.GetGadgetsByID(_cn ? (int)ArcDPSEnums.TargetID.ConjuredAmalgamate_CHINA : (int)ArcDPSEnums.TargetID.ConjuredAmalgamate);

            if (!cas.Any())
            {
                throw new MissingKeyActorsException("Conjured Amalgamate not found");
            }
            IReadOnlyList <AgentItem> leftArms  = agentData.GetGadgetsByID(_cn ? (int)ArcDPSEnums.TargetID.CALeftArm_CHINA : (int)ArcDPSEnums.TargetID.CALeftArm);
            IReadOnlyList <AgentItem> rightArms = agentData.GetGadgetsByID(_cn ? (int)ArcDPSEnums.TargetID.CARightArm_CHINA : (int)ArcDPSEnums.TargetID.CARightArm);

            foreach (AgentItem ca in cas)
            {
                ca.OverrideType(AgentItem.AgentType.NPC);
                ca.OverrideID(ArcDPSEnums.TargetID.ConjuredAmalgamate);
            }
            foreach (AgentItem leftArm in leftArms)
            {
                leftArm.OverrideType(AgentItem.AgentType.NPC);
                leftArm.OverrideID(ArcDPSEnums.TargetID.CALeftArm);
            }
            foreach (AgentItem rightArm in rightArms)
            {
                rightArm.OverrideType(AgentItem.AgentType.NPC);
                rightArm.OverrideID(ArcDPSEnums.TargetID.CARightArm);
            }
            agentData.Refresh();
            AgentItem sword = agentData.AddCustomNPCAgent(0, fightData.FightEnd, "Conjured Sword\0:Conjured Sword\051", ParserHelper.Spec.NPC, (int)ArcDPSEnums.TrashID.ConjuredPlayerSword, true);

            ComputeFightTargets(agentData, combatData, extensions);
            foreach (CombatItem c in combatData)
            {
                if (c.IsDamage(extensions) && c.SkillID == 52370)
                {
                    c.OverrideSrcAgent(sword.Agent);
                }
            }
        }
Exemple #5
0
        internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
        {
            var attackTargetEvents = combatData.Where(x => x.IsStateChange == ArcDPSEnums.StateChange.AttackTarget).ToList();
            var idsToUse           = new List <ArcDPSEnums.TargetID> {
                ArcDPSEnums.TargetID.TheDragonVoidJormag,
                ArcDPSEnums.TargetID.TheDragonVoidPrimordious,
                ArcDPSEnums.TargetID.TheDragonVoidKralkatorrik,
                ArcDPSEnums.TargetID.TheDragonVoidMordremoth,
                ArcDPSEnums.TargetID.TheDragonVoidZhaitan,
                ArcDPSEnums.TargetID.TheDragonVoidSooWon,
            };
            int index = 0;

            foreach (CombatItem at in attackTargetEvents)
            {
                AgentItem dragonVoid = agentData.GetAgent(at.DstAgent, at.Time);
                AgentItem atAgent    = agentData.GetAgent(at.SrcAgent, at.Time);
                // We take attack events, filter out the first one, present at spawn, that is always a non targetable event
                var targetables = combatData.Where(x => x.IsStateChange == ArcDPSEnums.StateChange.Targetable && x.SrcMatchesAgent(atAgent) && x.Time > 2000).ToList();
                // There are only two relevant attack targets, one represents the first five and the last one Soo Won
                if (!targetables.Any())
                {
                    continue;
                }
                var targetOns  = targetables.Where(x => x.DstAgent == 1).ToList();
                var targetOffs = targetables.Where(x => x.DstAgent == 0).ToList();
                // Events to be copied
                var posFacingHP = combatData.Where(x => x.SrcMatchesAgent(dragonVoid) && (x.IsStateChange == ArcDPSEnums.StateChange.Position || x.IsStateChange == ArcDPSEnums.StateChange.Rotation || x.IsStateChange == ArcDPSEnums.StateChange.MaxHealthUpdate)).ToList();
                //
                foreach (CombatItem targetOn in targetOns)
                {
                    // If Soo Won has been already created, we break
                    if (index >= idsToUse.Count)
                    {
                        break;
                    }
                    int        id        = (int)idsToUse[index++];
                    long       start     = targetOn.Time;
                    long       end       = fightData.FightEnd;
                    CombatItem targetOff = targetOffs.FirstOrDefault(x => x.Time > start);
                    // Don't split Soo won into two
                    if (targetOff != null && id != (int)ArcDPSEnums.TargetID.TheDragonVoidSooWon)
                    {
                        end = targetOff.Time;
                    }
                    AgentItem extra = agentData.AddCustomNPCAgent(start, end, dragonVoid.Name, dragonVoid.Spec, id, false, dragonVoid.Toughness, dragonVoid.Healing, dragonVoid.Condition, dragonVoid.Concentration, dragonVoid.HitboxWidth, dragonVoid.HitboxHeight);
                    foreach (CombatItem c in combatData)
                    {
                        if (extra.InAwareTimes(c.Time))
                        {
                            if (c.SrcMatchesAgent(dragonVoid, extensions))
                            {
                                // Avoid making the gadget go back to 100% hp on "death"
                                if (c.IsStateChange == ArcDPSEnums.StateChange.HealthUpdate && c.DstAgent == 10000 && c.Time > extra.LastAware - 2000)
                                {
                                    continue;
                                }
                                c.OverrideSrcAgent(extra.Agent);
                            }
                            if (c.DstMatchesAgent(dragonVoid, extensions))
                            {
                                c.OverrideDstAgent(extra.Agent);
                            }
                        }
                    }
                    var attackTargetCopy = new CombatItem(at);
                    attackTargetCopy.OverrideTime(extra.FirstAware);
                    attackTargetCopy.OverrideDstAgent(extra.Agent);
                    combatData.Add(attackTargetCopy);
                    foreach (CombatItem c in posFacingHP)
                    {
                        var cExtra = new CombatItem(c);
                        cExtra.OverrideTime(extra.FirstAware);
                        cExtra.OverrideSrcAgent(extra.Agent);
                        combatData.Add(cExtra);
                    }
                }
            }
            if (index == 0)
            {
                // Add dummy target as there are no dragon voids
                agentData.AddCustomNPCAgent(0, fightData.FightEnd, "Dummy Harvest Temple", Spec.NPC, (int)ArcDPSEnums.TargetID.DummyTarget, true);
                Targetless = true;
            }
            ComputeFightTargets(agentData, combatData, extensions);
            foreach (NPC target in Targets)
            {
                switch (target.ID)
                {
                case (int)ArcDPSEnums.TargetID.TheDragonVoidJormag:
                    target.OverrideName("The JormagVoid");
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidKralkatorrik:
                    target.OverrideName("The KralkatorrikVoid");
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidMordremoth:
                    target.OverrideName("The MordremothVoid");
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidPrimordious:
                    target.OverrideName("The PrimordiusVoid");
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidSooWon:
                    target.OverrideName("The SooWonVoid");
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidZhaitan:
                    target.OverrideName("The ZhaitanVoid");
                    break;
                }
            }
        }
        internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
        {
            //
            var attackTargetEvents = combatData.Where(x => x.IsStateChange == ArcDPSEnums.StateChange.AttackTarget).ToList();
            var idsToUse           = new List <ArcDPSEnums.TargetID> {
                ArcDPSEnums.TargetID.TheDragonVoidJormag,
                ArcDPSEnums.TargetID.TheDragonVoidPrimordus,
                ArcDPSEnums.TargetID.TheDragonVoidKralkatorrik,
                ArcDPSEnums.TargetID.TheDragonVoidMordremoth,
                ArcDPSEnums.TargetID.TheDragonVoidZhaitan,
                ArcDPSEnums.TargetID.TheDragonVoidSooWon,
            };
            int index = 0;

            foreach (CombatItem at in attackTargetEvents)
            {
                AgentItem dragonVoid = agentData.GetAgent(at.DstAgent, at.Time);
                AgentItem atAgent    = agentData.GetAgent(at.SrcAgent, at.Time);
                // We take attack events, filter out the first one, present at spawn, that is always a non targetable event
                var targetables = combatData.Where(x => x.IsStateChange == ArcDPSEnums.StateChange.Targetable && x.SrcMatchesAgent(atAgent) && x.Time > 2000).ToList();
                // There are only two relevant attack targets, one represents the first five and the last one Soo Won
                if (!targetables.Any())
                {
                    continue;
                }
                var targetOns  = targetables.Where(x => x.DstAgent == 1).ToList();
                var targetOffs = targetables.Where(x => x.DstAgent == 0).ToList();
                // Events to be copied
                var posFacingHPEventsToCopy = combatData.Where(x => x.SrcMatchesAgent(dragonVoid) && (x.IsStateChange == ArcDPSEnums.StateChange.MaxHealthUpdate)).ToList();
                posFacingHPEventsToCopy.AddRange(combatData.Where(x => x.SrcMatchesAgent(atAgent) && (x.IsStateChange == ArcDPSEnums.StateChange.Position || x.IsStateChange == ArcDPSEnums.StateChange.Rotation)));
                var attackTargetEventsToCopy = combatData.Where(x => x.SrcMatchesAgent(atAgent) && (x.IsStateChange == ArcDPSEnums.StateChange.AttackTarget)).ToList();
                //
                foreach (CombatItem targetOn in targetOns)
                {
                    // If Soo Won has been already created, we break
                    if (index >= idsToUse.Count)
                    {
                        break;
                    }
                    int        id        = (int)idsToUse[index++];
                    long       start     = targetOn.Time;
                    long       end       = fightData.FightEnd;
                    CombatItem targetOff = targetOffs.FirstOrDefault(x => x.Time > start);
                    // Don't split Soo won into two
                    if (targetOff != null && id != (int)ArcDPSEnums.TargetID.TheDragonVoidSooWon)
                    {
                        end = targetOff.Time;
                    }
                    AgentItem extra        = agentData.AddCustomNPCAgent(start, end, dragonVoid.Name, dragonVoid.Spec, id, false, dragonVoid.Toughness, dragonVoid.Healing, dragonVoid.Condition, dragonVoid.Concentration, atAgent.HitboxWidth, atAgent.HitboxHeight);
                    ulong     lastHPUpdate = ulong.MaxValue;
                    foreach (CombatItem c in combatData)
                    {
                        if (extra.InAwareTimes(c.Time))
                        {
                            if (c.SrcMatchesAgent(dragonVoid, extensions))
                            {
                                // Avoid making the gadget go back to 100% hp on "death"
                                if (c.IsStateChange == ArcDPSEnums.StateChange.HealthUpdate)
                                {
                                    // Discard hp update that goes up close to death time
                                    if (c.DstAgent >= lastHPUpdate && c.Time > extra.LastAware - 2000)
                                    {
                                        continue;
                                    }
                                    // Remember last hp
                                    lastHPUpdate = c.DstAgent;
                                }
                                c.OverrideSrcAgent(extra.Agent);
                            }
                            // Redirect effects from attack target to main body
                            if (c.IsStateChange == ArcDPSEnums.StateChange.Effect && c.SrcMatchesAgent(atAgent, extensions))
                            {
                                c.OverrideSrcAgent(extra.Agent);
                            }
                            if (c.DstMatchesAgent(dragonVoid, extensions))
                            {
                                c.OverrideDstAgent(extra.Agent);
                            }
                        }
                    }
                    var attackTargetCopy = new CombatItem(at);
                    attackTargetCopy.OverrideTime(extra.FirstAware);
                    attackTargetCopy.OverrideDstAgent(extra.Agent);
                    combatData.Add(attackTargetCopy);
                    foreach (CombatItem c in posFacingHPEventsToCopy)
                    {
                        var cExtra = new CombatItem(c);
                        cExtra.OverrideTime(extra.FirstAware);
                        cExtra.OverrideSrcAgent(extra.Agent);
                        combatData.Add(cExtra);
                    }
                    foreach (CombatItem c in attackTargetEventsToCopy)
                    {
                        var cExtra = new CombatItem(c);
                        cExtra.OverrideTime(extra.FirstAware);
                        cExtra.OverrideDstAgent(extra.Agent);
                        //combatData.Add(cExtra);
                    }
                }
            }
            //
            IReadOnlyList <AgentItem> voidAmalgamates = agentData.GetNPCsByID((int)ArcDPSEnums.TrashID.VoidAmalgamate);
            bool needRefresh = false;

            foreach (AgentItem voidAmal in voidAmalgamates)
            {
                if (combatData.Where(x => x.SkillID == VoidShell && x.IsBuffApply() && x.SrcMatchesAgent(voidAmal)).Any())
                {
                    voidAmal.OverrideID(ArcDPSEnums.TrashID.PushableVoidAmalgamate);
                    needRefresh = true;
                }
            }
            AgentItem dragonBodyVoidAmalgamate = voidAmalgamates.MaxBy(x => x.LastAware - x.FirstAware);

            if (dragonBodyVoidAmalgamate != null)
            {
                dragonBodyVoidAmalgamate.OverrideID(ArcDPSEnums.TrashID.DragonBodyVoidAmalgamate);
                needRefresh = true;
            }
            if (needRefresh)
            {
                agentData.Refresh();
            }
            if (index == 0)
            {
                // Add dummy target as there are no dragon voids
                agentData.AddCustomNPCAgent(0, fightData.FightEnd, "Dummy Harvest Temple", Spec.NPC, (int)ArcDPSEnums.TargetID.DummyTarget, true);
                Targetless = true;
            }
            //
            ComputeFightTargets(agentData, combatData, extensions);
            //
            int  purificationID = 0;
            bool needRedirect   = false;

            (HashSet <ulong> jormagDamagingAgents, NPC jormag)       = (new HashSet <ulong>(), null);
            (HashSet <ulong> primordusDamagingAgents, NPC primordus) = (new HashSet <ulong>(), null);
            (HashSet <ulong> kralkDamagingAgents, NPC kralk)         = (new HashSet <ulong>(), null);
            (HashSet <ulong> mordDamagingAgents, NPC mord)           = (new HashSet <ulong>(), null);
            (HashSet <ulong> zhaitanDamagingAgents, NPC zhaitan)     = (new HashSet <ulong>(), null);
            (HashSet <ulong> soowonDamagingAgents, NPC soowon)       = (new HashSet <ulong>(), null);
            foreach (NPC target in Targets)
            {
                switch (target.ID)
                {
                case (int)ArcDPSEnums.TargetID.TheDragonVoidJormag:
                    target.OverrideName("The JormagVoid");
                    jormag       = target;
                    needRedirect = true;
                    var jormagAttacks = new HashSet <long>()
                    {
                        BreathOfJormag1,
                        BreathOfJormag2,
                        BreathOfJormag3,
                    };
                    jormagDamagingAgents = new HashSet <ulong>(combatData.Where(x => x.IsDamage() && jormagAttacks.Contains(x.SkillID)).Select(x => x.SrcAgent));
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidKralkatorrik:
                    target.OverrideName("The KralkatorrikVoid");
                    kralk        = target;
                    needRedirect = true;
                    var kralkAttacks = new HashSet <long>()
                    {
                        BrandingBeam,
                        CrystalBarrage,
                        VoidPoolKralkatorrik
                    };
                    kralkDamagingAgents = new HashSet <ulong>(combatData.Where(x => x.IsDamage() && kralkAttacks.Contains(x.SkillID)).Select(x => x.SrcAgent));
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidMordremoth:
                    target.OverrideName("The MordremothVoid");
                    mord         = target;
                    needRedirect = true;
                    var mordAttacks = new HashSet <long>()
                    {
                        Shockwave,
                        PoisonRoar,
                    };
                    mordDamagingAgents = new HashSet <ulong>(combatData.Where(x => x.IsDamage() && mordAttacks.Contains(x.SkillID)).Select(x => x.SrcAgent));
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidPrimordus:
                    target.OverrideName("The PrimordusVoid");
                    primordus    = target;
                    needRedirect = true;
                    var primordusAttacks = new HashSet <long>()
                    {
                        LavaSlam,
                        JawsOfDestruction,
                    };
                    primordusDamagingAgents = new HashSet <ulong>(combatData.Where(x => x.IsDamage() && primordusAttacks.Contains(x.SkillID)).Select(x => x.SrcAgent));
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidSooWon:
                    target.OverrideName("The SooWonVoid");
                    soowon       = target;
                    needRedirect = true;
                    var soowonAttacks = new HashSet <long>()
                    {
                        TsunamiSlam1,
                        TsunamiSlam2,
                        ClawSlap,
                        MagicHail,
                        VoidPurge,
                        VoidPoolSooWon,
                        TormentOfTheVoid
                    };
                    soowonDamagingAgents = new HashSet <ulong>(combatData.Where(x => x.IsDamage() && soowonAttacks.Contains(x.SkillID)).Select(x => x.SrcAgent));
                    break;

                case (int)ArcDPSEnums.TargetID.TheDragonVoidZhaitan:
                    target.OverrideName("The ZhaitanVoid");
                    zhaitan      = target;
                    needRedirect = true;
                    var zhaiAttacks = new HashSet <long>()
                    {
                        ScreamOfZhaitan,
                        SlamZhaitan,
                        PutridDeluge
                    };
                    zhaitanDamagingAgents = new HashSet <ulong>(combatData.Where(x => x.IsDamage() && zhaiAttacks.Contains(x.SkillID)).Select(x => x.SrcAgent));
                    break;

                case (int)ArcDPSEnums.TrashID.PushableVoidAmalgamate:
                case (int)ArcDPSEnums.TrashID.KillableVoidAmalgamate:
                    target.OverrideName("Heart " + (++purificationID));
                    break;
                }
            }
            if (needRedirect)
            {
                foreach (CombatItem cbt in combatData)
                {
                    if (cbt.IsDamage())
                    {
                        // sanity check
                        if (agentData.GetAgent(cbt.SrcAgent, cbt.Time).GetFinalMaster().IsPlayer)
                        {
                            continue;
                        }
                        if (jormagDamagingAgents.Any(x => cbt.SrcAgent == x && jormag.FirstAware <= cbt.Time && cbt.Time <= jormag.LastAware))
                        {
                            cbt.OverrideSrcAgent(jormag.AgentItem.Agent);
                        }
                        else if (primordusDamagingAgents.Any(x => cbt.SrcAgent == x && primordus.FirstAware <= cbt.Time && cbt.Time <= primordus.LastAware))
                        {
                            cbt.OverrideSrcAgent(primordus.AgentItem.Agent);
                        }
                        else if (kralkDamagingAgents.Any(x => cbt.SrcAgent == x && kralk.FirstAware <= cbt.Time && cbt.Time <= kralk.LastAware))
                        {
                            cbt.OverrideSrcAgent(kralk.AgentItem.Agent);
                        }
                        else if (mordDamagingAgents.Any(x => cbt.SrcAgent == x && mord.FirstAware <= cbt.Time && cbt.Time <= mord.LastAware))
                        {
                            cbt.OverrideSrcAgent(mord.AgentItem.Agent);
                        }
                        else if (zhaitanDamagingAgents.Any(x => cbt.SrcAgent == x && zhaitan.FirstAware <= cbt.Time && cbt.Time <= zhaitan.LastAware))
                        {
                            cbt.OverrideSrcAgent(zhaitan.AgentItem.Agent);
                        }
                        else if (soowonDamagingAgents.Any(x => cbt.SrcAgent == x && soowon.FirstAware <= cbt.Time && cbt.Time <= soowon.LastAware))
                        {
                            cbt.OverrideSrcAgent(soowon.AgentItem.Agent);
                        }
                    }
                }
            }
        }
 internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
 {
     agentData.AddCustomNPCAgent(0, fightData.FightEnd, "River of Souls", Spec.NPC, (int)ArcDPSEnums.TargetID.DummyTarget, true);
     ComputeFightTargets(agentData, combatData, extensions);
 }
 internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
 {
     // has breakbar state into
     if (combatData.Any(x => x.IsStateChange == ArcDPSEnums.StateChange.BreakbarState))
     {
         var sacrificeList      = combatData.Where(x => x.SkillID == MatthiasSacrifice && !x.IsExtension && (x.IsBuffRemove == ArcDPSEnums.BuffRemove.All || x.IsBuffApply())).ToList();
         var sacrificeStartList = sacrificeList.Where(x => x.IsBuffRemove == ArcDPSEnums.BuffRemove.None).ToList();
         var sacrificeEndList   = sacrificeList.Where(x => x.IsBuffRemove == ArcDPSEnums.BuffRemove.All).ToList();
         var copies             = new List <CombatItem>();
         for (int i = 0; i < sacrificeStartList.Count; i++)
         {
             //
             long sacrificeStartTime = sacrificeStartList[i].Time;
             long sacrificeEndTime   = i < sacrificeEndList.Count ? sacrificeEndList[i].Time : fightData.FightEnd;
             //
             AgentItem sacrifice = agentData.GetAgentByType(AgentItem.AgentType.Player).FirstOrDefault(x => x == agentData.GetAgent(sacrificeStartList[i].DstAgent, sacrificeStartList[i].Time));
             if (sacrifice == null)
             {
                 continue;
             }
             AgentItem sacrificeCrystal = agentData.AddCustomNPCAgent(sacrificeStartTime, sacrificeEndTime + 100, "Sacrificed " + (i + 1) + " " + sacrifice.Name.Split('\0')[0], sacrifice.Spec, (int)ArcDPSEnums.TrashID.MatthiasSacrificeCrystal, false);
             foreach (CombatItem cbt in combatData)
             {
                 if (!sacrificeCrystal.InAwareTimes(cbt.Time))
                 {
                     continue;
                 }
                 bool skip = !(cbt.DstMatchesAgent(sacrifice, extensions) || cbt.SrcMatchesAgent(sacrifice, extensions));
                 if (skip)
                 {
                     continue;
                 }
                 // redirect damage events
                 if (cbt.IsDamage(extensions))
                 {
                     // only redirect incoming damage
                     if (cbt.DstMatchesAgent(sacrifice, extensions))
                     {
                         cbt.OverrideDstAgent(sacrificeCrystal.Agent);
                     }
                 }
                 // copy the rest
                 else
                 {
                     var copy = new CombatItem(cbt);
                     if (copy.DstMatchesAgent(sacrifice, extensions))
                     {
                         copy.OverrideDstAgent(sacrificeCrystal.Agent);
                     }
                     if (copy.SrcMatchesAgent(sacrifice, extensions))
                     {
                         copy.OverrideSrcAgent(sacrificeCrystal.Agent);
                     }
                     copies.Add(copy);
                 }
             }
         }
         if (copies.Any())
         {
             combatData.AddRange(copies);
         }
     }
     ComputeFightTargets(agentData, combatData, extensions);
     foreach (AbstractSingleActor target in Targets)
     {
         if (target.ID == (int)ArcDPSEnums.TrashID.MatthiasSacrificeCrystal)
         {
             target.SetManualHealth(100000);
         }
     }
 }