internal override void ComputeNPCCombatReplayActors(NPC target, ParsedEvtcLog log, CombatReplay replay) { IReadOnlyList <AbstractCastEvent> cls = target.GetCastEvents(log, 0, log.FightData.FightEnd); switch (target.ID) { case (int)ArcDPSEnums.TargetID.Cairn: var swordSweep = cls.Where(x => x.SkillId == 37631).ToList(); foreach (AbstractCastEvent c in swordSweep) { int start = (int)c.Time; int preCastTime = 1400; int initialHitDuration = 850; int sweepDuration = 1100; int width = 1400; int height = 80; Point3D facing = replay.Rotations.FirstOrDefault(x => x.Time >= start); if (facing != null) { float initialDirection = ParserHelper.RadianToDegreeF(Math.Atan2(facing.Y, facing.X)); replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, initialDirection, width / 2, (start, start + preCastTime), "rgba(200, 0, 255, 0.1)", new AgentConnector(target))); replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, initialDirection, width / 2, (start + preCastTime, start + preCastTime + initialHitDuration), "rgba(150, 0, 180, 0.5)", new AgentConnector(target))); replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, initialDirection, width / 2, 360, (start + preCastTime + initialHitDuration, start + preCastTime + initialHitDuration + sweepDuration), "rgba(150, 0, 180, 0.5)", new AgentConnector(target))); } } var wave = cls.Where(x => x.SkillId == 37910).ToList(); foreach (AbstractCastEvent c in wave) { int start = (int)c.Time; int preCastTime = 1200; int duration = 600; int firstRadius = 400; int secondRadius = 700; int thirdRadius = 1000; int fourthRadius = 1300; replay.Decorations.Add(new DoughnutDecoration(true, 0, firstRadius, secondRadius, (start + preCastTime, start + preCastTime + duration), "rgba(100,0,155,0.3)", new AgentConnector(target))); replay.Decorations.Add(new DoughnutDecoration(true, 0, secondRadius, thirdRadius, (start + preCastTime + 2 * duration, start + preCastTime + 3 * duration), "rgba(100,0,155,0.3)", new AgentConnector(target))); replay.Decorations.Add(new DoughnutDecoration(true, 0, thirdRadius, fourthRadius, (start + preCastTime + 5 * duration, start + preCastTime + 6 * duration), "rgba(100,0,155,0.3)", new AgentConnector(target))); } break; default: break; } }
internal override void ComputeNPCCombatReplayActors(NPC target, ParsedEvtcLog log, CombatReplay replay) { IReadOnlyList <AbstractCastEvent> cls = target.GetCastEvents(log, 0, log.FightData.FightEnd); int start = (int)replay.TimeOffsets.start; int end = (int)replay.TimeOffsets.end; switch (target.ID) { case (int)ArcDPSEnums.TargetID.SoullessHorror: // arena reduction var center = new Point3D(-10581, 825, -817, 0); string destroyedRingColor = "rgba(255, 120, 30, 0.3)"; if (center != null) { List <(double, int, int)> destroyedRings; if (log.FightData.IsCM) { destroyedRings = new List <(double, int, int)>() { (100, 1330, 1550), (90, 1120, 1330), (66, 910, 1120), (33, 720, 910) }; } else { destroyedRings = new List <(double, int, int)>() { (90, 1330, 1550), (66, 1120, 1330), (33, 910, 1120), }; } foreach ((double hpVal, int innerRadius, int outerRadius) in destroyedRings) { Segment hpUpdate = target.GetHealthUpdates(log).FirstOrDefault(x => x.Value <= hpVal); if (hpUpdate != null) { replay.Decorations.Add(new DoughnutDecoration(true, (int)hpUpdate.Start + 3000, innerRadius, outerRadius, ((int)hpUpdate.Start, (int)log.FightData.FightEnd), destroyedRingColor, new PositionConnector(center))); replay.Decorations.Add(new DoughnutDecoration(true, 0, innerRadius, outerRadius, ((int)hpUpdate.Start, (int)log.FightData.FightEnd), destroyedRingColor, new PositionConnector(center))); } else { break; } } } // var howling = cls.Where(x => x.SkillId == 48662).ToList(); foreach (AbstractCastEvent c in howling) { start = (int)c.Time; end = (int)c.EndTime; replay.Decorations.Add(new CircleDecoration(true, start + c.ExpectedDuration, 180, (start, end), "rgba(0, 180, 255, 0.3)", new AgentConnector(target))); replay.Decorations.Add(new CircleDecoration(true, 0, 180, (start, end), "rgba(0, 180, 255, 0.3)", new AgentConnector(target))); } var vortex = cls.Where(x => x.SkillId == 47327).ToList(); foreach (AbstractCastEvent c in vortex) { start = (int)c.Time; end = start + 4000; Point3D next = replay.PolledPositions.FirstOrDefault(x => x.Time >= start); Point3D prev = replay.PolledPositions.LastOrDefault(x => x.Time <= start); if (next != null || prev != null) { replay.Decorations.Add(new CircleDecoration(false, 0, 380, (start, end), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, start))); replay.Decorations.Add(new CircleDecoration(true, end, 380, (start, end), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, start))); replay.Decorations.Add(new DoughnutDecoration(true, 0, 380, 760, (end, end + 1000), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, start))); } } var deathBloom = cls.Where(x => x.SkillId == 48500).ToList(); foreach (AbstractCastEvent c in deathBloom) { start = (int)c.Time; end = (int)c.EndTime; Point3D facing = replay.Rotations.FirstOrDefault(x => x.Time >= start); if (facing == null) { continue; } for (int i = 0; i < 8; i++) { replay.Decorations.Add(new PieDecoration(true, 0, 3500, Point3D.GetRotationFromFacing(facing) + (i * 360 / 8), 360 / 12, (start, end), "rgba(255,200,0,0.5)", new AgentConnector(target))); } } var quad1 = cls.Where(x => x.SkillId == 48363).ToList(); var quad2 = cls.Where(x => x.SkillId == 47915).ToList(); foreach (AbstractCastEvent c in quad1) { start = (int)c.Time; end = (int)c.EndTime; Point3D facing = replay.Rotations.FirstOrDefault(x => x.Time >= start); if (facing == null) { continue; } for (int i = 0; i < 4; i++) { replay.Decorations.Add(new PieDecoration(true, 0, 3500, Point3D.GetRotationFromFacing(facing) + (i * 360 / 4), 360 / 12, (start, end), "rgba(255,200,0,0.5)", new AgentConnector(target))); } } foreach (AbstractCastEvent c in quad2) { start = (int)c.Time; end = (int)c.EndTime; Point3D facing = replay.Rotations.FirstOrDefault(x => x.Time >= start); if (facing == null) { continue; } for (int i = 0; i < 4; i++) { replay.Decorations.Add(new PieDecoration(true, 0, 3500, Point3D.GetRotationFromFacing(facing) + 45 + (i * 360 / 4), 360 / 12, (start, end), "rgba(255,200,0,0.5)", new AgentConnector(target))); } } break; case (int)ArcDPSEnums.TrashID.Scythe: replay.Decorations.Add(new CircleDecoration(true, 0, 80, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target))); break; case (int)ArcDPSEnums.TrashID.TormentedDead: if (replay.Positions.Count == 0) { break; } replay.Decorations.Add(new CircleDecoration(true, 0, 400, (end, end + 60000), "rgba(255, 0, 0, 0.5)", new PositionConnector(replay.Positions.Last()))); break; case (int)ArcDPSEnums.TrashID.SurgingSoul: List <Point3D> positions = replay.Positions; if (positions.Count < 2) { break; } if (positions[0].X <-12000 || positions[0].X> -9250) { replay.Decorations.Add(new RectangleDecoration(true, 0, 240, 660, (start, end), "rgba(255,100,0,0.5)", new AgentConnector(target))); break; } else if (positions[0].Y < -525 || positions[0].Y > 2275) { replay.Decorations.Add(new RectangleDecoration(true, 0, 645, 238, (start, end), "rgba(255,100,0,0.5)", new AgentConnector(target))); break; } break; case (int)ArcDPSEnums.TrashID.FleshWurm: break; default: break; } }
internal override void ComputeNPCCombatReplayActors(NPC target, ParsedEvtcLog log, CombatReplay replay) { IReadOnlyList <AbstractCastEvent> cls = target.GetCastEvents(log, 0, log.FightData.FightEnd); int start = (int)replay.TimeOffsets.start; int end = (int)replay.TimeOffsets.end; switch (target.ID) { case (int)ArcDPSEnums.TargetID.PeerlessQadim: var cataCycle = cls.Where(x => x.SkillId == 56329).ToList(); var forceOfHavoc = cls.Where(x => x.SkillId == 56017).ToList(); var forceOfRetal = cls.Where(x => x.SkillId == ForceOfRetaliationCast).ToList(); var etherStrikes = cls.Where(x => x.SkillId == 56012 || x.SkillId == 56653).ToList(); var causticChaos = cls.Where(x => x.SkillId == 56332).ToList(); var expoReperc = cls.Where(x => x.SkillId == 56223).ToList(); foreach (AbstractCastEvent c in cataCycle) { int magmaRadius = 850; start = (int)c.Time; end = (int)c.EndTime; Point3D pylonPosition = replay.PolledPositions.LastOrDefault(x => x.Time <= end); replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (start, end), "rgba(255, 50, 50, 0.15)", new PositionConnector(pylonPosition))); replay.Decorations.Add(new CircleDecoration(true, end, magmaRadius, (start, end), "rgba(255, 50, 50, 0.25)", new PositionConnector(pylonPosition))); replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (end, (int)log.FightData.FightEnd), "rgba(255, 50, 0, 0.5)", new PositionConnector(pylonPosition))); } foreach (AbstractCastEvent c in forceOfHavoc) { int roadLength = 2400; int roadWidth = 360; int hitboxOffset = 200; int subdivisions = 100; int rollOutTime = 3250; start = (int)c.Time; int preCastTime = 1500; int duration = 22500; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time <= start + 1000); Point3D position = replay.Positions.LastOrDefault(x => x.Time <= start + 1000); if (facing != null && position != null) { float direction = ParserHelper.RadianToDegreeF(Math.Atan2(facing.Y, facing.X)); replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, roadLength, roadWidth, direction, roadLength / 2 + 200, (start, start + preCastTime), "rgba(255, 0, 0, 0.1)", new PositionConnector(position))); for (int i = 0; i < subdivisions; i++) { replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, roadLength / subdivisions, roadWidth, direction, (int)((i + 0.5) * roadLength / subdivisions + hitboxOffset), (start + preCastTime + i * (rollOutTime / subdivisions), start + preCastTime + i * (rollOutTime / subdivisions) + duration), "rgba(143, 0, 179, 0.6)", new PositionConnector(position))); } } } foreach (AbstractCastEvent c in forceOfRetal) { int radius = 650; double radiusIncrement = 433.3; int preCastTime = 1800; int timeBetweenCascades = 200; int cascades = 5; start = (int)c.Time + 1400; Point3D position = replay.Positions.LastOrDefault(x => x.Time <= start + 1000); replay.Decorations.Add(new CircleDecoration(true, 0, radius, (start, start + preCastTime), "rgba(255, 220, 50, 0.15)", new PositionConnector(position))); replay.Decorations.Add(new CircleDecoration(true, start + preCastTime, radius, (start, start + preCastTime), "rgba(255, 220, 50, 0.25)", new PositionConnector(position))); for (int i = 0; i < cascades; i++) { replay.Decorations.Add(new DoughnutDecoration(true, 0, radius + (int)(radiusIncrement * i), radius + (int)(radiusIncrement * (i + 1)), (start + preCastTime + timeBetweenCascades * i, start + preCastTime + timeBetweenCascades * (i + 1)), "rgba(30, 30, 30, 0.5)", new PositionConnector(position))); replay.Decorations.Add(new DoughnutDecoration(true, 0, radius + (int)(radiusIncrement * i), radius + (int)(radiusIncrement * (i + 1)), (start + preCastTime + timeBetweenCascades * (i + 1), start + preCastTime + timeBetweenCascades * (i + 2)), "rgba(50, 20, 50, 0.25)", new PositionConnector(position))); } } foreach (AbstractCastEvent c in etherStrikes) { int coneRadius = 2600; int coneAngle = 60; start = (int)c.Time; end = start + 250; Point3D facing = replay.Rotations.LastOrDefault(x => x.Time <= start + 300); replay.Decorations.Add(new PieDecoration(false, 0, coneRadius, facing, coneAngle, (start, end), "rgba(255, 100, 0, 0.30)", new AgentConnector(target))); replay.Decorations.Add(new PieDecoration(true, 0, coneRadius, facing, coneAngle, (start, end), "rgba(255, 100, 0, 0.1)", new AgentConnector(target))); } foreach (AbstractCastEvent c in causticChaos) { double acceleration = c.Acceleration; double ratio = 1.0; if (acceleration > 0) { ratio = acceleration * 0.5 + 1; } else { ratio = acceleration * 0.6 + 1; } int chaosLength = 2600; int chaosWidth = 100; start = (int)c.Time; end = (int)c.EndTime; int aimTime = (int)((double)c.ExpectedDuration * ratio); replay.Decorations.Add(new FacingDecoration((0, end), new AgentConnector(target), replay.PolledRotations)); replay.Decorations.Add(new FacingRectangleDecoration((start, end), new AgentConnector(target), replay.PolledRotations, chaosLength, chaosWidth, chaosLength / 2, "rgba(255,100,0,0.3)")); if (end > start + aimTime) { replay.Decorations.Add(new FacingRectangleDecoration((start + aimTime, end), new AgentConnector(target), replay.PolledRotations, chaosLength, chaosWidth, chaosLength / 2, "rgba(100,100,100,0.7)")); } } foreach (AbstractCastEvent c in expoReperc) { int radius = 650; start = (int)c.Time; end = (int)c.EndTime; Point3D position = replay.Positions.LastOrDefault(x => x.Time <= start + 1000); replay.Decorations.Add(new CircleDecoration(true, 0, radius, (start, end), "rgba(255, 220, 0, 0.15)", new PositionConnector(position))); replay.Decorations.Add(new CircleDecoration(true, end, radius, (start, end), "rgba(255, 220, 50, 0.25)", new PositionConnector(position))); foreach (NPC pylon in TrashMobs.Where(x => x.ID == 21962)) { replay.Decorations.Add(new CircleDecoration(true, 0, radius, (start, end), "rgba(255, 220, 0, 0.15)", new AgentConnector(pylon))); replay.Decorations.Add(new CircleDecoration(true, end, radius, (start, end), "rgba(255, 220, 50, 0.25)", new AgentConnector(pylon))); } } break; case (int)ArcDPSEnums.TrashID.EntropicDistortion: //sapping surge, red tether List <AbstractBuffEvent> sappingSurge = GetFilteredList(log.CombatData, SappingSurge, target, true, true); int surgeStart = 0; AbstractSingleActor source = null; foreach (AbstractBuffEvent c in sappingSurge) { if (c is BuffApplyEvent) { AbstractSingleActor qadim = Targets.FirstOrDefault(x => x.ID == (int)ArcDPSEnums.TargetID.PeerlessQadim); surgeStart = (int)c.Time; source = (AbstractSingleActor)log.PlayerList.FirstOrDefault(x => x.AgentItem == c.CreditedBy) ?? qadim; } else { int surgeEnd = (int)c.Time; if (source != null) { replay.Decorations.Add(new LineDecoration(0, (surgeStart, surgeEnd), "rgba(255, 0, 0, 0.3)", new AgentConnector(target), new AgentConnector(source))); } } } Point3D firstEntropicPosition = replay.PolledPositions.FirstOrDefault(); if (firstEntropicPosition != null) { replay.Decorations.Add(new CircleDecoration(true, 0, 300, (start - 5000, start), "rgba(255, 0, 0, 0.4)", new PositionConnector(firstEntropicPosition))); replay.Decorations.Add(new CircleDecoration(true, start, 300, (start - 5000, start), "rgba(255, 0, 0, 0.4)", new PositionConnector(firstEntropicPosition))); } break; case (int)ArcDPSEnums.TrashID.BigKillerTornado: replay.Decorations.Add(new CircleDecoration(true, 0, 450, (start, end), "rgba(255, 150, 0, 0.4)", new AgentConnector(target))); break; case (int)ArcDPSEnums.TrashID.Pylon1: break; case (int)ArcDPSEnums.TrashID.Pylon2: break; case (int)ArcDPSEnums.TrashID.EnergyOrb: replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, end), "rgba(0, 255, 0, 0.3)", new AgentConnector(target))); break; default: break; } }
internal DoughnutDecorationSerializable(ParsedEvtcLog log, DoughnutDecoration decoration, CombatReplayMap map) : base(log, decoration, map) { Type = "Doughnut"; OuterRadius = decoration.OuterRadius; InnerRadius = decoration.InnerRadius; }