Skip to content

Commit

Permalink
Merge pull request #948 from Linkaaaaa/wing8
Browse files Browse the repository at this point in the history
Wing 8 mechanics and combat replay
  • Loading branch information
EliphasNUIT authored Nov 24, 2024
2 parents cf76e6d + 2d722d4 commit 4437dee
Show file tree
Hide file tree
Showing 19 changed files with 334 additions and 101 deletions.
9 changes: 7 additions & 2 deletions GW2EIEvtcParser/EIData/Buffs/EncounterBuffs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ internal static class EncounterBuffs
new Buff("Nova Shield", NovaShield, Source.FightSpecific, BuffClassification.Other, BuffImages.DiaphanousShielding),
new Buff("Harmonic Sensitivity", HarmonicSensitivity, Source.FightSpecific, BuffClassification.Debuff, BuffImages.Tracked),
new Buff("Galvanic Sensitivity", GalvanicSensitivity, Source.FightSpecific, BuffClassification.Debuff, BuffImages.ExposedEyes),
new Buff("Thrumming Presence", ThrummingPresence, Source.FightSpecific, BuffClassification.Debuff, BuffImages.ConjuredBarrier),
new Buff("Thrumming Presence", ThrummingPresenceBuff, Source.FightSpecific, BuffClassification.Debuff, BuffImages.ConjuredBarrier),
new Buff("Charge (Decima)", ChargeDecima, Source.FightSpecific, BuffStackType.Stacking, 10, BuffClassification.Other, BuffImages.ElectricalBuildup),
new Buff("Decima Beam Targeting", DecimaBeamLoading, Source.FightSpecific, BuffClassification.Unknown, BuffImages.Unknown),
new Buff("Decima Red Beam Targeting", DecimaRedBeamLoading, Source.FightSpecific, BuffClassification.Unknown, BuffImages.Unknown),
Expand All @@ -395,11 +395,16 @@ internal static class EncounterBuffs
new Buff("Target Order: 5 (JW)", TargetOrder5JW, Source.FightSpecific, BuffClassification.Other, BuffImages.TargetOrder5),
new Buff("Focused Fluxlance", FocusedFluxlance, Source.FightSpecific, BuffClassification.Other, BuffImages.Unknown),
new Buff("Unstoppable (Decima)", UnstoppableDecima, Source.FightSpecific, BuffClassification.Other, BuffImages.Enraged),
new Buff("Fluxlance Target (Buff 1)", FluxlanceTargetBuff1, Source.FightSpecific, BuffClassification.Other, BuffImages.Target),
new Buff("Fluxlance Target (Buff 2)", FluxlanceTargetBuff2, Source.FightSpecific, BuffClassification.Other, BuffImages.Target),
new Buff("Fluxlance Target (Red Arrow)", FluxlanceRedArrowTargetBuff, Source.FightSpecific, BuffClassification.Other, BuffImages.Target2),
// Greer
new Buff("Empowered (Greer)", EmpoweredGreer, Source.FightSpecific, BuffStackType.Stacking, 99, BuffClassification.Other, BuffImages.EmpoweredMursaarOverseer),
new Buff("Damage Immunity", DamageImmunity, Source.FightSpecific, BuffClassification.Other, BuffImages.DefensiveInspiration),
new Buff("Infectious Rot", InfectiousRotBuff, Source.FightSpecific, BuffClassification.Other, BuffImages.MonsterSkill),
// Ura
new Buff("Pressure Blast", PressureBlast, Source.FightSpecific, BuffClassification.Other, BuffImages.Unknown),
new Buff("Pressure Blast", PressureBlastBubbleBuff, Source.FightSpecific, BuffClassification.Other, BuffImages.Unknown),
new Buff("Pressure Blast Target", PressureBlastTargetBuff, Source.FightSpecific, BuffClassification.Other, BuffImages.Unknown),
new Buff("Sulfuric Acid", SulfuricAcid, Source.FightSpecific, BuffStackType.Stacking, 99, BuffClassification.Other, BuffImages.SulfuricAcid),
new Buff("Deterrence", Deterrence, Source.FightSpecific, BuffClassification.Other, BuffImages.Deterrence),
new Buff("Bloodstone Saturation", BloodstoneSaturation, Source.FightSpecific, BuffStackType.Stacking, 25, BuffClassification.Other, BuffImages.BloodstoneSaturation),
Expand Down
4 changes: 2 additions & 2 deletions GW2EIEvtcParser/EIData/CombatReplay/CombatReplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ internal void AddTether(IEnumerable<BuffEvent> tethers, Color color, double opac
/// <param name="color">color of the tether</param>
/// <param name="thickness">thickness of the tether</param>
/// <param name="worldSizeThickess">true to indicate that thickness is in inches instead of pixels</param>
internal void addTetherWithCustomConnectors(ParsedEvtcLog log, IEnumerable<BuffEvent> tethers, string color, CustomConnectorBuilder srcConnectorBuilder, CustomConnectorBuilder dstConnectorBuilder, uint thickness = 2, bool worldSizeThickess = false)
internal void AddTetherWithCustomConnectors(ParsedEvtcLog log, IEnumerable<BuffEvent> tethers, string color, CustomConnectorBuilder srcConnectorBuilder, CustomConnectorBuilder dstConnectorBuilder, uint thickness = 2, bool worldSizeThickess = false)
{
int tetherStart = 0;
AgentItem src = ParserHelper._unknownAgent;
Expand Down Expand Up @@ -548,7 +548,7 @@ internal void addTetherWithCustomConnectors(ParsedEvtcLog log, IEnumerable<BuffE
/// <param name="worldSizeThickess">true to indicate that thickness is in inches instead of pixels</param>
internal void AddTetherWithCustomConnectors(ParsedEvtcLog log, IEnumerable<BuffEvent> tethers, Color color, double opacity, CustomConnectorBuilder srcConnectorBuilder, CustomConnectorBuilder dstConnectorBuilder, uint thickness = 2, bool worldSizeThickess = false)
{
addTetherWithCustomConnectors(log, tethers, color.WithAlpha(opacity).ToString(true), srcConnectorBuilder, dstConnectorBuilder, thickness, worldSizeThickess);
AddTetherWithCustomConnectors(log, tethers, color.WithAlpha(opacity).ToString(true), srcConnectorBuilder, dstConnectorBuilder, thickness, worldSizeThickess);
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions GW2EIEvtcParser/EIData/MathUtils/GenericSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public struct GenericSegment<T>(long start, long end, T? value)
public long Start = start;
public long End = end;
public T? Value = value; //TODO(Rennorb) @perf @cleanup
public readonly (long, long) TimeSpan => (Start, End);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public GenericSegment(long start, long end) : this(start, end, default) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public Kanaxai(int triggerID) : base(triggerID)
return diff > -ServerDelayConstant && diff <= 1000;
});
}),
new PlayerDstBuffApplyMechanic([RendingStormAxeTargetBuff1, RendingStormAxeTargetBuff2], "Rending Storm Target", new MechanicPlotlySetting(Symbols.CircleX, Colors.LightPurple), "RendStm.T", "Targetted by Rending Storm (Axe Throw)", "Rending Storm Target", 150),
new PlayerDstBuffApplyMechanic([RendingStormAxeTargetBuff1, RendingStormAxeTargetBuff2], "Rending Storm Target", new MechanicPlotlySetting(Symbols.CircleX, Colors.LightPurple), "RendStm.T", "Targeted by Rending Storm (Axe Throw)", "Rending Storm Target", 150),
});
Extension = "kanaxai";
Icon = EncounterIconKanaxai;
Expand Down
82 changes: 75 additions & 7 deletions GW2EIEvtcParser/EncounterLogic/Raids/W8/DecimaTheStormsinger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using static GW2EIEvtcParser.EncounterLogic.EncounterImages;
using static GW2EIEvtcParser.EncounterLogic.EncounterLogicPhaseUtils;
using static GW2EIEvtcParser.EncounterLogic.EncounterLogicUtils;
using static GW2EIEvtcParser.ParserHelper;
using static GW2EIEvtcParser.SkillIDs;

