private static (long timeCasting, int casts, int timeSaved, int timeWasted) GetCastValues(IReadOnlyList <AbstractCastEvent> clList, PhaseData phase) { long timeCasting = 0; int casts = 0, timeWasted = 0, timeSaved = 0; foreach (AbstractCastEvent cl in clList) { if (phase.InInterval(cl.Time)) { casts++; switch (cl.Status) { case AbstractCastEvent.AnimationStatus.Interrupted: timeWasted += cl.SavedDuration; break; case AbstractCastEvent.AnimationStatus.Reduced: timeSaved += cl.SavedDuration; break; } } timeCasting += Math.Min(cl.EndTime, phase.End) - Math.Max(cl.Time, phase.Start); } return(timeCasting, casts, timeSaved, timeWasted); }
private static List <List <object> > GetMechanicChartPoints(IReadOnlyList <MechanicEvent> mechanicLogs, PhaseData phase, ParsedEvtcLog log, bool enemyMechanic) { var res = new List <List <object> >(); if (!enemyMechanic) { var playerIndex = new Dictionary <AbstractSingleActor, int>(); for (int p = 0; p < log.Friendlies.Count; p++) { playerIndex.Add(log.Friendlies[p], p); res.Add(new List <object>()); } foreach (MechanicEvent ml in mechanicLogs.Where(x => phase.InInterval(x.Time))) { double time = (ml.Time - phase.Start) / 1000.0; if (playerIndex.TryGetValue(ml.Actor, out int p)) { res[p].Add(time); } } } else { var targetIndex = new Dictionary <AbstractSingleActor, int>(); for (int p = 0; p < phase.Targets.Count; p++) { targetIndex.Add(phase.Targets[p], p); res.Add(new List <object>()); } res.Add(new List <object>()); foreach (MechanicEvent ml in mechanicLogs.Where(x => phase.InInterval(x.Time))) { double time = (ml.Time - phase.Start) / 1000.0; if (targetIndex.TryGetValue(ml.Actor, out int p)) { res[p].Add(time); } else { res[res.Count - 1].Add(new object[] { time, ml.Actor.Character }); } } } return(res); }
public static List <List <object> > GetMechanicChartPoints(List <MechanicEvent> mechanicLogs, PhaseData phase, ParsedLog log, bool enemyMechanic) { List <List <object> > res = new List <List <object> >(); if (!enemyMechanic) { Dictionary <DummyActor, int> playerIndex = new Dictionary <DummyActor, int>(); for (var p = 0; p < log.PlayerList.Count; p++) { playerIndex.Add(log.PlayerList[p], p); res.Add(new List <object>()); } foreach (MechanicEvent ml in mechanicLogs.Where(x => phase.InInterval(x.Time))) { double time = (ml.Time - phase.Start) / 1000.0; if (playerIndex.TryGetValue(ml.Actor, out int p)) { res[p].Add(time); } } } else { Dictionary <DummyActor, int> targetIndex = new Dictionary <DummyActor, int>(); for (var p = 0; p < phase.Targets.Count; p++) { targetIndex.Add(phase.Targets[p], p); res.Add(new List <object>()); } res.Add(new List <object>()); foreach (MechanicEvent ml in mechanicLogs.Where(x => phase.InInterval(x.Time))) { double time = (ml.Time - phase.Start) / 1000.0; if (targetIndex.TryGetValue(ml.Actor, out int p)) { res[p].Add(time); } else { res[res.Count - 1].Add(new object[] { time, ml.Actor.Character }); } } } return(res); }
protected void AddTargetsToPhase(PhaseData phase, List <ushort> ids, ParsedLog log) { foreach (Boss target in Targets) { if (ids.Contains(target.ID) && phase.InInterval(target.FirstAware, log.FightData.FightStart)) { phase.Targets.Add(target); } } phase.OverrideTimes(log.FightData.FightStart); }
protected void AddTargetsToPhaseAndFit(PhaseData phase, List <int> ids, ParsedEvtcLog log) { foreach (NPC target in Targets) { if (ids.Contains(target.ID) && phase.InInterval(Math.Max(target.FirstAware, 0))) { phase.AddTarget(target); } } phase.OverrideTimes(log); }
protected void AddTargetsToPhase(PhaseData phase, List <ushort> ids, ParsedLog log) { foreach (Target target in Targets) { if (ids.Contains(target.ID) && phase.InInterval(Math.Max(log.FightData.ToFightSpace(target.FirstAware), 0))) { phase.Targets.Add(target); } } phase.OverrideTimes(log); }
private static List <int[]> GetMechanicData(IReadOnlyCollection <Mechanic> presMech, ParsedEvtcLog log, AbstractActor actor, PhaseData phase) { var res = new List <int[]>(); foreach (Mechanic mech in presMech) { int filterCount = 0; int count = 0; if (mech.InternalCooldown > 0) { long timeFilter = 0; var mls = log.MechanicData.GetMechanicLogs(log, mech).Where(x => x.Actor.Agent == actor.Agent).ToList(); foreach (MechanicEvent ml in mls) { bool inInterval = phase.InInterval(ml.Time); if (ml.Time - timeFilter < mech.InternalCooldown)//ICD check { if (inInterval) { filterCount++; } } timeFilter = ml.Time; if (inInterval) { count++; } } } else { count = log.MechanicData.GetMechanicLogs(log, mech).Where(x => x.Actor.Agent == actor.Agent && phase.InInterval(x.Time)).Count(); } res.Add(new int[] { count - filterCount, count }); } return(res); }
private void CreateMechanicTable(int phaseIndex) { HashSet <Mechanic> presMech = _log.MechanicData.GetPresentPlayerMechs(_log, phaseIndex); //Dictionary<string, HashSet<Mechanic>> presEnemyMech = log.MechanicData.getPresentEnemyMechs(phaseIndex); PhaseData phase = _phases[phaseIndex]; //List<AbstractMasterPlayer> enemyList = log.MechanicData.getEnemyList(phaseIndex); int countLines = 0; if (presMech.Count > 0) { WriteCell("Name"); foreach (Mechanic mech in presMech) { WriteCell("\"" + mech.Description + "\""); } NewLine(); foreach (Player p in _log.PlayerList) { WriteCell(p.Character); foreach (Mechanic mech in presMech) { int count = _log.MechanicData.GetMechanicLogs(_log, mech).Count(x => x.Actor.Agent == p.Agent && phase.InInterval(x.Time)); WriteCell(count.ToString()); } NewLine(); countLines++; } } while (countLines < 15)//so each graph has equal spacing { NewLine(); countLines++; } }
public static List <int[]> GetMechanicData(HashSet <Mechanic> presMech, ParsedLog log, AbstractActor actor, PhaseData phase) { var res = new List <int[]>(); foreach (Mechanic mech in presMech) { long timeFilter = 0; int filterCount = 0; var mls = log.MechanicData.GetMechanicLogs(log, mech).Where(x => x.Actor.Agent == actor.Agent && phase.InInterval(x.Time)).ToList(); int count = mls.Count; foreach (MechanicEvent ml in mls) { if (mech.InternalCooldown != 0 && ml.Time - timeFilter < mech.InternalCooldown)//ICD check { filterCount++; } timeFilter = ml.Time; } res.Add(new int[] { count - filterCount, count }); } return(res); }
internal override List <PhaseData> GetPhases(ParsedEvtcLog log, bool requirePhases) { List <PhaseData> phases = GetInitialPhase(log); AbstractSingleActor ca = Targets.FirstOrDefault(x => x.ID == (int)ArcDPSEnums.TargetID.ConjuredAmalgamate); if (ca == null) { throw new MissingKeyActorsException("Conjured Amalgamate not found"); } phases[0].AddTarget(ca); if (!requirePhases) { return(phases); } phases.AddRange(GetPhasesByInvul(log, 52255, ca, true, false)); for (int i = 1; i < phases.Count; i++) { string name; PhaseData phase = phases[i]; if (i % 2 == 1) { name = "Arm Phase"; } else { name = "Burn Phase"; phase.AddTarget(ca); } phase.Name = name; } AbstractSingleActor leftArm = Targets.FirstOrDefault(x => x.ID == (int)ArcDPSEnums.TargetID.CALeftArm); if (leftArm != null) { List <long> targetables = GetTargetableTimes(log, leftArm); for (int i = 1; i < phases.Count; i += 2) { PhaseData phase = phases[i]; if (targetables.Exists(x => phase.InInterval(x))) { phase.Name = "Left " + phase.Name; phase.AddTarget(leftArm); } } } AbstractSingleActor rightArm = Targets.FirstOrDefault(x => x.ID == (int)ArcDPSEnums.TargetID.CARightArm); if (rightArm != null) { List <long> targetables = GetTargetableTimes(log, rightArm); for (int i = 1; i < phases.Count; i += 2) { PhaseData phase = phases[i]; if (targetables.Exists(x => phase.InInterval(x))) { if (phase.Name.Contains("Left")) { phase.Name = "Both Arms Phase"; } else { phase.Name = "Right " + phase.Name; } phase.AddTarget(rightArm); } } } return(phases); }
private static object[] GetDMGDtoItem(SkillItem skill, List <AbstractHealthDamageEvent> damageLogs, Dictionary <SkillItem, List <AbstractCastEvent> > castLogsBySkill, Dictionary <long, SkillItem> usedSkills, Dictionary <long, Buff> usedBoons, BuffsContainer boons, PhaseData phase) { int totaldamage = 0, mindamage = int.MaxValue, maxdamage = int.MinValue, hits = 0, crit = 0, critDamage = 0, connectedHits = 0, flank = 0, againstMoving = 0, glance = 0, shieldDamage = 0; bool IsIndirectDamage = false; foreach (AbstractHealthDamageEvent dl in damageLogs) { IsIndirectDamage = IsIndirectDamage || dl is NonDirectHealthDamageEvent; int curdmg = dl.HealthDamage; totaldamage += curdmg; hits += dl.DoubleProcHit ? 0 : 1; if (dl.HasHit) { if (curdmg < mindamage) { mindamage = curdmg; } if (curdmg > maxdamage) { maxdamage = curdmg; } connectedHits++; if (dl.HasCrit) { crit++; critDamage += dl.HealthDamage; } if (dl.HasGlanced) { glance++; } if (dl.IsFlanking) { flank++; } if (dl.AgainstMoving) { againstMoving++; } } shieldDamage += dl.ShieldDamage; } if (IsIndirectDamage) { if (!usedBoons.ContainsKey(skill.ID)) { if (boons.BuffsByIds.TryGetValue(skill.ID, out Buff buff)) { usedBoons.Add(buff.ID, buff); } else { SkillItem aux = skill; var auxBoon = new Buff(aux.Name, aux.ID, aux.Icon); usedBoons.Add(auxBoon.ID, auxBoon); } } } else { if (!usedSkills.ContainsKey(skill.ID)) { usedSkills.Add(skill.ID, skill); } } long timeCasting = 0; int casts = 0, timeWasted = 0, timeSaved = 0; if (!IsIndirectDamage && castLogsBySkill != null && castLogsBySkill.TryGetValue(skill, out List <AbstractCastEvent> clList)) { foreach (AbstractCastEvent cl in clList) { if (phase.InInterval(cl.Time)) { casts++; switch (cl.Status) { case AbstractCastEvent.AnimationStatus.Interrupted: timeWasted += cl.SavedDuration; break; case AbstractCastEvent.AnimationStatus.Reduced: timeSaved += cl.SavedDuration; break; } } timeCasting += Math.Min(cl.EndTime, phase.End) - Math.Max(cl.Time, phase.Start); } } object[] skillItem = { IsIndirectDamage, skill.ID, totaldamage, mindamage == int.MaxValue ? 0 : mindamage, maxdamage == int.MinValue ? 0 : maxdamage, IsIndirectDamage ? 0 : casts, connectedHits, IsIndirectDamage ? 0 : crit, IsIndirectDamage ? 0 : flank, IsIndirectDamage ? 0 : glance, IsIndirectDamage ? 0 : -timeWasted / 1000.0, IsIndirectDamage ? 0 : timeSaved / 1000.0, shieldDamage, IsIndirectDamage ? 0 : critDamage, hits, IsIndirectDamage ? 0 : timeCasting, againstMoving }; return(skillItem); }
private static List <object[]> BuildDMGDistBodyData(ParsedEvtcLog log, IReadOnlyList <AbstractCastEvent> casting, IReadOnlyList <AbstractHealthDamageEvent> damageLogs, Dictionary <long, SkillItem> usedSkills, Dictionary <long, Buff> usedBuffs, PhaseData phase) { var list = new List <object[]>(); var castLogsBySkill = casting.GroupBy(x => x.Skill).ToDictionary(x => x.Key, x => x.ToList()); var damageLogsBySkill = damageLogs.GroupBy(x => x.Skill).ToDictionary(x => x.Key, x => x.ToList()); var conditionsById = log.StatisticsHelper.PresentConditions.ToDictionary(x => x.ID); foreach (KeyValuePair <SkillItem, List <AbstractHealthDamageEvent> > pair in damageLogsBySkill) { list.Add(GetDMGDtoItem(pair.Key, pair.Value, castLogsBySkill, usedSkills, usedBuffs, log.Buffs, phase)); } // non damaging foreach (KeyValuePair <SkillItem, List <AbstractCastEvent> > pair in castLogsBySkill) { if (damageLogsBySkill.ContainsKey(pair.Key)) { continue; } if (!usedSkills.ContainsKey(pair.Key.ID)) { usedSkills.Add(pair.Key.ID, pair.Key); } long timeCasting = 0; int casts = 0; int timeWasted = 0, timeSaved = 0; foreach (AbstractCastEvent cl in pair.Value) { if (phase.InInterval(cl.Time)) { casts++; switch (cl.Status) { case AbstractCastEvent.AnimationStatus.Interrupted: timeWasted += cl.SavedDuration; break; case AbstractCastEvent.AnimationStatus.Reduced: timeSaved += cl.SavedDuration; break; } } timeCasting += Math.Min(cl.EndTime, phase.End) - Math.Max(cl.Time, phase.Start); } object[] skillData = { false, pair.Key.ID, 0, -1, 0, casts, 0, 0, 0, 0, -timeWasted / 1000.0, timeSaved / 1000.0, 0, 0, 0, timeCasting, 0 }; list.Add(skillData); } return(list); }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { List <PhaseData> phases = GetInitialPhase(log); NPC ca = Targets.Find(x => x.ID == (int)ParseEnum.TargetIDS.ConjuredAmalgamate); if (ca == null) { throw new InvalidOperationException("Error Encountered: Conjured Amalgamate not found"); } phases[0].Targets.Add(ca); if (!requirePhases) { return(phases); } phases.AddRange(GetPhasesByInvul(log, 52255, ca, true, false)); for (int i = 1; i < phases.Count; i++) { string name; PhaseData phase = phases[i]; if (i % 2 == 1) { name = "Arm Phase"; } else { name = "Burn Phase"; phase.Targets.Add(ca); } phase.Name = name; } NPC leftArm = Targets.Find(x => x.ID == (int)ParseEnum.TargetIDS.CALeftArm); if (leftArm != null) { List <long> targetables = GetTargetableTimes(log, leftArm); for (int i = 1; i < phases.Count; i += 2) { PhaseData phase = phases[i]; if (targetables.Exists(x => phase.InInterval(x))) { phase.Name = "Left " + phase.Name; phase.Targets.Add(leftArm); } } } NPC rightArm = Targets.Find(x => x.ID == (int)ParseEnum.TargetIDS.CARightArm); if (rightArm != null) { List <long> targetables = GetTargetableTimes(log, rightArm); for (int i = 1; i < phases.Count; i += 2) { PhaseData phase = phases[i]; if (targetables.Exists(x => phase.InInterval(x))) { if (phase.Name.Contains("Left")) { phase.Name = "Both Arms Phase"; } else { phase.Name = "Right " + phase.Name; } phase.Targets.Add(rightArm); } } } return(phases); }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { long start = 0; long end = 0; List <PhaseData> phases = GetInitialPhase(log); Target ca = Targets.Find(x => x.ID == (ushort)ParseEnum.TargetIDS.ConjuredAmalgamate); if (ca == null) { throw new InvalidOperationException("Conjurate Amalgamate not found"); } phases[0].Targets.Add(ca); if (!requirePhases) { return(phases); } List <CombatItem> CAInvul = GetFilteredList(log, 52255, ca, false); for (int i = 0; i < CAInvul.Count; i++) { CombatItem invul = CAInvul[i]; if (invul.IsBuffRemove != ParseEnum.BuffRemove.None) { end = Math.Min(log.FightData.ToFightSpace(invul.Time), log.FightData.FightDuration); phases.Add(new PhaseData(start, end)); if (i == CAInvul.Count - 1) { phases.Add(new PhaseData(end, log.FightData.FightDuration)); } } else { start = Math.Min(log.FightData.ToFightSpace(invul.Time), log.FightData.FightDuration); phases.Add(new PhaseData(end, start)); if (i == CAInvul.Count - 1) { phases.Add(new PhaseData(start, log.FightData.FightDuration)); } } } phases.RemoveAll(x => x.GetDuration() < 1000); for (int i = 1; i < phases.Count; i++) { string name; PhaseData phase = phases[i]; if (i % 2 == 1) { name = "Arm Phase"; } else { name = "Burn Phase"; phase.Targets.Add(ca); } phase.Name = name; } Target leftArm = Targets.Find(x => x.ID == (ushort)ParseEnum.TargetIDS.CALeftArm); if (leftArm != null) { List <long> leftArmDown = log.GetBoonData(52430).Where(x => x.IsBuffRemove == ParseEnum.BuffRemove.All && x.SrcInstid == leftArm.InstID).Select(x => log.FightData.ToFightSpace(x.Time)).ToList(); for (int i = 1; i < phases.Count; i += 2) { PhaseData phase = phases[i]; if (leftArmDown.Exists(x => phase.InInterval(x))) { phase.Name = "Left " + phase.Name; phase.Targets.Add(leftArm); } } } Target rightArm = Targets.Find(x => x.ID == (ushort)ParseEnum.TargetIDS.CARightArm); if (rightArm != null) { List <long> rightArmDown = log.GetBoonData(52430).Where(x => x.IsBuffRemove == ParseEnum.BuffRemove.All && x.SrcInstid == rightArm.InstID).Select(x => log.FightData.ToFightSpace(x.Time)).ToList(); for (int i = 1; i < phases.Count; i += 2) { PhaseData phase = phases[i]; if (rightArmDown.Exists(x => phase.InInterval(x))) { if (phase.Name.Contains("Left")) { phase.Name = "Both Arms Phase"; } else { phase.Name = "Right " + phase.Name; } phase.Targets.Add(rightArm); } } } return(phases); }
private static object[] GetHealingToItem(SkillItem skill, List <EXTAbstractHealingEvent> healingLogs, Dictionary <SkillItem, List <AbstractCastEvent> > castLogsBySkill, Dictionary <long, SkillItem> usedSkills, Dictionary <long, Buff> usedBoons, BuffsContainer boons, PhaseData phase) { int totalhealing = 0, totaldownedhealing = 0, minhealing = int.MaxValue, maxhealing = int.MinValue, hits = 0; bool isIndirectHealing = false; foreach (EXTAbstractHealingEvent dl in healingLogs) { isIndirectHealing = isIndirectHealing || dl is EXTNonDirectHealingEvent; int curdmg = dl.HealingDone; totalhealing += curdmg; hits++; if (curdmg < minhealing) { minhealing = curdmg; } if (curdmg > maxhealing) { maxhealing = curdmg; } if (dl.AgainstDowned) { totaldownedhealing += dl.HealingDone; } } if (isIndirectHealing) { if (!usedBoons.ContainsKey(skill.ID)) { if (boons.BuffsByIds.TryGetValue(skill.ID, out Buff buff)) { usedBoons.Add(buff.ID, buff); } else { SkillItem aux = skill; var auxBoon = new Buff(aux.Name, aux.ID, aux.Icon); usedBoons.Add(auxBoon.ID, auxBoon); } } } else { if (!usedSkills.ContainsKey(skill.ID)) { usedSkills.Add(skill.ID, skill); } } if (castLogsBySkill != null && castLogsBySkill.ContainsKey(skill)) { isIndirectHealing = false; } long timeCasting = 0; int casts = 0, timeWasted = 0, timeSaved = 0; if (!isIndirectHealing && castLogsBySkill != null && castLogsBySkill.TryGetValue(skill, out List <AbstractCastEvent> clList)) { foreach (AbstractCastEvent cl in clList) { if (phase.InInterval(cl.Time)) { casts++; switch (cl.Status) { case AbstractCastEvent.AnimationStatus.Interrupted: timeWasted += cl.SavedDuration; break; case AbstractCastEvent.AnimationStatus.Reduced: timeSaved += cl.SavedDuration; break; } } timeCasting += Math.Min(cl.EndTime, phase.End) - Math.Max(cl.Time, phase.Start); } } object[] skillItem = { isIndirectHealing, skill.ID, totalhealing, minhealing == int.MaxValue ? 0 : minhealing, maxhealing == int.MinValue ? 0 : maxhealing, isIndirectHealing ? 0 : casts, isIndirectHealing ? 0 : -timeWasted / 1000.0, isIndirectHealing ? 0 : timeSaved / 1000.0, hits, isIndirectHealing ? 0 : timeCasting, totaldownedhealing }; return(skillItem); }
private IEnumerable <AbstractSingleActor> GetHPScarletPhantoms(PhaseData phase) { return(Targets.Where(x => (x.ID == (int)ArcDPSEnums.TrashID.ScarletPhantomHP || x.ID == (int)ArcDPSEnums.TrashID.ScarletPhantomHP2) && (phase.InInterval(x.FirstAware) || phase.InInterval(x.LastAware)))); }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { long start = 0; long end = 0; List <PhaseData> phases = GetInitialPhase(log); Boss qadim = Targets.Find(x => x.ID == (ushort)ParseEnum.BossIDS.Qadim); if (qadim == null) { throw new InvalidOperationException("Qadim not found"); } phases[0].Targets.Add(qadim); if (!requirePhases) { return(phases); } List <long> moltenArmor = GetFilteredList(log, 52329, qadim).Select(x => x.Time - log.FightData.FightStart).Distinct().ToList(); for (int i = 1; i < moltenArmor.Count; i++) { if (i % 2 == 0) { end = Math.Min(moltenArmor[i], log.FightData.FightDuration); phases.Add(new PhaseData(start, end)); if (i == moltenArmor.Count - 1) { phases.Add(new PhaseData(end, log.FightData.FightDuration)); } } else { start = Math.Min(moltenArmor[i], log.FightData.FightDuration); phases.Add(new PhaseData(end, start)); if (i == moltenArmor.Count - 1) { phases.Add(new PhaseData(start, log.FightData.FightDuration)); } } } string[] names = { "Hydra", "Qadim P1", "Apocalypse", "Qadim P2", "Wyvern", "Qadim P3" }; for (int i = 1; i < phases.Count; i++) { PhaseData phase = phases[i]; phase.Name = names[i - 1]; switch (i) { case 2: case 4: case 6: List <long> pyresFirstAware = log.AgentData.GetAgentsByID((ushort)PyreGuardian).Where(x => phase.InInterval(x.FirstAware - log.FightData.FightStart)).Select(x => x.FirstAware - log.FightData.FightStart).ToList(); if (pyresFirstAware.Count > 0 && pyresFirstAware.Max() > phase.Start) { phase.OverrideStart(pyresFirstAware.Max()); } phase.Targets.Add(qadim); break; default: List <ushort> ids = new List <ushort> { (ushort)WyvernMatriarch, (ushort)WyvernPatriarch, (ushort)AncientInvokedHydra, (ushort)ApocalypseBringer }; AddTargetsToPhase(phase, ids, log); phase.DrawArea = true; phase.DrawEnd = true; phase.DrawStart = true; break; } } phases.RemoveAll(x => x.Start >= x.End); return(phases); }