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.Xera:
                var summon = cls.Where(x => x.SkillId == 34887).ToList();
                foreach (AbstractCastEvent c in summon)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 180, ((int)c.Time, (int)c.EndTime), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                break;

            case (int)ArcDPSEnums.TrashID.ChargedBloodstone:
                if (_xeraFirstPhaseEndTime != 0)
                {
                    replay.Trim(_xeraFirstPhaseEndTime + 12000, replay.TimeOffsets.end);
                }
                break;

            case (int)ArcDPSEnums.TrashID.BloodstoneFragment:
                replay.Decorations.Add(new CircleDecoration(true, 0, 760, ((int)replay.TimeOffsets.start, (int)replay.TimeOffsets.end), "rgba(255, 155, 0, 0.2)", new AgentConnector(target)));
                break;

            default:
                break;
            }
        }
Example #2
0
        public override void ComputeNPCCombatReplayActors(NPC target, ParsedLog log, CombatReplay replay)
        {
            List <AbstractCastEvent> cls = target.GetCastLogs(log, 0, log.FightData.FightEnd);

            switch (target.ID)
            {
            case (int)ParseEnum.TargetIDS.Slothasor:
                var sleepy = cls.Where(x => x.SkillId == 34515).ToList();
                foreach (AbstractCastEvent c in sleepy)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 180, ((int)c.Time, (int)c.Time + c.ActualDuration), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                var breath = cls.Where(x => x.SkillId == 34516).ToList();
                foreach (AbstractCastEvent c in breath)
                {
                    int     start       = (int)c.Time;
                    int     preCastTime = 1000;
                    int     duration    = 2000;
                    int     range       = 600;
                    Point3D facing      = replay.Rotations.LastOrDefault(x => x.Time <= start + 1000);
                    if (facing != null)
                    {
                        int direction = Point3D.GetRotationFromFacing(facing);
                        int angle     = 60;
                        replay.Decorations.Add(new PieDecoration(true, 0, range, direction, angle, (start, start + preCastTime), "rgba(255,200,0,0.1)", new AgentConnector(target)));
                        replay.Decorations.Add(new PieDecoration(true, 0, range, direction, angle, (start + preCastTime, start + preCastTime + duration), "rgba(255,200,0,0.4)", new AgentConnector(target)));
                    }
                }
                var tantrum = cls.Where(x => x.SkillId == 34547).ToList();
                foreach (AbstractCastEvent c in tantrum)
                {
                    int start = (int)c.Time;
                    int end   = start + c.ActualDuration;
                    replay.Decorations.Add(new CircleDecoration(false, 0, 300, (start, end), "rgba(255, 150, 0, 0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new CircleDecoration(true, end, 300, (start, end), "rgba(255, 150, 0, 0.4)", new AgentConnector(target)));
                }
                var shakes = cls.Where(x => x.SkillId == 34482).ToList();
                foreach (AbstractCastEvent c in shakes)
                {
                    int start = (int)c.Time;
                    int end   = start + c.ActualDuration;
                    replay.Decorations.Add(new CircleDecoration(false, 0, 700, (start, end), "rgba(255, 0, 0, 0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new CircleDecoration(true, end, 700, (start, end), "rgba(255, 0, 0, 0.4)", 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);

            switch (target.ID)
            {
            case (int)ArcDPSEnums.TargetID.Slothasor:
                var sleepy = cls.Where(x => x.SkillId == NarcolepsySkill).ToList();
                foreach (AbstractCastEvent c in sleepy)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 180, ((int)c.Time, (int)c.EndTime), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                var breath = cls.Where(x => x.SkillId == Halitosis).ToList();
                foreach (AbstractCastEvent c in breath)
                {
                    int     start       = (int)c.Time;
                    int     preCastTime = 1000;
                    int     duration    = 2000;
                    int     range       = 600;
                    Point3D facing      = replay.Rotations.LastOrDefault(x => x.Time <= start + 1000);
                    if (facing != null)
                    {
                        float direction = Point3D.GetRotationFromFacing(facing);
                        int   angle     = 60;
                        replay.Decorations.Add(new PieDecoration(true, 0, range, direction, angle, (start, start + preCastTime), "rgba(255,200,0,0.1)", new AgentConnector(target)));
                        replay.Decorations.Add(new PieDecoration(true, 0, range, direction, angle, (start + preCastTime, start + preCastTime + duration), "rgba(255,200,0,0.4)", new AgentConnector(target)));
                    }
                }
                var tantrum = cls.Where(x => x.SkillId == TantrumSkill).ToList();
                foreach (AbstractCastEvent c in tantrum)
                {
                    int start = (int)c.Time;
                    int end   = (int)c.EndTime;
                    replay.Decorations.Add(new CircleDecoration(false, 0, 300, (start, end), "rgba(255, 150, 0, 0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new CircleDecoration(true, end, 300, (start, end), "rgba(255, 150, 0, 0.4)", new AgentConnector(target)));
                }
                var shakes = cls.Where(x => x.SkillId == SporeRelease).ToList();
                foreach (AbstractCastEvent c in shakes)
                {
                    int start = (int)c.Time;
                    int end   = (int)c.EndTime;
                    replay.Decorations.Add(new CircleDecoration(false, 0, 700, (start, end), "rgba(255, 0, 0, 0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new CircleDecoration(true, end, 700, (start, end), "rgba(255, 0, 0, 0.4)", new AgentConnector(target)));
                }
                break;

            default:
                break;
            }
        }
Example #4
0
        public override void ComputeNPCCombatReplayActors(NPC target, ParsedLog log, CombatReplay replay)
        {
            List <AbstractCastEvent> cls = target.GetCastLogs(log, 0, log.FightData.FightEnd);

            switch (target.ID)
            {
            case (int)ParseEnum.TargetIDS.Xera:
                var summon = cls.Where(x => x.SkillId == 34887).ToList();
                foreach (AbstractCastEvent c in summon)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 180, ((int)c.Time, (int)c.Time + c.ActualDuration), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                break;

            default:
                break;
            }
        }
Example #5
0
        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.Xera:
                var summon = cls.Where(x => x.SkillId == 34887).ToList();
                foreach (AbstractCastEvent c in summon)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 180, ((int)c.Time, (int)c.EndTime), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                break;

            default:
                break;
            }
        }
        private static void AddMatthiasBubbles(long buffID, NPC target, ParsedEvtcLog log, CombatReplay replay)
        {
            List <AbstractBuffEvent> shields = GetFilteredList(log.CombatData, buffID, target, true);
            int start = 0;

            for (int i = 0; i < shields.Count; i++)
            {
                AbstractBuffEvent buffEvent = shields[i];
                if (buffEvent is BuffApplyEvent)
                {
                    start = (int)buffEvent.Time;
                    if (i == shields.Count - 1)
                    {
                        replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)start, (int)log.FightData.FightEnd), "rgba(255, 0, 255, 0.5)", new AgentConnector(target)));
                    }
                }
                else
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)start, (int)buffEvent.Time), "rgba(255, 0, 255, 0.5)", new AgentConnector(target)));
                }
            }
        }
        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.TrashID.Jade:
                List <AbstractBuffEvent> shield = GetFilteredList(log.CombatData, 38155, target, true);
                int shieldStart  = 0;
                int shieldRadius = 100;
                foreach (AbstractBuffEvent c in shield)
                {
                    if (c is BuffApplyEvent)
                    {
                        shieldStart = (int)c.Time;
                    }
                    else
                    {
                        int shieldEnd = (int)c.Time;
                        replay.Decorations.Add(new CircleDecoration(true, 0, shieldRadius, (shieldStart, shieldEnd), "rgba(255, 200, 0, 0.3)", new AgentConnector(target)));
                    }
                }
                var explosion = cls.Where(x => x.SkillId == 37788).ToList();
                foreach (AbstractCastEvent c in explosion)
                {
                    int start    = (int)c.Time;
                    int precast  = 1350;
                    int duration = 100;
                    int radius   = 1200;
                    replay.Decorations.Add(new CircleDecoration(true, 0, radius, (start, start + precast + duration), "rgba(255, 0, 0, 0.05)", new AgentConnector(target)));
                    replay.Decorations.Add(new CircleDecoration(true, 0, radius, (start + precast, start + precast + duration), "rgba(255, 0, 0, 0.25)", new AgentConnector(target)));
                }
                break;

            default:
                break;
            }
        }