namespace GW2EIEvtcParser.EncounterLogic;
Expand All @@ -16,6 +17,15 @@ internal class DecimaTheStormsinger : MountBalrior
{
public DecimaTheStormsinger(int triggerID) : base(triggerID)
{
MechanicList.AddRange(new List<Mechanic>()
{
new PlayerDstHitMechanic(Fluxlance, "Fluxlance", new MechanicPlotlySetting(Symbols.StarSquare, Colors.LightOrange), "Fluxlance.H", "Hit by Fluxlance (Single Orange Arrow)", "Fluxlance Hit", 0),
new PlayerDstHitMechanic(FluxlanceFusillade, "Fluxlance Fusillade", new MechanicPlotlySetting(Symbols.StarDiamond, Colors.LightOrange), "FluxFusi.H", "Hit by Fluxlance Fusillade (Sequential Orange Arrows)", "Fluxlance Fusillade Hit", 0),
new PlayerDstHitMechanic([FluxlanceSalvo1, FluxlanceSalvo2, FluxlanceSalvo3, FluxlanceSalvo4, FluxlanceSalvo5], "Fluxlance Salvo", new MechanicPlotlySetting(Symbols.StarDiamondOpen, Colors.LightOrange), "FluxSalvo.H", "Hit by Fluxlance Salvo (Simultaneous Orange Arrows)", "Fluxlance Salvo Hit", 0),
new PlayerDstBuffApplyMechanic([TargetOrder1JW, TargetOrder2JW, TargetOrder3JW, TargetOrder4JW, TargetOrder5JW], "Target Order", new MechanicPlotlySetting(Symbols.StarTriangleDown, Colors.LightOrange), "FluxOrder.T", "Targeted by Fluxlance (Target Order)", "Fluxlance Target (Sequential)", 0),
new PlayerDstBuffApplyMechanic(FluxlanceTargetBuff1, "Fluxlance", new MechanicPlotlySetting(Symbols.StarTriangleDown, Colors.Orange), "Fluxlance.T", "Targeted by Fluxlance", "Fluxlance Target", 0),
new PlayerDstBuffApplyMechanic(FluxlanceRedArrowTargetBuff, "Fluxlance", new MechanicPlotlySetting(Symbols.StarTriangleDown, Colors.Red), "FluxRed.T", "Targeted by Fluxlance (Red Arrow)", "Fluxlance (Red Arrow)", 0),
});
Extension = "decima";
Icon = EncounterIconDecima;
EncounterCategoryInformation.InSubCategoryOrder = 1;
Expand All @@ -41,15 +51,22 @@ protected override ReadOnlySpan<int> GetTargetsIDs()
{
return
[
ArcDPSEnums.TrashID.GreenOrb1Person,
ArcDPSEnums.TrashID.GreenOrb2Persons,
ArcDPSEnums.TrashID.GreenOrb3Persons,
ArcDPSEnums.TrashID.GreenOrb1Player,
ArcDPSEnums.TrashID.GreenOrb2Players,
ArcDPSEnums.TrashID.GreenOrb3Players,
ArcDPSEnums.TrashID.EnlightenedConduit,
ArcDPSEnums.TrashID.DecimaBeamEnd,
ArcDPSEnums.TrashID.DecimaBeamStart,
ArcDPSEnums.TrashID.DecimaBeamEnd,
];
}

internal override List<InstantCastFinder> GetInstantCastFinders()
{
return
[
new DamageCastFinder(ThrummingPresenceBuff, ThrummingPresenceDamage),
];
}

internal override List<PhaseData> GetPhases(ParsedEvtcLog log, bool requirePhases)
{
Expand Down Expand Up @@ -86,17 +103,35 @@ internal override void ComputeNPCCombatReplayActors(NPC target, ParsedEvtcLog lo
switch (target.ID)
{
case (int)ArcDPSEnums.TargetID.Decima:
var casts = target.GetCastEvents(log, log.FightData.FightStart, log.FightData.FightEnd).ToList();

AddRedRing(target, log, replay, casts, DecimaSpawnsConduitsP1);
AddRedRing(target, log, replay, casts, DecimaSpawnsConduitsP2);
AddRedRing(target, log, replay, casts, DecimaSpawnsConduitsP3);

if (log.CombatData.TryGetEffectEventsBySrcWithGUID(target.AgentItem, EffectGUIDs.DecimaMainshockIndicator, out var mainshockSlices))
{
foreach (EffectEvent effect in mainshockSlices)
{
long duration = 2300;
long growing = effect.Time + duration;
(long start, long end) lifespan2 = effect.ComputeLifespan(log, duration);
var rotation = new AngleConnector(effect.Rotation.Z + 90);
var slice = (PieDecoration)new PieDecoration(1200, 32, lifespan2, Colors.LightOrange, 0.4, new PositionConnector(effect.Position)).UsingRotationConnector(rotation);
replay.AddDecorationWithBorder(slice, Colors.LightOrange, 0.6);
}
}
break;
// TODO: find all greens and their proper sizes
case (int)ArcDPSEnums.TrashID.GreenOrb1Person:
case (int)ArcDPSEnums.TrashID.GreenOrb1Player:
replay.AddOverheadIcon(lifespan, target, ParserIcons.TargetOrder1Overhead);
//replay.Decorations.Add(new CircleDecoration(100, lifespan, Colors.Green, 0.3, new AgentConnector(target)));
break;
case (int)ArcDPSEnums.TrashID.GreenOrb2Persons:
case (int)ArcDPSEnums.TrashID.GreenOrb2Players:
replay.AddOverheadIcon(lifespan, target, ParserIcons.TargetOrder2Overhead);
//replay.Decorations.Add(new CircleDecoration(200, lifespan, Colors.Green, 0.3, new AgentConnector(target)));
break;
case (int)ArcDPSEnums.TrashID.GreenOrb3Persons:
case (int)ArcDPSEnums.TrashID.GreenOrb3Players:
replay.AddOverheadIcon(lifespan, target, ParserIcons.TargetOrder3Overhead);
//replay.Decorations.Add(new CircleDecoration(200, lifespan, Colors.Green, 0.3, new AgentConnector(target)));
break;
Expand Down Expand Up @@ -180,10 +215,43 @@ internal override void ComputePlayerCombatReplayActors(PlayerActor player, Parse
{
base.ComputePlayerCombatReplayActors(player, log, replay);

// Target Overhead
// In phase 2 you get the Fluxlance Target Buff but also Target Order, in game only Target Order is displayed overhead, so we filter those out.
var p2Targets = player.GetBuffStatus(log, [TargetOrder1JW, TargetOrder2JW, TargetOrder3JW, TargetOrder4JW, TargetOrder5JW], log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0);
var allTargets = player.GetBuffStatus(log, FluxlanceTargetBuff1, log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0);
var filtered = allTargets.Where(x => !p2Targets.Any(y => Math.Abs(x.Start - y.Start) < ServerDelayConstant));
foreach (var segment in filtered)
{
replay.AddOverheadIcon(segment, player, ParserIcons.TargetOverhead);
}

// Target Order Overhead
replay.AddOverheadIcons(player.GetBuffStatus(log, TargetOrder1JW, log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0), player, ParserIcons.TargetOrder1Overhead);
replay.AddOverheadIcons(player.GetBuffStatus(log, TargetOrder2JW, log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0), player, ParserIcons.TargetOrder2Overhead);
replay.AddOverheadIcons(player.GetBuffStatus(log, TargetOrder3JW, log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0), player, ParserIcons.TargetOrder3Overhead);
replay.AddOverheadIcons(player.GetBuffStatus(log, TargetOrder4JW, log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0), player, ParserIcons.TargetOrder4Overhead);
replay.AddOverheadIcons(player.GetBuffStatus(log, TargetOrder5JW, log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0), player, ParserIcons.TargetOrder5Overhead);
}

/// <summary>
/// The ring appears when Decima spawns conduits and ends when she starts the breakbar (Flux Nova).
/// </summary>
private static void AddRedRing(NPC target, ParsedEvtcLog log, CombatReplay replay, List<CastEvent> casts, long skillId)
{
var conduitsSpawn = casts.FirstOrDefault(x => x.SkillId == skillId);

// Return only if P2 and P3 are null
if (conduitsSpawn == null && skillId != DecimaSpawnsConduitsP1)
{
return;
}

// The spawn of the first conduits might be missing in the log, we use FightStart.
long start = conduitsSpawn != null ? conduitsSpawn.Time : log.FightData.FightStart;
var breakbar = casts.FirstOrDefault(x => x.SkillId == FluxNova && x.Time > start);
long end = breakbar != null ? breakbar.Time : log.FightData.FightEnd;

(long start, long end) lifespan = (start, end);
replay.Decorations.Add(new CircleDecoration(700, lifespan, Colors.Red, 0.2, new AgentConnector(target)).UsingFilled(false));
}
}
35 changes: 35 additions & 0 deletions GW2EIEvtcParser/EncounterLogic/Raids/W8/GreerTheBlightbringer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@ namespace GW2EIEvtcParser.EncounterLogic;

internal class GreerTheBlightbringer : MountBalrior
{
private readonly long[] ReflectableProjectiles = [BlobOfBlight, BlobOfBlight2, ScatteringSporeblast, RainOfSpores];
public GreerTheBlightbringer(int triggerID) : base(triggerID)
{
MechanicList.AddRange(new List<Mechanic>()
{
new PlayerSrcHitMechanic(ReflectableProjectiles, "Reflected Projectiles", new MechanicPlotlySetting(Symbols.YDown, Colors.Pink), "ProjRefl.Greer.H", "Reflected projectiles have hit Greer", "Reflected Projectile Hit (Greer)", 0).UsingChecker((hde, log) => hde.To.IsSpecies(ArcDPSEnums.TargetID.Greer)),
new PlayerSrcHitMechanic(ReflectableProjectiles, "Reflected Projectiles", new MechanicPlotlySetting(Symbols.YDown, Colors.Purple), "ProjRefl.Reeg.H", "Reflected projectiles have hit Reeg", "Reflected Projectile Hit (Reeg)", 0).UsingChecker((hde, log) => hde.To.IsSpecies(ArcDPSEnums.TrashID.Reeg)),
new PlayerSrcHitMechanic(ReflectableProjectiles, "Reflected Projectiles", new MechanicPlotlySetting(Symbols.YDown, Colors.LightPurple), "ProjRefl.Gree.H", "Reflected projectiles have hit Gree", "Reflected Projectile Hit (Gree)", 0).UsingChecker((hde, log) => hde.To.IsSpecies(ArcDPSEnums.TrashID.Gree)),
new PlayerDstBuffApplyMechanic(InfectiousRotBuff, "Infectious Rot", new MechanicPlotlySetting(Symbols.CircleX, Colors.Red), "InfRot.T", "Targeted by Infectious Rot (Failed Green)", "Infectious Rot (Green Fail)", 0),
new PlayerDstEffectMechanic(EffectGUIDs.GreerNoxiousBlightGreen, "Noxious Blight", new MechanicPlotlySetting(Symbols.Circle, Colors.Green), "NoxBlight.T", "Targeted by Noxious Blight (Green)", "Noxious Blight (Green)", 0),
});
Extension = "greer";
Icon = EncounterIconGreer;
EncounterCategoryInformation.InSubCategoryOrder = 0;
Expand Down Expand Up @@ -101,4 +110,30 @@ internal override List<PhaseData> GetPhases(ParsedEvtcLog log, bool requirePhase
}
return phases;
}

internal override void ComputePlayerCombatReplayActors(PlayerActor player, ParsedEvtcLog log, CombatReplay replay)
{
base.ComputePlayerCombatReplayActors(player, log, replay);

// Noxious Blight - Green AoE
if (log.CombatData.TryGetEffectEventsByDstWithGUID(player.AgentItem, EffectGUIDs.GreerNoxiousBlightGreen, out var noxiousBlight))
{
foreach (EffectEvent effect in noxiousBlight)
{
long duration = 10000;
long growing = effect.Time + duration;
(long start, long end) lifespan = effect.ComputeLifespan(log, duration);
var circle = new CircleDecoration(240, lifespan, Colors.Green, 0.2, new AgentConnector(player));
replay.AddDecorationWithGrowing(circle, growing);
}
}

// Infectious Rot - Failed Green AoE
var infectiousRot = player.GetBuffStatus(log, InfectiousRotBuff, log.FightData.LogStart, log.FightData.LogEnd).Where(x => x.Value > 0);
foreach (var segment in infectiousRot)
{
replay.Decorations.Add(new CircleDecoration(200, segment.TimeSpan, Colors.Red, 0.2, new AgentConnector(player)));
}

}
}
8 changes: 8 additions & 0 deletions GW2EIEvtcParser/EncounterLogic/Raids/W8/MountBalrior.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@

using GW2EIEvtcParser.EIData;
using static GW2EIEvtcParser.EncounterLogic.EncounterCategory;
using static GW2EIEvtcParser.SkillIDs;

namespace GW2EIEvtcParser.EncounterLogic;

internal abstract class MountBalrior : RaidLogic
{
public MountBalrior(int triggerID) : base(triggerID)
{
MechanicList.AddRange(new List<Mechanic>
{
new PlayerDstBuffApplyMechanic(ExposedPlayer, "Exposed", new MechanicPlotlySetting(Symbols.TriangleLeft, Colors.Purple, 10), "Exposed", "Exposed Applied (Increased incoming damage)", "Exposed Applied", 0),
new PlayerDstBuffApplyMechanic(Debilitated, "Debilitated", new MechanicPlotlySetting(Symbols.TriangleDown, Colors.Purple, 10), "Debilitated", "Debilitated Applied (Reduced outgoing damage)", "Debilitated Applied", 0),
new PlayerDstBuffApplyMechanic(Infirmity, "Infirmity", new MechanicPlotlySetting(Symbols.TriangleUp, Colors.Purple, 10), "Infirmity", "Infirmity Applied (Reduced incoming healing)", "Infirmity", 0),
});
EncounterCategoryInformation.SubCategory = SubFightCategory.MountBalrior;
EncounterID |= EncounterIDs.RaidWingMasks.MountBalriorMask;
}
Expand Down
Loading

0 comments on commit 4437dee

Please sign in to comment.