private void CalculateDefenses() { CombatData combatData = _log.CombatData; foreach (Player player in _log.PlayerList) { FinalDefenses[] phaseDefense = new FinalDefenses[_statistics.Phases.Count]; for (int phaseIndex = 0; phaseIndex < _statistics.Phases.Count; phaseIndex++) { FinalDefenses final = new FinalDefenses(); PhaseData phase = _statistics.Phases[phaseIndex]; long start = _log.FightData.ToLogSpace(phase.Start); long end = _log.FightData.ToLogSpace(phase.End); List <DamageLog> damageLogs = player.GetDamageTakenLogs(null, _log, phase.Start, phase.End); //List<DamageLog> healingLogs = player.getHealingReceivedLogs(log, phase.getStart(), phase.getEnd()); final.DamageTaken = damageLogs.Sum(x => (long)x.Damage); //final.allHealReceived = healingLogs.Sum(x => x.getDamage()); final.BlockedCount = damageLogs.Count(x => x.Result == ParseEnum.Result.Block); final.InvulnedCount = 0; final.DamageInvulned = 0; final.EvadedCount = damageLogs.Count(x => x.Result == ParseEnum.Result.Evade); final.DodgeCount = player.GetCastLogs(_log, 0, _log.FightData.FightDuration).Count(x => x.SkillId == SkillItem.DodgeId); final.DamageBarrier = damageLogs.Sum(x => x.ShieldDamage); final.InterruptedCount = damageLogs.Count(x => x.Result == ParseEnum.Result.Interrupt); foreach (DamageLog log in damageLogs.Where(x => x.Result == ParseEnum.Result.Absorb)) { final.InvulnedCount++; final.DamageInvulned += log.Damage; } List <CombatItem> deads = combatData.GetStates(player.InstID, ParseEnum.StateChange.ChangeDead, start, end); List <CombatItem> downs = combatData.GetStates(player.InstID, ParseEnum.StateChange.ChangeDown, start, end); List <CombatItem> dcs = combatData.GetStates(player.InstID, ParseEnum.StateChange.Despawn, start, end); final.DownCount = downs.Count; final.DeadCount = deads.Count; final.DCCount = dcs.Count; phaseDefense[phaseIndex] = final; } List <Tuple <long, long> > dead = new List <Tuple <long, long> >(); List <Tuple <long, long> > down = new List <Tuple <long, long> >(); List <Tuple <long, long> > dc = new List <Tuple <long, long> >(); combatData.GetAgentStatus(player.FirstAware, player.LastAware, player.InstID, dead, down, dc); for (int phaseIndex = 0; phaseIndex < _statistics.Phases.Count; phaseIndex++) { FinalDefenses defenses = phaseDefense[phaseIndex]; PhaseData phase = _statistics.Phases[phaseIndex]; long start = phase.Start; long end = phase.End; defenses.DownDuration = (int)down.Where(x => x.Item2 >= start && x.Item1 <= end).Sum(x => Math.Min(end, x.Item2) - Math.Max(x.Item1, start)); defenses.DeadDuration = (int)dead.Where(x => x.Item2 >= start && x.Item1 <= end).Sum(x => Math.Min(end, x.Item2) - Math.Max(x.Item1, start)); defenses.DCDuration = (int)dc.Where(x => x.Item2 >= start && x.Item1 <= end).Sum(x => Math.Min(end, x.Item2) - Math.Max(x.Item1, start)); } _statistics.Defenses[player] = phaseDefense; } }
private FinalStatsAll GetFinalStats(Player p, int phaseIndex) { PhaseData phase = _statistics.Phases[phaseIndex]; long start = phase.Start + _log.FightData.FightStart; long end = phase.End + _log.FightData.FightStart; FinalStatsAll final = new FinalStatsAll(); HashSet <long> nonCritable = new HashSet <long> { 9292, 52370 }; foreach (DamageLog dl in p.GetJustPlayerDamageLogs(null, _log, phase.Start, phase.End)) { if (dl.IsCondi == 0) { if (dl.Result == ParseEnum.Result.Crit) { final.CriticalRate++; final.CriticalDmg += dl.Damage; } if (dl.IsNinety > 0) { final.ScholarRate++; final.ScholarDmg += (int)(dl.Damage / 11.0); //regular+10% damage } if (dl.IsMoving > 0) { final.MovingRate++; final.MovingDamage += (int)(dl.Damage / 21.0); } final.FlankingRate += dl.IsFlanking; if (dl.Result == ParseEnum.Result.Glance) { final.GlanceRate++; } if (dl.Result == ParseEnum.Result.Blind) { final.Missed++; } if (dl.Result == ParseEnum.Result.Interrupt) { final.Interrupts++; } if (dl.Result == ParseEnum.Result.Absorb) { final.Invulned++; } final.PowerLoopCount++; if (!nonCritable.Contains(dl.SkillId)) { final.CritablePowerLoopCount++; } } } if (p.Account == ":Conjured Sword") { return(final); } foreach (CastLog cl in p.GetCastLogs(_log, phase.Start, phase.End)) { if (cl.EndActivation == ParseEnum.Activation.CancelCancel) { final.Wasted++; final.TimeWasted += cl.ActualDuration; } if (cl.EndActivation == ParseEnum.Activation.CancelFire) { final.Saved++; if (cl.ActualDuration < cl.ExpectedDuration) { final.TimeSaved += cl.ExpectedDuration - cl.ActualDuration; } } } final.TimeSaved = final.TimeSaved / 1000f; final.TimeWasted = final.TimeWasted / 1000f; double avgBoons = 0; foreach (long duration in p.GetBoonPresence(_log, phaseIndex).Values) { avgBoons += duration; } final.AvgBoons = avgBoons / phase.GetDuration(); double avgCondis = 0; foreach (long duration in p.GetCondiPresence(_log, phaseIndex).Values) { avgCondis += duration; } final.AvgConditions = avgCondis / phase.GetDuration(); // Counts CombatData combatData = _log.CombatData; final.SwapCount = combatData.GetStates(p.InstID, ParseEnum.StateChange.WeaponSwap, start, end).Count; final.DownCount = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDown, start, end).Count; final.DodgeCount = combatData.GetSkillCount(p.InstID, SkillItem.DodgeId, start, end) + combatData.GetBuffCount(p.InstID, 40408, start, end);//dodge = 65001 mirage cloak =40408 if (_settings.ParseCombatReplay && _log.FightData.Logic.CanCombatReplay) { if (_statistics.StackCenterPositions == null) { _statistics.StackCenterPositions = new List <Point3D>(); List <List <Point3D> > GroupsPosList = new List <List <Point3D> >(); foreach (Player player in _log.PlayerList) { if (player.Account == ":Conjured Sword") { continue; } GroupsPosList.Add(player.CombatReplay.GetActivePositions()); } for (int time = 0; time < GroupsPosList[0].Count; time++) { float x = 0; float y = 0; float z = 0; int activePlayers = GroupsPosList.Count; foreach (List <Point3D> points in GroupsPosList) { Point3D point = points[time]; if (point != null) { x += point.X; y += point.Y; z += point.Z; } else { activePlayers--; } } x = x / activePlayers; y = y / activePlayers; z = z / activePlayers; _statistics.StackCenterPositions.Add(new Point3D(x, y, z, _settings.PollingRate * time)); } } List <Point3D> positions = p.CombatReplay.Positions.Where(x => x.Time >= phase.Start && x.Time <= phase.End).ToList(); int offset = p.CombatReplay.Positions.Count(x => x.Time < phase.Start); if (positions.Count > 1) { List <float> distances = new List <float>(); for (int time = 0; time < positions.Count; time++) { float deltaX = positions[time].X - _statistics.StackCenterPositions[time + offset].X; float deltaY = positions[time].Y - _statistics.StackCenterPositions[time + offset].Y; //float deltaZ = positions[time].Z - StackCenterPositions[time].Z; distances.Add((float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY)); } final.StackDist = distances.Sum() / distances.Count; } else { final.StackDist = -1; } } List <CombatItem> dead = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDead, start, end); List <CombatItem> up = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeUp, start, end); final.Died = 0.0; if (dead.Count > 0) { final.Died = up.Count > 0 && up.Last().Time > dead.Last().Time ? -dead.Count : dead.Last().Time - start; } List <CombatItem> disconnect = combatData.GetStates(p.InstID, ParseEnum.StateChange.Despawn, start, end); final.Dcd = 0.0; if (disconnect.Count > 0) { final.Dcd = disconnect.Last().Time - start; } return(final); }
public void ComputeMechanics(ParsedLog log) { MechanicData mechData = log.MechanicData; FightData fightData = log.FightData; CombatData combatData = log.CombatData; long start = fightData.FightStart; long end = fightData.FightEnd; Mechanic.CheckSpecialCondition condition; HashSet <ushort> playersIds = new HashSet <ushort>(log.PlayerList.Select(x => x.InstID)); Dictionary <ushort, AbstractMasterPlayer> regroupedMobs = new Dictionary <ushort, AbstractMasterPlayer>(); foreach (Mechanic mech in MechanicList) { switch (mech.MechanicType) { case Mechanic.MechType.PlayerStatus: foreach (Player p in log.PlayerList) { List <CombatItem> cList = new List <CombatItem>(); switch (mech.SkillId) { case SkillItem.DeathId: cList = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDead, start, end); break; case SkillItem.DownId: cList = combatData.GetStates(p.InstID, ParseEnum.StateChange.ChangeDown, start, end); break; case SkillItem.ResurrectId: cList = log.GetCastData(p.InstID).Where(x => x.SkillID == SkillItem.ResurrectId && x.IsActivation.IsCasting()).ToList(); break; } foreach (CombatItem mechItem in cList) { mechData[mech].Add(new MechanicLog(mechItem.Time - start, mech, p)); } } break; case Mechanic.MechType.SkillOnPlayer: foreach (Player p in log.PlayerList) { List <DamageLog> dls = p.GetDamageTakenLogs(log, 0, fightData.FightDuration); condition = mech.SpecialCondition; foreach (DamageLog dLog in dls) { if (condition != null && !condition(new SpecialConditionItem(dLog))) { continue; } if (dLog.SkillId == mech.SkillId && dLog.Result.IsHit()) { mechData[mech].Add(new MechanicLog(dLog.Time, mech, p)); } } } break; case Mechanic.MechType.PlayerBoon: case Mechanic.MechType.PlayerOnPlayer: case Mechanic.MechType.PlayerBoonRemove: foreach (Player p in log.PlayerList) { condition = mech.SpecialCondition; foreach (CombatItem c in log.GetBoonData(mech.SkillId)) { if (condition != null && !condition(new SpecialConditionItem(c))) { continue; } if (mech.MechanicType == Mechanic.MechType.PlayerBoonRemove) { if (c.IsBuffRemove == ParseEnum.BuffRemove.Manual && p.InstID == c.SrcInstid) { mechData[mech].Add(new MechanicLog(c.Time - start, mech, p)); } } else { if (c.IsBuffRemove == ParseEnum.BuffRemove.None && p.InstID == c.DstInstid) { mechData[mech].Add(new MechanicLog(c.Time - start, mech, p)); if (mech.MechanicType == Mechanic.MechType.PlayerOnPlayer) { mechData[mech].Add(new MechanicLog(c.Time - start, mech, log.PlayerList.FirstOrDefault(x => x.InstID == c.SrcInstid))); } } } } } break; case Mechanic.MechType.HitOnEnemy: foreach (Player p in log.PlayerList) { condition = mech.SpecialCondition; IEnumerable <AgentItem> agents = log.AgentData.GetAgentsByID((ushort)mech.SkillId); foreach (AgentItem a in agents) { foreach (DamageLog dl in p.GetDamageLogs(null, log, 0, log.FightData.FightDuration)) { if (dl.DstInstId != a.InstID || dl.IsCondi > 0 || dl.Time < a.FirstAware - start || dl.Time > a.LastAware - start || (condition != null && !condition(new SpecialConditionItem(dl)))) { continue; } mechData[mech].Add(new MechanicLog(dl.Time, mech, p)); } } } break; case Mechanic.MechType.PlayerSkill: foreach (Player p in log.PlayerList) { condition = mech.SpecialCondition; foreach (CombatItem c in log.GetCastDataById(mech.SkillId)) { if (condition != null && !condition(new SpecialConditionItem(c))) { continue; } if (c.IsActivation.IsCasting() && c.SrcInstid == p.InstID) { mechData[mech].Add(new MechanicLog(c.Time - fightData.FightStart, mech, p)); } } } break; case Mechanic.MechType.EnemyBoon: case Mechanic.MechType.EnemyBoonStrip: condition = mech.SpecialCondition; foreach (CombatItem c in log.GetBoonData(mech.SkillId)) { if (condition != null && !condition(new SpecialConditionItem(c))) { continue; } AbstractMasterPlayer amp = null; if (mech.MechanicType == Mechanic.MechType.EnemyBoon && c.IsBuffRemove == ParseEnum.BuffRemove.None) { Boss target = Targets.Find(x => x.InstID == c.DstInstid && x.FirstAware <= c.Time && x.LastAware >= c.Time); if (target != null) { amp = target; } else { AgentItem a = log.AgentData.GetAgent(c.DstAgent); if (playersIds.Contains(a.InstID)) { continue; } else if (a.MasterAgent != 0) { AgentItem m = log.AgentData.GetAgent(a.MasterAgent); if (playersIds.Contains(m.InstID)) { continue; } } if (!regroupedMobs.TryGetValue(a.ID, out amp)) { amp = new DummyPlayer(a); regroupedMobs.Add(a.ID, amp); } } } else if (mech.MechanicType == Mechanic.MechType.EnemyBoonStrip && c.IsBuffRemove == ParseEnum.BuffRemove.Manual) { Boss target = Targets.Find(x => x.InstID == c.SrcInstid && x.FirstAware <= c.Time && x.LastAware >= c.Time); if (target != null) { amp = target; } else { AgentItem a = log.AgentData.GetAgent(c.SrcAgent); if (playersIds.Contains(a.InstID)) { continue; } else if (a.MasterAgent != 0) { AgentItem m = log.AgentData.GetAgent(a.MasterAgent); if (playersIds.Contains(m.InstID)) { continue; } } if (!regroupedMobs.TryGetValue(a.ID, out amp)) { amp = new DummyPlayer(a); regroupedMobs.Add(a.ID, amp); } } } if (amp != null) { mechData[mech].Add(new MechanicLog(c.Time - fightData.FightStart, mech, amp)); } } break; case Mechanic.MechType.EnemyCastEnd: case Mechanic.MechType.EnemyCastStart: condition = mech.SpecialCondition; foreach (CombatItem c in log.GetCastDataById(mech.SkillId)) { if (condition != null && !condition(new SpecialConditionItem(c))) { continue; } AbstractMasterPlayer amp = null; if ((mech.MechanicType == Mechanic.MechType.EnemyCastStart && c.IsActivation.IsCasting()) || (mech.MechanicType == Mechanic.MechType.EnemyCastEnd && !c.IsActivation.IsCasting())) { Boss target = Targets.Find(x => x.InstID == c.SrcInstid && x.FirstAware <= c.Time && x.LastAware >= c.Time); if (target != null) { amp = target; } else { AgentItem a = log.AgentData.GetAgent(c.SrcAgent); if (playersIds.Contains(a.InstID)) { continue; } else if (a.MasterAgent != 0) { AgentItem m = log.AgentData.GetAgent(a.MasterAgent); if (playersIds.Contains(m.InstID)) { continue; } } if (!regroupedMobs.TryGetValue(a.ID, out amp)) { amp = new DummyPlayer(a); regroupedMobs.Add(a.ID, amp); } } } if (amp != null) { mechData[mech].Add(new MechanicLog(c.Time - fightData.FightStart, mech, amp)); } } break; case Mechanic.MechType.Spawn: foreach (AgentItem a in log.AgentData.GetAgentByType(AgentItem.AgentType.NPC).Where(x => x.ID == mech.SkillId)) { if (!regroupedMobs.TryGetValue(a.ID, out AbstractMasterPlayer amp)) { amp = new DummyPlayer(a); regroupedMobs.Add(a.ID, amp); } mechData[mech].Add(new MechanicLog(a.FirstAware - fightData.FightStart, mech, amp)); } break; } } mechData.ComputePresentMechanics(log); }