Example #8
0
        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.Nikare:
                //CC
                var barrageN = cls.Where(x => x.SkillId == 51977).ToList();
                foreach (AbstractCastEvent c in barrageN)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)c.Time, (int)c.EndTime), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                //Platform wipe (CM only)
                var aquaticDomainN = cls.Where(x => x.SkillId == 52374).ToList();
                foreach (AbstractCastEvent c in aquaticDomainN)
                {
                    int start  = (int)c.Time;
                    int end    = (int)c.EndTime;
                    int radius = 800;
                    replay.Decorations.Add(new CircleDecoration(true, end, radius, (start, end), "rgba(255, 255, 0, 0.3)", new AgentConnector(target)));
                }
                break;

            case (int)ArcDPSEnums.TargetID.Kenut:
                //CC
                var barrageK = cls.Where(x => x.SkillId == 51977).ToList();
                foreach (AbstractCastEvent c in barrageK)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)c.Time, (int)c.EndTime), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                //Platform wipe (CM only)
                var aquaticDomainK = cls.Where(x => x.SkillId == 52374).ToList();
                foreach (AbstractCastEvent c in aquaticDomainK)
                {
                    int start  = (int)c.Time;
                    int end    = (int)c.EndTime;
                    int radius = 800;
                    replay.Decorations.Add(new CircleDecoration(true, end, radius, (start, end), "rgba(255, 255, 0, 0.3)", new AgentConnector(target)));
                }
                var shockwave = cls.Where(x => x.SkillId == 53018).ToList();
                foreach (AbstractCastEvent c in shockwave)
                {
                    int start    = (int)c.Time;
                    int delay    = 960;
                    int duration = 3000;
                    int radius   = 1200;
                    replay.Decorations.Add(new CircleDecoration(false, start + delay + duration, radius, (start + delay, start + delay + duration), "rgba(100, 200, 255, 0.5)", new AgentConnector(target)));
                }
                var boonSteal = cls.Where(x => x.SkillId == 51965).ToList();
                foreach (AbstractCastEvent c in boonSteal)
                {
                    int     start    = (int)c.Time;
                    int     delay    = 1000;
                    int     duration = 500;
                    int     width    = 500;
                    int     height   = 250;
                    Point3D facing   = replay.Rotations.FirstOrDefault(x => x.Time >= start);
                    if (facing != null)
                    {
                        float rotation = Point3D.GetRotationFromFacing(facing);
                        replay.Decorations.Add(new RotatedRectangleDecoration(false, 0, width, height, rotation, width / 2, (start + delay, start + delay + duration), "rgba(255, 175, 0, 0.8)", new AgentConnector(target)));
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, rotation, width / 2, (start + delay, start + delay + duration), "rgba(255, 175, 0, 0.2)", new AgentConnector(target)));
                    }
                }
                break;

            default:
                break;
            }
        }
        internal override void ComputePlayerCombatReplayActors(AbstractPlayer p, ParsedEvtcLog log, CombatReplay replay)
        {
            // fixated
            List <AbstractBuffEvent> fixated = GetFilteredList(log.CombatData, FixatedQadimThePeerless, p, true, true);
            int fixatedStart = 0;

            foreach (AbstractBuffEvent c in fixated)
            {
                if (c is BuffApplyEvent)
                {
                    fixatedStart = Math.Max((int)c.Time, 0);
                }
                else
                {
                    int fixatedEnd = (int)c.Time;
                    replay.Decorations.Add(new CircleDecoration(true, 0, 120, (fixatedStart, fixatedEnd), "rgba(255, 80, 255, 0.3)", new AgentConnector(p)));
                }
            }
            // Chaos Corrosion
            List <AbstractBuffEvent> chaosCorrosion = GetFilteredList(log.CombatData, ChaosCorrosion, p, true, true);
            int corrosionStart = 0;

            foreach (AbstractBuffEvent c in chaosCorrosion)
            {
                if (c is BuffApplyEvent)
                {
                    corrosionStart = (int)c.Time;
                }
                else
                {
                    int corrosionEnd = (int)c.Time;
                    replay.Decorations.Add(new CircleDecoration(true, 0, 100, (corrosionStart, corrosionEnd), "rgba(80, 80, 80, 0.3)", new AgentConnector(p)));
                }
            }
            // Critical Mass, debuff while carrying an orb
            List <AbstractBuffEvent> criticalMass = GetFilteredList(log.CombatData, CriticalMass, p, true, true);
            int criticalMassStart = 0;

            foreach (AbstractBuffEvent c in criticalMass)
            {
                if (c is BuffApplyEvent)
                {
                    criticalMassStart = (int)c.Time;
                }
                else
                {
                    int criticalMassEnd = (int)c.Time;
                    replay.Decorations.Add(new CircleDecoration(false, 0, 200, (criticalMassStart, criticalMassEnd), "rgba(255, 0, 0, 0.3)", new AgentConnector(p)));
                }
            }
            // Magma drop
            List <AbstractBuffEvent> magmaDrop = GetFilteredList(log.CombatData, MagmaDrop, p, true, true);
            int magmaDropStart = 0;
            int magmaRadius    = 420;
            int magmaOffset    = 4000;

            string[] magmaColors = { "255, 215, 0", "255, 130, 50" };
            int      magmaColor  = 0;

            foreach (AbstractBuffEvent c in magmaDrop)
            {
                if (c is BuffApplyEvent)
                {
                    magmaDropStart = (int)c.Time;
                }
                else
                {
                    int magmaDropEnd = (int)c.Time;
                    replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (magmaDropStart, magmaDropEnd), "rgba(255, 50, 0, 0.15)", new AgentConnector(p)));
                    replay.Decorations.Add(new CircleDecoration(true, magmaDropEnd, magmaRadius, (magmaDropStart, magmaDropEnd), "rgba(255, 50, 0, 0.25)", new AgentConnector(p)));
                    Point3D magmaNextPos = replay.PolledPositions.FirstOrDefault(x => x.Time >= magmaDropEnd);
                    Point3D magmaPrevPos = replay.PolledPositions.LastOrDefault(x => x.Time <= magmaDropEnd);
                    if (magmaNextPos != null || magmaPrevPos != null)
                    {
                        string colorToUse = magmaColors[magmaColor];
                        magmaColor = (magmaColor + 1) % 2;
                        replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (magmaDropEnd, magmaDropEnd + magmaOffset), "rgba(" + colorToUse + ", 0.15)", new InterpolatedPositionConnector(magmaPrevPos, magmaNextPos, magmaDropEnd)));
                        replay.Decorations.Add(new CircleDecoration(true, magmaDropEnd + magmaOffset, magmaRadius, (magmaDropEnd, magmaDropEnd + magmaOffset), "rgba(" + colorToUse + ", 0.25)", new InterpolatedPositionConnector(magmaPrevPos, magmaNextPos, magmaDropEnd)));
                        replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (magmaDropEnd + magmaOffset, (int)log.FightData.FightEnd), "rgba(" + colorToUse + ", 0.5)", new InterpolatedPositionConnector(magmaPrevPos, magmaNextPos, magmaDropEnd)));
                    }
                }
            }
            //sapping surge, bad red tether
            List <AbstractBuffEvent> sappingSurge = GetFilteredList(log.CombatData, SappingSurge, p, 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.4)", new AgentConnector(p), new AgentConnector(source)));
                    }
                }
            }
            // kinetic abundance, good (blue) tether
            List <AbstractBuffEvent> kineticAbundance = GetFilteredList(log.CombatData, KineticAbundance, p, true, true);
            int kinStart = 0;
            AbstractSingleActor kinSource = null;

            foreach (AbstractBuffEvent c in kineticAbundance)
            {
                if (c is BuffApplyEvent)
                {
                    kinStart = (int)c.Time;
                    //kinSource = log.PlayerList.FirstOrDefault(x => x.AgentItem == c.By);
                    kinSource = (AbstractSingleActor)log.PlayerList.FirstOrDefault(x => x.AgentItem == c.CreditedBy) ?? TrashMobs.FirstOrDefault(x => x.AgentItem == c.CreditedBy);
                }
                else
                {
                    int kinEnd = (int)c.Time;
                    if (kinSource != null)
                    {
                        replay.Decorations.Add(new LineDecoration(0, (kinStart, kinEnd), "rgba(0, 0, 255, 0.4)", new AgentConnector(p), new AgentConnector(kinSource)));
                    }
                }
            }
        }
        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 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.Sabetha:
                var flameWall = cls.Where(x => x.SkillId == 31332).ToList();
                foreach (AbstractCastEvent c in flameWall)
                {
                    int     start = (int)c.Time;
                    int     preCastTime = 2800;
                    int     duration = 10000;
                    int     width = 1300; int height = 60;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time <= start);
                    if (facing != null)
                    {
                        int initialDirection = (int)(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI);
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, initialDirection, width / 2, (start, start + preCastTime), "rgba(255, 100, 0, 0.2)", new AgentConnector(target)));
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, initialDirection, width / 2, 360, (start + preCastTime, start + preCastTime + duration), "rgba(255, 50, 0, 0.5)", new AgentConnector(target)));
                    }
                }
                break;

            case (int)ArcDPSEnums.TrashID.Kernan:
                var bulletHail = cls.Where(x => x.SkillId == 31721).ToList();
                foreach (AbstractCastEvent c in bulletHail)
                {
                    int     start           = (int)c.Time;
                    int     firstConeStart  = start;
                    int     secondConeStart = start + 800;
                    int     thirdConeStart  = start + 1600;
                    int     firstConeEnd    = firstConeStart + 400;
                    int     secondConeEnd   = secondConeStart + 400;
                    int     thirdConeEnd    = thirdConeStart + 400;
                    int     radius          = 1500;
                    Point3D facing          = replay.Rotations.LastOrDefault(x => x.Time <= start);
                    if (facing != null)
                    {
                        replay.Decorations.Add(new PieDecoration(true, 0, radius, facing, 28, (firstConeStart, firstConeEnd), "rgba(255,200,0,0.3)", new AgentConnector(target)));
                        replay.Decorations.Add(new PieDecoration(true, 0, radius, facing, 54, (secondConeStart, secondConeEnd), "rgba(255,200,0,0.3)", new AgentConnector(target)));
                        replay.Decorations.Add(new PieDecoration(true, 0, radius, facing, 81, (thirdConeStart, thirdConeEnd), "rgba(255,200,0,0.3)", new AgentConnector(target)));
                    }
                }
                break;

            case (int)ArcDPSEnums.TrashID.Knuckles:
                var breakbar = cls.Where(x => x.SkillId == 31763).ToList();
                foreach (AbstractCastEvent c in breakbar)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 180, ((int)c.Time, (int)c.EndTime), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                break;

            case (int)ArcDPSEnums.TrashID.Karde:
                var flameBlast = cls.Where(x => x.SkillId == 31761).ToList();
                foreach (AbstractCastEvent c in flameBlast)
                {
                    int     start  = (int)c.Time;
                    int     end    = start + 4000;
                    int     radius = 600;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time <= start);
                    if (facing != null)
                    {
                        replay.Decorations.Add(new PieDecoration(true, 0, radius, facing, 60, (start, end), "rgba(255,200,0,0.5)", new AgentConnector(target)));
                    }
                }
                break;

            default:
                break;
            }
        }
