public static void WriteCastingItemIcon(StreamWriter sw, CastLog cl, SkillData skillList, PhaseData phase, bool last) { SkillItem skill = skillList.Get(cl.SkillId); GW2APISkill skillApi = skill?.ApiSkill; float offset = (cl.Time - phase.Start) / 1000f; if ((skillApi != null && skillApi.slot != "Weapon_1") || skillApi == null) { sw.Write("{" + "source: '" + skill.Icon + "'," + "xref: 'x'," + "yref: 'y'," + "x: " + Math.Max(offset, 0.0f) + "," + "y: 0," + "sizex: 1.1," + "sizey: 1.1," + "xanchor: 'left'," + "yanchor: 'bottom'" + "}"); } if (!last) { sw.Write(","); } }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { long fightDuration = log.FightData.FightDuration; List <PhaseData> phases = GetInitialPhase(log); Target mainTarget = Targets.Find(x => x.ID == (ushort)ParseEnum.TargetIDS.Matthias); if (mainTarget == null) { throw new InvalidOperationException("Main target of the fight not found"); } phases[0].Targets.Add(mainTarget); if (!requirePhases) { return(phases); } // Special buff cast check CombatItem heatWave = log.CombatData.GetBoonData(34526).FirstOrDefault(); if (heatWave != null) { phases.Add(new PhaseData(0, log.FightData.ToFightSpace(heatWave.Time) - 1)); CombatItem downPour = log.CombatData.GetDamageData(mainTarget.InstID, mainTarget.FirstAware, mainTarget.LastAware).Find(x => x.SkillID == 34554); if (downPour != null) { phases.Add(new PhaseData(log.FightData.ToFightSpace(heatWave.Time), log.FightData.ToFightSpace(downPour.Time) - 1)); List <CastLog> castLogs = mainTarget.GetCastLogs(log, 0, log.FightData.FightEnd); CastLog abo = castLogs.Find(x => x.SkillId == 34427); if (abo != null) { phases.Add(new PhaseData(log.FightData.ToFightSpace(downPour.Time), abo.Time - 1)); CombatItem invulRemove = log.CombatData.GetBoonDataByDst(mainTarget.InstID, log.FightData.ToLogSpace(abo.Time), log.FightData.ToLogSpace(abo.Time) + 10000).FirstOrDefault(x => x.SkillID == 757 && x.IsBuffRemove != ParseEnum.BuffRemove.None); if (invulRemove != null) { phases.Add(new PhaseData(log.FightData.ToFightSpace(invulRemove.Time), fightDuration)); } } else { phases.Add(new PhaseData(log.FightData.ToFightSpace(downPour.Time), fightDuration)); } } else { phases.Add(new PhaseData(log.FightData.ToFightSpace(heatWave.Time), fightDuration)); } } else { phases.Add(new PhaseData(0, fightDuration)); } string[] namesMat = new [] { "Ice Phase", "Fire Phase", "Storm Phase", "Abomination Phase" }; for (int i = 1; i < phases.Count; i++) { phases[i].Name = namesMat[i - 1]; phases[i].DrawStart = i > 1; phases[i].Targets.Add(mainTarget); } return(phases); }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { long start = 0; long end = 0; long fightDuration = log.FightData.FightDuration; List <PhaseData> phases = GetInitialPhase(log); Boss mainTarget = Targets.Find(x => x.ID == (ushort)ParseEnum.BossIDS.Matthias); if (mainTarget == null) { throw new InvalidOperationException("Main target of the fight not found"); } phases[0].Targets.Add(mainTarget); if (!requirePhases) { return(phases); } // Special buff cast check CombatItem heatWave = log.GetBoonData(34526).FirstOrDefault(); List <long> phaseStarts = new List <long>(); if (heatWave != null) { phaseStarts.Add(heatWave.Time - log.FightData.FightStart); CombatItem downPour = log.GetDamageData(mainTarget.InstID).Find(x => x.SkillID == 34554); if (downPour != null) { phaseStarts.Add(downPour.Time - log.FightData.FightStart); List <CastLog> castLogs = mainTarget.GetCastLogs(log, 0, log.FightData.FightEnd); CastLog abo = castLogs.Find(x => x.SkillId == 34427); if (abo != null) { phaseStarts.Add(abo.Time); } } } foreach (long t in phaseStarts) { end = t; phases.Add(new PhaseData(start, end)); // make sure stuff from the precedent phase mix witch each other start = t + 1; } if (fightDuration - start > 5000 && start >= phases.Last().End) { phases.Add(new PhaseData(start, fightDuration)); } string[] namesMat = new [] { "Ice Phase", "Fire Phase", "Storm Phase", "Abomination Phase" }; for (int i = 1; i < phases.Count; i++) { phases[i].Name = namesMat[i - 1]; phases[i].DrawStart = i > 1; phases[i].Targets.Add(mainTarget); } return(phases); }
// helpers public static object[] GetSkillData(CastLog cl, long phaseStart) { object[] rotEntry = new object[5]; double offset = 0.0; double start = (cl.Time - phaseStart) / 1000.0; rotEntry[0] = start; if (start < 0.0) { offset = -1000.0 * start; rotEntry[0] = 0; } rotEntry[1] = cl.SkillId; rotEntry[2] = cl.ActualDuration - offset;; rotEntry[3] = EncodeEndActivation(cl.EndActivation); rotEntry[4] = cl.StartActivation == ParseEnum.Activation.Quickness ? 1 : 0; return(rotEntry); }
private void ComputeFightPhases(Target mainTarget, List <PhaseData> phases, ParsedLog log, List <CastLog> castLogs, long fightDuration, long start) { CastLog shield = castLogs.Find(x => x.SkillId == 47396); if (shield != null) { long end = shield.Time; phases.Add(new PhaseData(start, end)); CastLog firstDamage = castLogs.FirstOrDefault(x => x.SkillId == 47304 && x.Time >= end); if (firstDamage != null) { phases.Add(new PhaseData(firstDamage.Time, fightDuration)); } } else { phases.Add(new PhaseData(start, fightDuration)); } }
private List <PhaseData> GetInBetweenSoulSplits(ParsedLog log, Target dhuum, long mainStart, long mainEnd) { List <CastLog> cls = dhuum.GetCastLogs(log, 0, log.FightData.FightDuration); List <CastLog> cataCycle = cls.Where(x => x.SkillId == 48398).ToList(); List <CastLog> gDeathmark = cls.Where(x => x.SkillId == 48210).ToList(); if (gDeathmark.Count < cataCycle.Count) { return(new List <PhaseData>()); } List <PhaseData> phases = new List <PhaseData>(); long start = mainStart; long end = 0; int i = 1; foreach (CastLog cl in cataCycle) { CastLog clDeathmark = gDeathmark[i - 1]; end = Math.Min(clDeathmark.Time, mainEnd); phases.Add(new PhaseData(start, end) { Name = "Pre-Soulsplit " + i++ }); start = cl.Time + cl.ActualDuration; } phases.Add(new PhaseData(start, mainEnd) { Name = "Pre-Ritual" }); foreach (PhaseData phase in phases) { phase.Targets.Add(dhuum); } phases.RemoveAll(x => x.DurationInMS <= 2200); return(phases); }
public override void ComputeAdditionalTargetData(Target target, ParsedLog log) { // TODO: correct position CombatReplay replay = target.CombatReplay; List <CastLog> cls = target.GetCastLogs(log, 0, log.FightData.FightDuration); switch (target.ID) { case (ushort)ParseEnum.TargetIDS.Dhuum: List <CastLog> deathmark = cls.Where(x => x.SkillId == 48176).ToList(); CastLog majorSplit = cls.Find(x => x.SkillId == 47396); foreach (CastLog c in deathmark) { int start = (int)c.Time; int zoneActive = start + 1550; int zoneDeadly = zoneActive + 6000; //point where the zone becomes impossible to walk through unscathed int zoneEnd = zoneActive + 120000; int radius = 450; if (majorSplit != null) { zoneEnd = Math.Min(zoneEnd, (int)majorSplit.Time); zoneDeadly = Math.Min(zoneDeadly, (int)majorSplit.Time); } int spellCenterDistance = 200; //hitbox radius Point3D facing = replay.Rotations.LastOrDefault(x => x.Time <= start + 3000); Point3D targetPosition = replay.Positions.LastOrDefault(x => x.Time <= start + 3000); if (facing != null && targetPosition != null) { Point3D position = new Point3D(targetPosition.X + (facing.X * spellCenterDistance), targetPosition.Y + (facing.Y * spellCenterDistance), targetPosition.Z, targetPosition.Time); replay.Actors.Add(new CircleActor(true, zoneActive, radius, new Tuple <int, int>(start, zoneActive), "rgba(200, 255, 100, 0.5)", new PositionConnector(position))); replay.Actors.Add(new CircleActor(false, 0, radius, new Tuple <int, int>(start, zoneActive), "rgba(200, 255, 100, 0.5)", new PositionConnector(position))); replay.Actors.Add(new CircleActor(true, 0, radius, new Tuple <int, int>(zoneActive, zoneDeadly), "rgba(200, 255, 100, 0.5)", new PositionConnector(position))); replay.Actors.Add(new CircleActor(true, 0, radius, new Tuple <int, int>(zoneDeadly, zoneEnd), "rgba(255, 100, 0, 0.5)", new PositionConnector(position))); } } List <CastLog> cataCycle = cls.Where(x => x.SkillId == 48398).ToList(); foreach (CastLog c in cataCycle) { int start = (int)c.Time; int end = start + c.ActualDuration; replay.Actors.Add(new CircleActor(true, end, 300, new Tuple <int, int>(start, end), "rgba(255, 150, 0, 0.7)", new AgentConnector(target))); replay.Actors.Add(new CircleActor(true, 0, 300, new Tuple <int, int>(start, end), "rgba(255, 150, 0, 0.5)", new AgentConnector(target))); } List <CastLog> slash = cls.Where(x => x.SkillId == 47561).ToList(); foreach (CastLog c in slash) { int start = (int)c.Time; int end = start + c.ActualDuration; Point3D facing = replay.Rotations.FirstOrDefault(x => x.Time >= start); if (facing == null) { continue; } replay.Actors.Add(new PieActor(false, 0, 850, facing, 60, new Tuple <int, int>(start, end), "rgba(255, 150, 0, 0.5)", new AgentConnector(target))); } if (majorSplit != null) { int start = (int)majorSplit.Time; int end = (int)log.FightData.FightDuration; replay.Actors.Add(new CircleActor(true, 0, 320, new Tuple <int, int>(start, end), "rgba(0, 180, 255, 0.2)", new AgentConnector(target))); } break; default: throw new InvalidOperationException("Unknown ID in ComputeAdditionalData"); } }
public override void ComputeAdditionalBossData(Boss boss, ParsedLog log) { CombatReplay replay = boss.CombatReplay; List <CastLog> cls = boss.GetCastLogs(log, 0, log.FightData.FightDuration); switch (boss.ID) { case (ushort)ParseEnum.BossIDS.KeepConstruct: List <CastLog> magicCharge = cls.Where(x => x.SkillId == 35048).ToList(); List <CastLog> magicExplode = cls.Where(x => x.SkillId == 34894).ToList(); for (var i = 0; i < magicCharge.Count; i++) { CastLog charge = magicCharge[i]; if (i < magicExplode.Count) { CastLog fire = magicExplode[i]; int start = (int)charge.Time; int end = (int)fire.Time + fire.ActualDuration; replay.Actors.Add(new CircleActor(false, 0, 300, new Tuple <int, int>(start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(boss))); replay.Actors.Add(new CircleActor(true, end, 300, new Tuple <int, int>(start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(boss))); } } List <CastLog> towerDrop = cls.Where(x => x.SkillId == 35086).ToList(); foreach (CastLog c in towerDrop) { int start = (int)c.Time; int end = start + c.ActualDuration; int skillCast = end - 1000; Point3D next = replay.Positions.FirstOrDefault(x => x.Time >= end); Point3D prev = replay.Positions.LastOrDefault(x => x.Time <= end); if (prev != null || next != null) { replay.Actors.Add(new CircleActor(false, 0, 400, new Tuple <int, int>(start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end))); replay.Actors.Add(new CircleActor(true, skillCast, 400, new Tuple <int, int>(start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end))); } } List <CastLog> blades1 = cls.Where(x => x.SkillId == 35064).ToList(); List <CastLog> blades2 = cls.Where(x => x.SkillId == 35137).ToList(); List <CastLog> blades3 = cls.Where(x => x.SkillId == 34971).ToList(); int bladeDelay = 150; int duration = 1000; foreach (CastLog c in blades1) { int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9)); int start = (int)c.Time + bladeDelay; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000); if (facing == null) { continue; } replay.Actors.Add(new CircleActor(true, 0, 200, new Tuple <int, int>(start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(boss))); replay.Actors.Add(new PieActor(true, 0, 1600, facing, 360 * 3 / 32, new Tuple <int, int>(start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts twice as long for (int i = 1; i < ticks; i++) { replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, new Tuple <int, int>(start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts longer } } foreach (CastLog c in blades2) { int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9)); int start = (int)c.Time + bladeDelay; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000); if (facing == null) { continue; } replay.Actors.Add(new CircleActor(true, 0, 200, new Tuple <int, int>(start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(boss))); replay.Actors.Add(new PieActor(true, 0, 1600, facing, 360 * 3 / 32, new Tuple <int, int>(start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts twice as long replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI), 360 * 3 / 32, new Tuple <int, int>(start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts twice as long for (int i = 1; i < ticks; i++) { replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, new Tuple <int, int>(start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts longer replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, new Tuple <int, int>(start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts longer } } foreach (CastLog c in blades3) { int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9)); int start = (int)c.Time + bladeDelay; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000); if (facing == null) { continue; } replay.Actors.Add(new CircleActor(true, 0, 200, new Tuple <int, int>(start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(boss))); replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI), 360 * 3 / 32, new Tuple <int, int>(start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts twice as long replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + 120), 360 * 3 / 32, new Tuple <int, int>(start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts twice as long replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI - 120), 360 * 3 / 32, new Tuple <int, int>(start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts twice as long for (int i = 1; i < ticks; i++) { replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, new Tuple <int, int>(start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts longer replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8 + 120), 360 * 3 / 32, new Tuple <int, int>(start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts longer replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8 - 120), 360 * 3 / 32, new Tuple <int, int>(start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(boss))); // First blade lasts longer } } break; default: throw new InvalidOperationException("Unknown ID in ComputeAdditionalData"); } }
public static void WriteCastingItem(StreamWriter sw, CastLog cl, SkillData skillList, PhaseData phase) { GW2APISkill skill = skillList.Get(cl.SkillId)?.ApiSkill; string skillName = skill == null?skillList.GetName(cl.SkillId) : skill.name; float dur; if (skillName == "Dodge") { dur = 0.5f; } else if (cl.SkillId == SkillItem.WeaponSwapId) { skillName = "Weapon Swap"; dur = 0.1f; } else { dur = cl.ActualDuration / 1000f; } skillName = skillName.Replace("\"", ""); float offset = (cl.Time - phase.Start) / 1000f; float xVal = dur; if (offset < 0.0f) { xVal += offset; } xVal = Math.Min(xVal, (phase.End - cl.Time) / 1000f); sw.Write("{"); { sw.Write(cl.SkillId == -5 ? "y: ['1']," : "y: ['1.5'],"); sw.Write( "x: ['" + xVal + "']," + "base:'" + Math.Max(offset, 0.0f) + "'," + "name: \"" + skillName + " " + dur + "s\"," + //get name should be handled by api "orientation:'h'," + "mode: 'markers'," + "type: 'bar',"); if (skill != null) { sw.Write(skill.slot == "Weapon_1" ? "width:'0.5'," : "width:'1',"); } else { sw.Write("width:'1',"); } sw.Write("hoverinfo: 'name'," + "hoverlabel:{namelength:'-1'},"); sw.Write("marker: {"); { if (cl.EndActivation == ParseEnum.Activation.CancelFire) { sw.Write("color: 'rgb(40,40,220)',"); } else if (cl.EndActivation == ParseEnum.Activation.CancelCancel) { sw.Write("color: 'rgb(220,40,40)',"); } else if (cl.EndActivation == ParseEnum.Activation.Reset) { sw.Write("color: 'rgb(40,220,40)',"); } else { sw.Write("color: 'rgb(220,220,0)',"); } sw.Write("width: '5',"); sw.Write("line:{"); { if (cl.StartActivation == ParseEnum.Activation.Normal) { sw.Write("color: 'rgb(20,20,20)',"); } else if (cl.StartActivation == ParseEnum.Activation.Quickness) { sw.Write("color: 'rgb(220,40,220)',"); } sw.Write("width: '1'"); } sw.Write("}"); } sw.Write("},"); sw.Write("showlegend: false"); } sw.Write(" },"); }
public static void WriteCastingItemIcon(StreamWriter sw, CastLog cl, SkillData skillList, PhaseData phase, bool last) { string skillIcon = ""; GW2APISkill skill = skillList.Get(cl.SkillId)?.ApiSkill; if (skill != null && cl.SkillId != -2) { float offset = (cl.Time - phase.Start) / 1000f; if (skill.slot != "Weapon_1") { skillIcon = skill.icon; sw.Write("{" + "source: '" + skillIcon + "'," + "xref: 'x'," + "yref: 'y'," + "x: " + Math.Max(offset, 0.0f) + "," + "y: 0," + "sizex: 1.1," + "sizey: 1.1," + "xanchor: 'left'," + "yanchor: 'bottom'" + "}"); } } else { string skillName = cl.SkillId == SkillItem.WeaponSwapId ? "Weapon Swap" : skillList.GetName(cl.SkillId); if (skillName == "Dodge") { skillIcon = GetLink("Dodge"); } else if (skillName == "Resurrect") { skillIcon = GetLink("Resurrect"); } else if (skillName == "Bandage") { skillIcon = GetLink("Bandage"); } else if (cl.SkillId == SkillItem.WeaponSwapId) { skillIcon = GetLink("Swap"); } sw.Write("{" + "source: '" + skillIcon + "'," + "xref: 'x'," + "yref: 'y'," + "x: " + (cl.Time - phase.Start) / 1000f + "," + "y: 0," + "sizex: 1.1," + "sizey: 1.1," + "xanchor: 'left'," + "yanchor: 'bottom'" + "}"); } if (!last) { sw.Write(","); } }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { long start = 0; long end = 0; long fightDuration = log.FightData.FightDuration; List <PhaseData> phases = GetInitialPhase(log); Target mainTarget = Targets.Find(x => x.ID == (ushort)ParseEnum.TargetIDS.KeepConstruct); if (mainTarget == null) { throw new InvalidOperationException("Main target of the fight not found"); } phases[0].Targets.Add(mainTarget); if (!requirePhases) { return(phases); } // Main phases 34894 List <CastLog> castLogs = mainTarget.GetCastLogs(log, 0, log.FightData.FightEnd); List <CastLog> magicCharge = castLogs.Where(x => x.SkillId == 35048).ToList(); List <CastLog> magicBlast = castLogs.Where(x => x.SkillId == 34894).ToList(); foreach (CastLog cl in magicCharge) { end = cl.Time; phases.Add(new PhaseData(start, end)); CastLog blast = magicBlast.FirstOrDefault(x => x.Time >= cl.Time); if (blast != null) { start = blast.Time + blast.ActualDuration; } else { start = end + cl.ActualDuration; } } if (fightDuration - start > 5000 && start >= phases.Last().End) { phases.Add(new PhaseData(start, fightDuration)); start = fightDuration; } string[] mainPhaseNames = { "100% - 66%", "66% - 33%", "33% - 0%" }; for (int i = 1; i < phases.Count; i++) { phases[i].Name = mainPhaseNames[i - 1]; phases[i].Targets.Add(mainTarget); } // add burn phases int offset = phases.Count; List <CombatItem> orbItems = log.GetBoonData(35096).Where(x => x.DstInstid == mainTarget.InstID).ToList(); // Get number of orbs and filter the list start = 0; int orbCount = 0; List <BoonsGraphModel.Segment> segments = new List <BoonsGraphModel.Segment>(); foreach (CombatItem c in orbItems) { if (c.IsBuffRemove == ParseEnum.BuffRemove.None) { if (start == 0) { start = log.FightData.ToFightSpace(c.Time); } orbCount++; } else if (start != 0) { segments.Add(new BoonsGraphModel.Segment(start, Math.Min(log.FightData.ToFightSpace(c.Time), fightDuration), orbCount)); orbCount = 0; start = 0; } } int burnCount = 1; foreach (var seg in segments) { var phase = new PhaseData(seg.Start, seg.End) { Name = "Burn " + burnCount++ + " (" + seg.Value + " orbs)", }; phase.Targets.Add(mainTarget); phases.Add(phase); } phases.Sort((x, y) => x.Start.CompareTo(y.Start)); // pre burn phases int preBurnCount = 1; List <PhaseData> preBurnPhase = new List <PhaseData>(); List <CombatItem> kcInvuls = GetFilteredList(log, 762, mainTarget, true); foreach (CombatItem invul in kcInvuls) { if (invul.IsBuffRemove == ParseEnum.BuffRemove.None) { end = log.FightData.ToFightSpace(invul.Time); PhaseData prevPhase = phases.LastOrDefault(x => x.Start <= end || x.End <= end); if (prevPhase != null) { start = (prevPhase.End >= end ? prevPhase.Start : prevPhase.End) + 1; if (end - start > 5000) { var phase = new PhaseData(start, end) { Name = "Pre-Burn " + preBurnCount++, }; phase.Targets.Add(mainTarget); preBurnPhase.Add(phase); } } } } phases.AddRange(preBurnPhase); phases.Sort((x, y) => x.Start.CompareTo(y.Start)); // add leftover phases PhaseData cur = null; int leftOverCount = 1; List <PhaseData> leftOverPhases = new List <PhaseData>(); for (int i = 0; i < phases.Count; i++) { PhaseData phase = phases[i]; if (phase.Name.Contains("%")) { cur = phase; } else if (phase.Name.Contains("orbs")) { if (cur != null) { if (cur.End >= phase.End + 5000 && (i == phases.Count - 1 || phases[i + 1].Name.Contains("Phase"))) { PhaseData leftOverPhase = new PhaseData(phase.End + 1, cur.End) { Name = "Leftover " + leftOverCount++, }; leftOverPhase.Targets.Add(mainTarget); leftOverPhases.Add(leftOverPhase); } } } } phases.AddRange(leftOverPhases); phases.Sort((x, y) => x.Start.CompareTo(y.Start)); return(phases); }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { long start = 0; long end = 0; long fightDuration = log.FightData.FightDuration; List <PhaseData> phases = GetInitialPhase(log); Target mainTarget = Targets.Find(x => x.ID == (ushort)ParseEnum.TargetIDS.KeepConstruct); if (mainTarget == null) { throw new InvalidOperationException("Main target of the fight not found"); } phases[0].Targets.Add(mainTarget); if (!requirePhases) { return(phases); } // Main phases 34894 List <CastLog> castLogs = mainTarget.GetCastLogs(log, 0, log.FightData.FightEnd); List <CastLog> magicCharge = castLogs.Where(x => x.SkillId == 35048).ToList(); List <CastLog> magicBlast = castLogs.Where(x => x.SkillId == 34894).ToList(); foreach (CastLog cl in magicCharge) { end = cl.Time; phases.Add(new PhaseData(start, end)); CastLog blast = magicBlast.FirstOrDefault(x => x.Time >= cl.Time); if (blast != null) { start = blast.Time + blast.ActualDuration; } else { start = end + cl.ActualDuration; } } if (fightDuration - start > 5000 && start >= phases.Last().End) { phases.Add(new PhaseData(start, fightDuration)); start = fightDuration; } for (int i = 1; i < phases.Count; i++) { phases[i].Name = "Phase " + i; phases[i].Targets.Add(mainTarget); } // add burn phases int offset = phases.Count; List <CombatItem> orbItems = log.GetBoonData(35096).Where(x => x.DstInstid == mainTarget.InstID).ToList(); // Get number of orbs and filter the list start = 0; int orbCount = 0; List <BoonsGraphModel.Segment> segments = new List <BoonsGraphModel.Segment>(); foreach (CombatItem c in orbItems) { if (c.IsBuffRemove == ParseEnum.BuffRemove.None) { if (start == 0) { start = log.FightData.ToFightSpace(c.Time); } orbCount++; } else if (start != 0) { segments.Add(new BoonsGraphModel.Segment(start, Math.Min(log.FightData.ToFightSpace(c.Time), fightDuration), orbCount)); orbCount = 0; start = 0; } } int burnCount = 1; foreach (var seg in segments) { var phase = new PhaseData(seg.Start, seg.End) { Name = "Burn " + burnCount++ + " (" + seg.Value + " orbs)", }; phase.Targets.Add(mainTarget); phases.Add(phase); } phases.Sort((x, y) => (x.Start < y.Start) ? -1 : 1); return(phases); }
public override List <PhaseData> GetPhases(ParsedLog log, bool requirePhases) { long start = 0; long end = 0; long fightDuration = log.FightData.FightDuration; List <PhaseData> phases = GetInitialPhase(log); Boss mainTarget = Targets.Find(x => x.ID == (ushort)ParseEnum.BossIDS.Dhuum); if (mainTarget == null) { throw new InvalidOperationException("Main target of the fight not found"); } phases[0].Targets.Add(mainTarget); if (!requirePhases) { return(phases); } // Sometimes the preevent is not in the evtc List <CastLog> castLogs = mainTarget.GetCastLogs(log, 0, log.FightData.FightEnd); List <CastLog> dhuumCast = mainTarget.GetCastLogs(log, 0, 20000); if (dhuumCast.Count > 0) { CastLog shield = castLogs.Find(x => x.SkillId == 47396); if (shield != null) { end = shield.Time; phases.Add(new PhaseData(start, end)); start = shield.Time + shield.ActualDuration; if (start < fightDuration - 5000) { phases.Add(new PhaseData(start, fightDuration)); } } if (fightDuration - start > 5000 && start >= phases.Last().End) { phases.Add(new PhaseData(start, fightDuration)); } string[] namesDh = new [] { "Main Fight", "Ritual" }; for (int i = 1; i < phases.Count; i++) { phases[i].Name = namesDh[i - 1]; phases[i].DrawArea = true; phases[i].DrawStart = i > 1; phases[i].DrawEnd = i < phases.Count - 1; phases[i].Targets.Add(mainTarget); } } else { CombatItem invulDhuum = log.GetBoonData(762).FirstOrDefault(x => x.IsBuffRemove != ParseEnum.BuffRemove.None && x.SrcInstid == mainTarget.InstID && x.Time > 115000 + log.FightData.FightStart); if (invulDhuum != null) { end = invulDhuum.Time - log.FightData.FightStart; phases.Add(new PhaseData(start, end)); start = end + 1; CastLog shield = castLogs.Find(x => x.SkillId == 47396); if (shield != null) { end = shield.Time; phases.Add(new PhaseData(start, end)); start = shield.Time + shield.ActualDuration; if (start < fightDuration - 5000) { phases.Add(new PhaseData(start, fightDuration)); } } } if (fightDuration - start > 5000 && start >= phases.Last().End) { phases.Add(new PhaseData(start, fightDuration)); } string[] namesDh = new [] { "Roleplay", "Main Fight", "Ritual" }; for (int i = 1; i < phases.Count; i++) { phases[i].Name = namesDh[i - 1]; phases[i].DrawArea = i > 1; phases[i].DrawStart = i > 1; phases[i].DrawEnd = i == 2; phases[i].Targets.Add(mainTarget); } } return(phases); }
public override void ComputeTargetCombatReplayActors(Target target, ParsedLog log, CombatReplay replay) { List <CastLog> cls = target.GetCastLogs(log, 0, log.FightData.FightDuration); switch (target.ID) { case (ushort)ParseEnum.TargetIDS.KeepConstruct: List <CastLog> magicCharge = cls.Where(x => x.SkillId == 35048).ToList(); List <CastLog> magicExplode = cls.Where(x => x.SkillId == 34894).ToList(); for (var i = 0; i < magicCharge.Count; i++) { CastLog charge = magicCharge[i]; if (i < magicExplode.Count) { CastLog fire = magicExplode[i]; int start = (int)charge.Time; int end = (int)fire.Time + fire.ActualDuration; replay.Actors.Add(new CircleActor(false, 0, 300, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target))); replay.Actors.Add(new CircleActor(true, end, 300, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target))); } } List <CastLog> towerDrop = cls.Where(x => x.SkillId == 35086).ToList(); foreach (CastLog c in towerDrop) { int start = (int)c.Time; int end = start + c.ActualDuration; int skillCast = end - 1000; Point3D next = replay.Positions.FirstOrDefault(x => x.Time >= end); Point3D prev = replay.Positions.LastOrDefault(x => x.Time <= end); if (prev != null || next != null) { replay.Actors.Add(new CircleActor(false, 0, 400, (start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end))); replay.Actors.Add(new CircleActor(true, skillCast, 400, (start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end))); } } List <CastLog> blades1 = cls.Where(x => x.SkillId == 35064).ToList(); List <CastLog> blades2 = cls.Where(x => x.SkillId == 35137).ToList(); List <CastLog> blades3 = cls.Where(x => x.SkillId == 34971).ToList(); int bladeDelay = 150; int duration = 1000; foreach (CastLog c in blades1) { int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9)); int start = (int)c.Time + bladeDelay; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000); if (facing == null) { continue; } replay.Actors.Add(new CircleActor(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target))); replay.Actors.Add(new PieActor(true, 0, 1600, facing, 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts twice as long for (int i = 1; i < ticks; i++) { replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts longer } } foreach (CastLog c in blades2) { int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9)); int start = (int)c.Time + bladeDelay; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000); if (facing == null) { continue; } replay.Actors.Add(new CircleActor(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target))); replay.Actors.Add(new PieActor(true, 0, 1600, facing, 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts twice as long replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts twice as long for (int i = 1; i < ticks; i++) { replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts longer replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts longer } } foreach (CastLog c in blades3) { int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9)); int start = (int)c.Time + bladeDelay; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000); if (facing == null) { continue; } replay.Actors.Add(new CircleActor(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target))); replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts twice as long replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + 120), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts twice as long replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI - 120), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts twice as long for (int i = 1; i < ticks; i++) { replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts longer replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8 + 120), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts longer replay.Actors.Add(new PieActor(true, 0, 1600, (int)Math.Round(Math.Atan2(-facing.Y, -facing.X) * 180 / Math.PI + i * 360 / 8 - 120), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,200,0,0.5)", new AgentConnector(target))); // First blade lasts longer } } // phantasms locations HashSet <ushort> phantasmsID = new HashSet <ushort> { (ushort)Jessica, (ushort)Olson, (ushort)Engul, (ushort)Faerla, (ushort)Caulle, (ushort)Henley, (ushort)Galletta, (ushort)Ianim, }; foreach (Mob m in TrashMobs) { if (phantasmsID.Contains(m.ID)) { int start = (int)log.FightData.ToFightSpace(m.FirstAware); Point3D pos = m.GetCombatReplayPositions(log).FirstOrDefault(); if (pos != null) { replay.Actors.Add(new CircleActor(true, 0, 300, (start - 5000, start), "rgba(220, 50, 0, 0.5)", new PositionConnector(pos))); replay.Actors.Add(new CircleActor(true, start, 300, (start - 5000, start), "rgba(220, 50, 0, 0.5)", new PositionConnector(pos))); } } } break; default: throw new InvalidOperationException("Unknown ID in ComputeAdditionalData"); } }