internal override void AdjustCombatEvent(CombatItem combatItem, AgentData agentData) { if (!IsHealingEvent(combatItem) && !IsBarrierEvent(combatItem)) { return; } // Prefer instid fetch for healing events AgentItem src = agentData.GetAgentByInstID(combatItem.SrcInstid, combatItem.Time); combatItem.OverrideSrcAgent(src.Agent); AgentItem dst = agentData.GetAgentByInstID(combatItem.DstInstid, combatItem.Time); combatItem.OverrideDstAgent(dst.Agent); }
internal override void EIEvtcParse(ulong gw2Build, FightData fightData, AgentData agentData, List <CombatItem> combatData, List <AbstractSingleActor> friendlies, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions) { // has breakbar state into if (combatData.Any(x => x.IsStateChange == ArcDPSEnums.StateChange.BreakbarState)) { long sacrificeID = 34442; var sacrificeList = combatData.Where(x => x.SkillID == sacrificeID && !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; // Player sacrifice = friendlies.OfType <Player>().FirstOrDefault(x => x.AgentItem == agentData.GetAgent(sacrificeStartList[i].DstAgent, sacrificeStartList[i].Time)); if (sacrifice == null) { continue; } AgentItem sacrificeCrystal = agentData.AddCustomAgent(sacrificeStartTime, sacrificeEndTime + 100, AgentItem.AgentType.NPC, "Sacrificed " + (i + 1) + " " + sacrifice.Character, sacrifice.Spec, (int)ArcDPSEnums.TrashID.MatthiasSacrificeCrystal, false); foreach (CombatItem cbt in combatData) { if (!sacrificeCrystal.InAwareTimes(cbt.Time)) { continue; } bool skip = !(cbt.DstMatchesAgent(sacrifice.AgentItem, extensions) || cbt.SrcMatchesAgent(sacrifice.AgentItem, extensions)); if (skip) { continue; } // redirect damage events if (cbt.IsDamage(extensions)) { // only redirect incoming damage if (cbt.DstMatchesAgent(sacrifice.AgentItem, extensions)) { cbt.OverrideDstAgent(sacrificeCrystal.Agent); } } // copy the rest else { var copy = new CombatItem(cbt); if (copy.DstMatchesAgent(sacrifice.AgentItem, extensions)) { copy.OverrideDstAgent(sacrificeCrystal.Agent); } if (copy.SrcMatchesAgent(sacrifice.AgentItem, 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); } } }
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); } } } } }