Example #12
0
        internal override void ComputeNPCCombatReplayActors(NPC target, ParsedEvtcLog log, CombatReplay replay)
        {
            int crStart = (int)replay.TimeOffsets.start;
            int crEnd   = (int)replay.TimeOffsets.end;
            IReadOnlyList <AbstractCastEvent> cls = target.GetCastEvents(log, 0, log.FightData.FightEnd);

            switch (target.ID)
            {
            case (int)ArcDPSEnums.TargetID.Sabir:
                List <AbstractBuffEvent> repulsionFields = GetFilteredList(log.CombatData, RepulsionField, target, true, true);
                int repulsionFieldStart = 0;
                foreach (AbstractBuffEvent c in repulsionFields)
                {
                    if (c is BuffApplyEvent)
                    {
                        repulsionFieldStart = (int)c.Time;
                    }
                    else
                    {
                        int repulsionFieldEnd = (int)c.Time;
                        replay.Decorations.Add(new CircleDecoration(true, 0, 120, (repulsionFieldStart, repulsionFieldEnd), "rgba(80, 0, 255, 0.3)", new AgentConnector(target)));
                    }
                }
                List <AbstractBuffEvent> ionShields = GetFilteredList(log.CombatData, IonShield, target, true, true);
                int ionShieldStart = 0;
                foreach (AbstractBuffEvent c in ionShields)
                {
                    if (c is BuffApplyEvent)
                    {
                        ionShieldStart = (int)c.Time;
                    }
                    else
                    {
                        int ionShieldEnd = (int)c.Time;
                        replay.Decorations.Add(new CircleDecoration(true, 0, 120, (ionShieldStart, ionShieldEnd), "rgba(0, 80, 255, 0.3)", new AgentConnector(target)));
                    }
                }
                //
                var furyOfTheStorm = cls.Where(x => x.SkillId == 56372).ToList();
                foreach (AbstractCastEvent c in furyOfTheStorm)
                {
                    replay.Decorations.Add(new CircleDecoration(true, (int)c.EndTime, 1200, ((int)c.Time, (int)c.EndTime), "rgba(0, 180, 255, 0.3)", new AgentConnector(target)));
                }
                //
                var unbridledTempest = cls.Where(x => x.SkillId == 56643).ToList();
                foreach (AbstractCastEvent c in unbridledTempest)
                {
                    int     start          = (int)c.Time;
                    int     delay          = 3000; // casttime 0 from skill def
                    int     duration       = 5000;
                    int     radius         = 1200;
                    Point3D targetPosition = replay.PolledPositions.LastOrDefault(x => x.Time <= start + 1000);
                    if (targetPosition != null)
                    {
                        replay.Decorations.Add(new CircleDecoration(true, 0, radius, (start, start + delay), "rgba(255, 100, 0, 0.2)", new PositionConnector(targetPosition)));
                        replay.Decorations.Add(new CircleDecoration(true, 0, radius, (start + delay - 10, start + delay + 100), "rgba(255, 100, 0, 0.5)", new PositionConnector(targetPosition)));
                        replay.Decorations.Add(new CircleDecoration(false, start + duration, radius, (start + delay, start + duration), "rgba(255, 150, 0, 0.7)", new PositionConnector(targetPosition)));
                    }
                }
                break;

            case (int)ArcDPSEnums.TrashID.BigKillerTornado:
                replay.Decorations.Add(new CircleDecoration(true, 0, 480, (crStart, crEnd), "rgba(255, 150, 0, 0.4)", new AgentConnector(target)));
                break;

            case (int)ArcDPSEnums.TrashID.SmallKillerTornado:
                replay.Decorations.Add(new CircleDecoration(true, 0, 120, (crStart, crEnd), "rgba(255, 150, 0, 0.4)", new AgentConnector(target)));
                break;

            case (int)ArcDPSEnums.TrashID.SmallJumpyTornado:
            case (int)ArcDPSEnums.TrashID.ParalyzingWisp:
            case (int)ArcDPSEnums.TrashID.VoltaicWisp:
                break;

            default:
                break;
            }
        }
        internal override void ComputeNPCCombatReplayActors(NPC target, ParsedEvtcLog log, CombatReplay replay)
        {
            int crStart = (int)replay.TimeOffsets.start;
            int crEnd   = (int)replay.TimeOffsets.end;
            IReadOnlyList <AbstractCastEvent> cls = target.GetCastEvents(log, 0, log.FightData.FightEnd);

            switch (target.ID)
            {
            case (int)ArcDPSEnums.TargetID.Adina:
                var doubleQuantumQuakes = cls.Where(x => x.SkillId == 56035).ToList();
                foreach (AbstractCastEvent c in doubleQuantumQuakes)
                {
                    int start = (int)c.Time;
                    int preCastTime = 2990;     // casttime 0
                    int duration = c.ActualDuration;
                    int width = 1100; int height = 60;
                    foreach (int angle in new List <int> {
                        90, 270
                    })
                    {
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, angle, width / 2, (start, start + preCastTime), "rgba(255, 100, 0, 0.2)", new AgentConnector(target)));
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, angle, width / 2, 360, (start + preCastTime, start + duration), "rgba(255, 50, 0, 0.5)", new AgentConnector(target)));
                    }
                }
                //
                var tripleQuantumQuakes = cls.Where(x => x.SkillId == 56381).ToList();
                foreach (AbstractCastEvent c in tripleQuantumQuakes)
                {
                    int start = (int)c.Time;
                    int preCastTime = 2990;     // casttime 0
                    int duration = c.ActualDuration;
                    int width = 1100; int height = 60;
                    foreach (int angle in new List <int> {
                        30, 150, 270
                    })
                    {
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, angle, width / 2, (start, start + preCastTime), "rgba(255, 100, 0, 0.2)", new AgentConnector(target)));
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, angle, width / 2, 360, (start + preCastTime, start + duration), "rgba(255, 50, 0, 0.5)", new AgentConnector(target)));
                    }
                }
                //
                var terraforms = cls.Where(x => x.SkillId == 56049).ToList();
                foreach (AbstractCastEvent c in terraforms)
                {
                    int start    = (int)c.Time;
                    int delay    = 2000;  // casttime 0 from skill def
                    int duration = 5000;
                    int radius   = 1100;
                    replay.Decorations.Add(new CircleDecoration(false, start + duration, radius, (start + delay, start + duration), "rgba(255, 150, 0, 0.7)", new AgentConnector(target)));
                }
                //
                List <AbstractBuffEvent> diamondPalisades = GetFilteredList(log.CombatData, 56636, target, true, true);
                int diamondPalisadeStart = 0;
                foreach (AbstractBuffEvent c in diamondPalisades)
                {
                    if (c is BuffApplyEvent)
                    {
                        diamondPalisadeStart = (int)c.Time;
                    }
                    else
                    {
                        replay.Decorations.Add(new CircleDecoration(true, 0, 90, (diamondPalisadeStart, (int)c.Time), "rgba(200, 0, 0, 0.3)", new AgentConnector(target)));
                    }
                }
                //
                var boulderBarrages = cls.Where(x => x.SkillId == 56648).ToList();
                foreach (AbstractCastEvent c in boulderBarrages)
                {
                    int start    = (int)c.Time;
                    int duration = 4600;     // cycle 3 from skill def
                    int radius   = 1100;
                    replay.Decorations.Add(new CircleDecoration(true, start + duration, radius, (start, start + duration), "rgba(255, 150, 0, 0.4)", new AgentConnector(target)));
                }
                break;

            default:
                break;
            }
        }
Example #14
0
 internal CircleDecorationSerializable(ParsedEvtcLog log, CircleDecoration decoration, CombatReplayMap map) : base(log, decoration, map)
 {
     Type      = "Circle";
     Radius    = decoration.Radius;
     MinRadius = decoration.MinRadius;
 }
        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.KeepConstruct:

                List <AbstractBuffEvent> kcOrbCollect = GetFilteredList(log.CombatData, XerasBoon, target, true, true);
                int kcOrbStart = 0, kcOrbEnd = 0;
                foreach (AbstractBuffEvent c in kcOrbCollect)
                {
                    if (c is BuffApplyEvent)
                    {
                        kcOrbStart = (int)c.Time;
                    }
                    else
                    {
                        kcOrbEnd = (int)c.Time;
                        replay.Decorations.Add(new CircleDecoration(false, 0, 300, (kcOrbStart, kcOrbEnd), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                        replay.Decorations.Add(new CircleDecoration(true, kcOrbEnd, 300, (kcOrbStart, kcOrbEnd), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                    }
                }
                var towerDrop  = cls.Where(x => x.SkillId == TowerDrop).ToList();
                foreach (AbstractCastEvent c in towerDrop)
                {
                    start = (int)c.Time;
                    end   = (int)c.EndTime;
                    int     skillCast = end - 1000;
                    Point3D next      = replay.PolledPositions.FirstOrDefault(x => x.Time >= end);
                    Point3D prev      = replay.PolledPositions.LastOrDefault(x => x.Time <= end);
                    if (prev != null || next != null)
                    {
                        replay.Decorations.Add(new CircleDecoration(false, 0, 400, (start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end)));
                        replay.Decorations.Add(new CircleDecoration(true, skillCast, 400, (start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end)));
                    }
                }
                var blades1    = cls.Where(x => x.SkillId == PhantasmalBlades1).ToList();
                var blades2    = cls.Where(x => x.SkillId == PhantasmalBlades2).ToList();
                var blades3    = cls.Where(x => x.SkillId == PhantasmalBlades3).ToList();
                int bladeDelay = 150;
                int duration   = 1000;
                foreach (AbstractCastEvent c in blades1)
                {
                    int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9));
                    start = (int)c.Time + bladeDelay;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000);
                    if (facing == null)
                    {
                        continue;
                    }
                    replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new PieDecoration(true, 0, 1600, facing, 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,0,255,0.5)", new AgentConnector(target)));     // First blade lasts twice as long
                    for (int i = 1; i < ticks; i++)
                    {
                        replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(facing.Y, facing.X)) + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,0,255,0.5)", new AgentConnector(target)));     // First blade lasts longer
                    }
                }
                foreach (AbstractCastEvent c in blades2)
                {
                    int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9));
                    start = (int)c.Time + bladeDelay;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000);
                    if (facing == null)
                    {
                        continue;
                    }
                    replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new PieDecoration(true, 0, 1600, facing, 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,0,255,0.5)", new AgentConnector(target)));                                                           // First blade lasts twice as long
                    replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X))), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,0,255,0.5)", new AgentConnector(target))); // First blade lasts twice as long
                    for (int i = 1; i < ticks; i++)
                    {
                        replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(facing.Y, facing.X)) + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,0,255,0.5)", new AgentConnector(target)));     // First blade lasts longer
                        replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X)) + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,0,255,0.5)", new AgentConnector(target)));   // First blade lasts longer
                    }
                }
                foreach (AbstractCastEvent c in blades3)
                {
                    int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9));
                    start = (int)c.Time + bladeDelay;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000);
                    if (facing == null)
                    {
                        continue;
                    }
                    replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X))), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,0,255,0.5)", new AgentConnector(target)));       // First blade lasts twice as long
                    replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X)) + 120), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,0,255,0.5)", new AgentConnector(target))); // First blade lasts twice as long
                    replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X)) - 120), 360 * 3 / 32, (start, start + 2 * duration), "rgba(255,0,255,0.5)", new AgentConnector(target))); // First blade lasts twice as long
                    for (int i = 1; i < ticks; i++)
                    {
                        replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X)) + i * 360 / 8), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,0,255,0.5)", new AgentConnector(target)));       // First blade lasts longer
                        replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X)) + i * 360 / 8 + 120), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,0,255,0.5)", new AgentConnector(target))); // First blade lasts longer
                        replay.Decorations.Add(new PieDecoration(true, 0, 1600, (ParserHelper.RadianToDegreeF(Math.Atan2(-facing.Y, -facing.X)) + i * 360 / 8 - 120), 360 * 3 / 32, (start + 1000 + i * duration, start + 1000 + (i + 1) * duration), "rgba(255,0,255,0.5)", new AgentConnector(target))); // First blade lasts longer
                    }
                }
                break;

            case (int)ArcDPSEnums.TrashID.KeepConstructCore:
                break;

            case (int)ArcDPSEnums.TrashID.Jessica:
            case (int)ArcDPSEnums.TrashID.Olson:
            case (int)ArcDPSEnums.TrashID.Engul:
            case (int)ArcDPSEnums.TrashID.Faerla:
            case (int)ArcDPSEnums.TrashID.Caulle:
            case (int)ArcDPSEnums.TrashID.Henley:
            case (int)ArcDPSEnums.TrashID.Galletta:
            case (int)ArcDPSEnums.TrashID.Ianim:
                replay.Decorations.Add(new CircleDecoration(false, 0, 600, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                replay.Decorations.Add(new CircleDecoration(true, 0, 400, (start, end), "rgba(0, 125, 255, 0.5)", new AgentConnector(target)));
                Point3D firstPhantasmPosition = replay.PolledPositions.FirstOrDefault();
                if (firstPhantasmPosition != null)
                {
                    replay.Decorations.Add(new CircleDecoration(true, 0, 300, (start - 5000, start), "rgba(220, 50, 0, 0.5)", new PositionConnector(firstPhantasmPosition)));
                    replay.Decorations.Add(new CircleDecoration(true, start, 300, (start - 5000, start), "rgba(220, 50, 0, 0.5)", new PositionConnector(firstPhantasmPosition)));
                }
                break;

            case (int)ArcDPSEnums.TrashID.GreenPhantasm:
                int lifetime = 8000;
                replay.Decorations.Add(new CircleDecoration(true, 0, 210, (start, start + lifetime), "rgba(0,255,0,0.2)", new AgentConnector(target)));
                replay.Decorations.Add(new CircleDecoration(true, start + lifetime, 210, (start, start + lifetime), "rgba(0,255,0,0.3)", new AgentConnector(target)));
                break;

            case (int)ArcDPSEnums.TrashID.RetrieverProjection:
            case (int)ArcDPSEnums.TrashID.InsidiousProjection:
            case (int)ArcDPSEnums.TrashID.UnstableLeyRift:
            case (int)ArcDPSEnums.TrashID.RadiantPhantasm:
            case (int)ArcDPSEnums.TrashID.CrimsonPhantasm:
                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.Matthias:
                var humanShield        = cls.Where(x => x.SkillId == 34468).ToList();
                var humanShieldRemoval = log.CombatData.GetBuffRemoveAllData(34518).Select(x => (int)x.Time).Distinct().ToList();
                for (int i = 0; i < humanShield.Count; i++)
                {
                    AbstractCastEvent shield = humanShield[i];
                    if (i < humanShieldRemoval.Count)
                    {
                        int removal = humanShieldRemoval[i];
                        replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)shield.Time, removal), "rgba(255, 0, 255, 0.5)", new AgentConnector(target)));
                    }
                    else
                    {
                        replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)shield.Time, (int)log.FightData.FightEnd), "rgba(255, 0, 255, 0.5)", new AgentConnector(target)));
                    }
                }
                var aboShield        = cls.Where(x => x.SkillId == 34510).ToList();
                var aboShieldRemoval = log.CombatData.GetBuffRemoveAllData(34376).Select(x => (int)x.Time).Distinct().ToList();
                for (int i = 0; i < aboShield.Count; i++)
                {
                    AbstractCastEvent shield = aboShield[i];
                    if (i < aboShieldRemoval.Count)
                    {
                        int removal = aboShieldRemoval[i];
                        replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)shield.Time, removal), "rgba(255, 0, 255, 0.5)", new AgentConnector(target)));
                    }
                    else
                    {
                        replay.Decorations.Add(new CircleDecoration(true, 0, 250, ((int)shield.Time, (int)log.FightData.FightEnd), "rgba(255, 0, 255, 0.5)", new AgentConnector(target)));
                    }
                }
                var rageShards = cls.Where(x => x.SkillId == 34404 || x.SkillId == 34411).ToList();
                foreach (AbstractCastEvent c in rageShards)
                {
                    start = (int)c.Time;
                    end   = (int)c.EndTime;
                    replay.Decorations.Add(new CircleDecoration(false, 0, 300, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                    replay.Decorations.Add(new CircleDecoration(true, end, 300, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                }
                var hadouken = cls.Where(x => x.SkillId == 34371 || x.SkillId == 34380).ToList();
                foreach (AbstractCastEvent c in hadouken)
                {
                    start = (int)c.Time;
                    int     preCastTime = 1000;
                    int     duration = 750;
                    int     width = 4000; int height = 130;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time <= start + 1000);
                    if (facing != null)
                    {
                        int direction = (int)(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI);
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, direction, width / 2, (start, start + preCastTime), "rgba(255, 0, 0, 0.1)", new AgentConnector(target)));
                        replay.Decorations.Add(new RotatedRectangleDecoration(true, 0, width, height, direction, width / 2, (start + preCastTime, start + preCastTime + duration), "rgba(255, 0, 0, 0.7)", new AgentConnector(target)));
                    }
                }
                break;

            case (int)ArcDPSEnums.TrashID.Storm:
                replay.Decorations.Add(new CircleDecoration(false, 0, 260, (start, end), "rgba(0, 80, 255, 0.5)", new AgentConnector(target)));
                break;

            case (int)ArcDPSEnums.TrashID.Spirit:
            case (int)ArcDPSEnums.TrashID.Spirit2:
                replay.Decorations.Add(new CircleDecoration(true, 0, 180, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                break;

            case (int)ArcDPSEnums.TrashID.IcePatch:
                replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, end), "rgba(0, 0, 255, 0.5)", new AgentConnector(target)));
                break;

            case (int)ArcDPSEnums.TrashID.Tornado:
                replay.Decorations.Add(new CircleDecoration(true, 0, 90, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                break;

            default:
                break;
            }
        }
        public override void ComputeNPCCombatReplayActors(NPC target, ParsedLog log, CombatReplay replay)
        {
            int start = (int)replay.TimeOffsets.start;
            int end   = (int)replay.TimeOffsets.end;
            List <AbstractCastEvent> cls = target.GetCastLogs(log, 0, log.FightData.FightEnd);

            switch (target.ID)
            {
            case (int)ParseEnum.TargetIDS.Deimos:
                var mindCrush = cls.Where(x => x.SkillId == 37613).ToList();
                foreach (AbstractCastEvent c in mindCrush)
                {
                    start = (int)c.Time;
                    end   = start + 5000;
                    replay.Decorations.Add(new CircleDecoration(true, end, 180, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                    replay.Decorations.Add(new CircleDecoration(false, 0, 180, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                    if (!log.FightData.IsCM)
                    {
                        replay.Decorations.Add(new CircleDecoration(true, 0, 180, (start, end), "rgba(0, 0, 255, 0.3)", new PositionConnector(new Point3D(-8421.818f, 3091.72949f, -9.818082e8f, 216))));
                    }
                }
                var annihilate = cls.Where(x => (x.SkillId == 38208) || (x.SkillId == 37929)).ToList();
                foreach (AbstractCastEvent c in annihilate)
                {
                    start = (int)c.Time;
                    int delay = 1000;
                    end = start + 2400;
                    int     duration = 120;
                    Point3D facing   = replay.Rotations.FirstOrDefault(x => x.Time >= start);
                    if (facing == null)
                    {
                        continue;
                    }
                    for (int i = 0; i < 6; i++)
                    {
                        replay.Decorations.Add(new PieDecoration(true, 0, 900, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI + i * 360 / 10), 360 / 10, (start + delay + i * duration, end + i * duration), "rgba(255, 200, 0, 0.5)", new AgentConnector(target)));
                        replay.Decorations.Add(new PieDecoration(false, 0, 900, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI + i * 360 / 10), 360 / 10, (start + delay + i * duration, end + i * 120), "rgba(255, 150, 0, 0.5)", new AgentConnector(target)));
                        if (i % 5 != 0)
                        {
                            replay.Decorations.Add(new PieDecoration(true, 0, 900, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI - i * 360 / 10), 360 / 10, (start + delay + i * duration, end + i * 120), "rgba(255, 200, 0, 0.5)", new AgentConnector(target)));
                            replay.Decorations.Add(new PieDecoration(false, 0, 900, (int)Math.Round(Math.Atan2(facing.Y, facing.X) * 180 / Math.PI - i * 360 / 10), 360 / 10, (start + delay + i * duration, end + i * 120), "rgba(255, 150, 0, 0.5)", new AgentConnector(target)));
                        }
                    }
                }
                List <AbstractBuffEvent> signets = GetFilteredList(log.CombatData, 38224, target, true);
                int sigStart = 0;
                int sigEnd   = 0;
                foreach (AbstractBuffEvent signet in signets)
                {
                    if (signet is BuffApplyEvent)
                    {
                        sigStart = (int)signet.Time;
                    }
                    else
                    {
                        sigEnd = (int)signet.Time;
                        replay.Decorations.Add(new CircleDecoration(true, 0, 120, (sigStart, sigEnd), "rgba(0, 200, 200, 0.5)", new AgentConnector(target)));
                    }
                }
                break;

            case (int)Gambler:
            case (int)Thief:
            case (int)Drunkard:
                break;

            case (int)Saul:
            case (int)GamblerClones:
            case (int)GamblerReal:
            case (int)Greed:
            case (int)Pride:
            case (int)Tear:
                break;

            case (int)Hands:
                replay.Decorations.Add(new CircleDecoration(true, 0, 90, (start, end), "rgba(255, 0, 0, 0.2)", new AgentConnector(target)));
                break;

            case (int)Oil:
                int delayOil = 3000;
                replay.Decorations.Add(new CircleDecoration(true, start + delayOil, 200, (start, start + delayOil), "rgba(255,100, 0, 0.5)", new AgentConnector(target)));
                replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start + delayOil, end), "rgba(0, 0, 0, 0.5)", new AgentConnector(target)));
                break;

            default:
                break;
            }
        }
        public override void ComputePlayerCombatReplayActors(Player p, ParsedLog log, CombatReplay replay)
        {
            // fixated
            List <AbstractBuffEvent> fixated = GetFilteredList(log.CombatData, 56510, p, true);
            int fixatedStart = 0;

            foreach (AbstractBuffEvent c in fixated)
            {
                if (c is BuffApplyEvent)
                {
                    fixatedStart = Math.Max((int)c.Time, 0);
                }
                else
                {
                    int fixatedEnd = (int)c.Time;
                    replay.Decorations.Add(new CircleDecoration(true, 0, 120, (fixatedStart, fixatedEnd), "rgba(255, 80, 255, 0.3)", new AgentConnector(p)));
                }
            }
            // Magma drop
            List <AbstractBuffEvent> magmaDrop = GetFilteredList(log.CombatData, 56475, p, true);
            int magmaDropStart = 0;
            int magmaRadius    = 420;
            int magmaOffset    = 4000;

            foreach (AbstractBuffEvent c in magmaDrop)
            {
                if (c is BuffApplyEvent)
                {
                    magmaDropStart = (int)c.Time;
                }
                else
                {
                    int magmaDropEnd = (int)c.Time;
                    replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (magmaDropStart, magmaDropEnd), "rgba(255, 150, 0, 0.15)", new AgentConnector(p)));
                    replay.Decorations.Add(new CircleDecoration(true, magmaDropEnd, magmaRadius, (magmaDropStart, magmaDropEnd), "rgba(255, 150, 0, 0.25)", new AgentConnector(p)));
                    Point3D magmaNextPos = replay.PolledPositions.FirstOrDefault(x => x.Time >= magmaDropEnd);
                    Point3D magmaPrevPos = replay.PolledPositions.LastOrDefault(x => x.Time <= magmaDropEnd);
                    if (magmaNextPos != null || magmaPrevPos != null)
                    {
                        replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (magmaDropEnd, magmaDropEnd + magmaOffset), "rgba(255, 220, 50, 0.15)", new InterpolatedPositionConnector(magmaPrevPos, magmaNextPos, magmaDropEnd)));
                        replay.Decorations.Add(new CircleDecoration(true, magmaDropEnd + magmaOffset, magmaRadius, (magmaDropEnd, magmaDropEnd + magmaOffset), "rgba(255, 220, 50, 0.25)", new InterpolatedPositionConnector(magmaPrevPos, magmaNextPos, magmaDropEnd)));
                        replay.Decorations.Add(new CircleDecoration(true, 0, magmaRadius, (magmaDropEnd + magmaOffset, (int)log.FightData.FightEnd), "rgba(255, 220, 50, 0.5)", new InterpolatedPositionConnector(magmaPrevPos, magmaNextPos, magmaDropEnd)));
                    }
                }
            }
            //sapping surge, bad red tether
            List <AbstractBuffEvent> sappingSurge = GetFilteredList(log.CombatData, 56118, p, true);
            int surgeStart             = 0;
            AbstractSingleActor source = null;

            foreach (AbstractBuffEvent c in sappingSurge)
            {
                if (c is BuffApplyEvent)
                {
                    NPC qadim = Targets.Find(x => x.ID == (int)ParseEnum.TargetID.PeerlessQadim);
                    surgeStart = (int)c.Time;
                    source     = (AbstractSingleActor)log.PlayerList.FirstOrDefault(x => x.AgentItem == c.By) ?? qadim;
                }
                else
                {
                    int surgeEnd = (int)c.Time;
                    if (source != null)
                    {
                        replay.Decorations.Add(new LineDecoration(0, (surgeStart, surgeEnd), "rgba(255, 0, 0, 0.4)", new AgentConnector(p), new AgentConnector(source)));
                    }
                }
            }
            // kinetic abundance, good (blue) tether
            List <AbstractBuffEvent> kineticAbundance = GetFilteredList(log.CombatData, 56609, p, true);
            int kinStart = 0;
            AbstractSingleActor kinSource = null;

            foreach (AbstractBuffEvent c in kineticAbundance)
            {
                if (c is BuffApplyEvent)
                {
                    kinStart = (int)c.Time;
                    //kinSource = log.PlayerList.FirstOrDefault(x => x.AgentItem == c.By);
                    kinSource = (AbstractSingleActor)log.PlayerList.FirstOrDefault(x => x.AgentItem == c.By) ?? TrashMobs.FirstOrDefault(x => x.AgentItem == c.By);
                }
                else
                {
                    int kinEnd = (int)c.Time;
                    if (kinSource != null)
                    {
                        replay.Decorations.Add(new LineDecoration(0, (kinStart, kinEnd), "rgba(0, 0, 255, 0.4)", new AgentConnector(p), new AgentConnector(kinSource)));
                    }
                }
            }
        }
        public override void ComputeNPCCombatReplayActors(NPC target, ParsedLog log, CombatReplay replay)
        {
            List <AbstractCastEvent> cls = target.GetCastLogs(log, 0, log.FightData.FightEnd);
            int start = (int)replay.TimeOffsets.start;
            int end   = (int)replay.TimeOffsets.end;

            switch (target.ID)
            {
            case (int)ParseEnum.TargetIDS.KeepConstruct:

                List <AbstractBuffEvent> kcOrbCollect = GetFilteredList(log.CombatData, 35025, target, true);
                int kcOrbStart = 0, kcOrbEnd = 0;
                foreach (AbstractBuffEvent c in kcOrbCollect)
                {
                    if (c is BuffApplyEvent)
                    {
                        kcOrbStart = (int)c.Time;
                    }
                    else
                    {
                        kcOrbEnd = (int)c.Time;
                        replay.Decorations.Add(new CircleDecoration(false, 0, 300, (kcOrbStart, kcOrbEnd), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                        replay.Decorations.Add(new CircleDecoration(true, kcOrbEnd, 300, (kcOrbStart, kcOrbEnd), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                    }
                }
                var towerDrop = cls.Where(x => x.SkillId == 35086).ToList();
                foreach (AbstractCastEvent c in towerDrop)
                {
                    start = (int)c.Time;
                    end   = start + c.ActualDuration;
                    int     skillCast = end - 1000;
                    Point3D next      = replay.PolledPositions.FirstOrDefault(x => x.Time >= end);
                    Point3D prev      = replay.PolledPositions.LastOrDefault(x => x.Time <= end);
                    if (prev != null || next != null)
                    {
                        replay.Decorations.Add(new CircleDecoration(false, 0, 400, (start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end)));
                        replay.Decorations.Add(new CircleDecoration(true, skillCast, 400, (start, skillCast), "rgba(255, 150, 0, 0.5)", new InterpolatedPositionConnector(prev, next, end)));
                    }
                }
                var blades1 = cls.Where(x => x.SkillId == 35064).ToList();
                var blades2 = cls.Where(x => x.SkillId == 35137).ToList();
                var blades3 = cls.Where(x => x.SkillId == 34971).ToList();
                int bladeDelay = 150;
                int duration = 1000;
                foreach (AbstractCastEvent c in blades1)
                {
                    int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9));
                    start = (int)c.Time + bladeDelay;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000);
                    if (facing == null)
                    {
                        continue;
                    }
                    replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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 (AbstractCastEvent c in blades2)
                {
                    int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9));
                    start = (int)c.Time + bladeDelay;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000);
                    if (facing == null)
                    {
                        continue;
                    }
                    replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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 (AbstractCastEvent c in blades3)
                {
                    int ticks = (int)Math.Max(0, Math.Min(Math.Ceiling((c.ActualDuration - 1150) / 1000.0), 9));
                    start = (int)c.Time + bladeDelay;
                    Point3D facing = replay.Rotations.LastOrDefault(x => x.Time < start + 1000);
                    if (facing == null)
                    {
                        continue;
                    }
                    replay.Decorations.Add(new CircleDecoration(true, 0, 200, (start, start + (ticks + 1) * 1000), "rgba(255,0,0,0.4)", new AgentConnector(target)));
                    replay.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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.Decorations.Add(new PieDecoration(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
                var phantasmsID = new HashSet <int>
                {
                    (int)Jessica,
                    (int)Olson,
                    (int)Engul,
                    (int)Faerla,
                    (int)Caulle,
                    (int)Henley,
                    (int)Galletta,
                    (int)Ianim,
                };
                foreach (NPC m in TrashMobs)
                {
                    if (phantasmsID.Contains(m.ID))
                    {
                        start = (int)m.FirstAware;
                        Point3D pos = m.GetCombatReplayPolledPositions(log).FirstOrDefault();
                        if (pos != null)
                        {
                            replay.Decorations.Add(new CircleDecoration(true, 0, 300, (start - 5000, start), "rgba(220, 50, 0, 0.5)", new PositionConnector(pos)));
                            replay.Decorations.Add(new CircleDecoration(true, start, 300, (start - 5000, start), "rgba(220, 50, 0, 0.5)", new PositionConnector(pos)));
                        }
                    }
                }
                break;

            case (int)Core:
                break;

            case (int)Jessica:
            case (int)Olson:
            case (int)Engul:
            case (int)Faerla:
            case (int)Caulle:
            case (int)Henley:
            case (int)Galletta:
            case (int)Ianim:
                NPC mainTarget = Targets.Find(x => x.ID == (int)ParseEnum.TargetIDS.KeepConstruct);
                if (mainTarget == null)
                {
                    throw new InvalidOperationException("Keep Construct not found");
                }
                replay.Decorations.Add(new CircleDecoration(false, 0, 600, (start, end), "rgba(255, 0, 0, 0.5)", new AgentConnector(target)));
                replay.Decorations.Add(new CircleDecoration(true, 0, 400, (start, end), "rgba(0, 125, 255, 0.5)", new AgentConnector(target)));
                break;

            case (int)GreenPhantasm:
                int lifetime = 8000;
                replay.Decorations.Add(new CircleDecoration(true, 0, 210, (start, start + lifetime), "rgba(0,255,0,0.2)", new AgentConnector(target)));
                replay.Decorations.Add(new CircleDecoration(true, start + lifetime, 210, (start, start + lifetime), "rgba(0,255,0,0.3)", new AgentConnector(target)));
                break;

            case (int)RetrieverProjection:
            case (int)InsidiousProjection:
            case (int)UnstableLeyRift:
            case (int)RadiantPhantasm:
            case (int)CrimsonPhantasm:
                break;

            default:
                break;
            }
        }
 internal CircleDecorationCombatReplayDescription(ParsedEvtcLog log, CircleDecoration decoration, CombatReplayMap map) : base(log, decoration, map)
 {
     Type      = "Circle";
     Radius    = decoration.Radius;
     MinRadius = decoration.MinRadius;
 }