|
| 1 | +using Dalamud.Game.ClientState.Objects.Types; |
| 2 | +using Dalamud.Game.Gui.PartyFinder.Types; |
| 3 | +using ECommons; |
| 4 | +using ECommons.DalamudServices; |
| 5 | +using ECommons.ExcelServices; |
| 6 | +using ECommons.Hooks.ActionEffectTypes; |
| 7 | +using ECommons.Logging; |
| 8 | +using ECommons.MathHelpers; |
| 9 | +using Splatoon.SplatoonScripting; |
| 10 | +using System; |
| 11 | +using System.Collections.Generic; |
| 12 | +using System.Linq; |
| 13 | +using System.Numerics; |
| 14 | +using System.Text; |
| 15 | + |
| 16 | +namespace SplatoonScriptsOfficial.Duties.Dawntrail; |
| 17 | + |
| 18 | +public class EX6_Arcane_Revelation : SplatoonScript |
| 19 | +{ |
| 20 | + public override Metadata Metadata { get; } = new(1, "NightmareXIV"); |
| 21 | + public override HashSet<uint>? ValidTerritories { get; } = [1308]; |
| 22 | + |
| 23 | + public override void OnSetup() |
| 24 | + { |
| 25 | + Controller.RegisterElementFromCode("Danger", """{"Name":"","radius":16.0,"fillIntensity":0.5}"""); |
| 26 | + } |
| 27 | + |
| 28 | + |
| 29 | + public Dictionary<CardinalDirection, Vector2> RawDirections = new() |
| 30 | + { |
| 31 | + [CardinalDirection.North] = new(100f, 240f), |
| 32 | + [CardinalDirection.West] = new(95.17041f, 249.98853f), |
| 33 | + [CardinalDirection.South] = new(100f, 260f), |
| 34 | + [CardinalDirection.East] = new(104.78369f, 249.98853f), |
| 35 | + }; |
| 36 | + |
| 37 | + public Dictionary<CardinalDirection, Vector2> Directions |
| 38 | + { |
| 39 | + get |
| 40 | + { |
| 41 | + if(Svc.Objects.TryGetFirst(x => x.DataId == DataId, out var obj)) |
| 42 | + { |
| 43 | + if(Vector2.Distance(obj.Position.ToVector2(), new(100f, 350f)) < 16f) |
| 44 | + { |
| 45 | + return RawDirections.ToDictionary(x => x.Key, x => x.Value with { Y = x.Value.Y + 100 }); |
| 46 | + } |
| 47 | + } |
| 48 | + return RawDirections; |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + public uint DataId = 18998; |
| 53 | + |
| 54 | + public uint Move3 = 45657; |
| 55 | + public uint Move2 = 45656; |
| 56 | + |
| 57 | + public bool DirectionDetermined = false; |
| 58 | + public CardinalDirection CurrentDirection = 0; |
| 59 | + public int NumMoves = 0; |
| 60 | + |
| 61 | + public override void OnReset() |
| 62 | + { |
| 63 | + NumMoves = 0; |
| 64 | + CurrentDirection = (CardinalDirection)(-1); |
| 65 | + DirectionDetermined = false; |
| 66 | + } |
| 67 | + |
| 68 | + public override void OnActionEffectEvent(ActionEffectSet set) |
| 69 | + { |
| 70 | + if(set.Action != null && set.Source is IBattleNpc bnpc && bnpc.Name.ToString() != "Automaton Queen") |
| 71 | + { |
| 72 | + PluginLog.Information($"Cast from: {bnpc}, {ExcelActionHelper.GetActionName(set.Action?.RowId ?? 0, true)}"); |
| 73 | + if(set.Action?.RowId.EqualsAny(47527u, 45713u, 45714u) == true) |
| 74 | + { |
| 75 | + DirectionDetermined = false; |
| 76 | + CurrentDirection = (CardinalDirection)(-1); |
| 77 | + NumMoves = 0; |
| 78 | + PluginLog.Information($"Initial: {CurrentDirection}, {NumMoves}, {DirectionDetermined}"); |
| 79 | + } |
| 80 | + if(set.Action?.RowId == Move2) |
| 81 | + { |
| 82 | + NumMoves = 2; |
| 83 | + PluginLog.Information($"2 moves"); |
| 84 | + } |
| 85 | + if(set.Action?.RowId == Move3) |
| 86 | + { |
| 87 | + NumMoves = 3; |
| 88 | + PluginLog.Information($"3 moves"); |
| 89 | + } |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + public override void OnUpdate() |
| 94 | + { |
| 95 | + Controller.GetRegisteredElements().Each(x => x.Value.Enabled = false); |
| 96 | + if(Svc.Objects.TryGetFirst(x => x.DataId == DataId, out var obj)) |
| 97 | + { |
| 98 | + if(DirectionDetermined) |
| 99 | + { |
| 100 | + if(Controller.TryGetElementByName("Danger", out var e)) |
| 101 | + { |
| 102 | + e.SetRefPosition(Directions[CurrentDirection].ToVector3()); |
| 103 | + e.Enabled = true; |
| 104 | + } |
| 105 | + } |
| 106 | + if(CurrentDirection == (CardinalDirection)(-1)) |
| 107 | + { |
| 108 | + CurrentDirection = GetCurrentDirection(); |
| 109 | + if(CurrentDirection != (CardinalDirection)(-1))PluginLog.Information($"Current direction set: {CurrentDirection}, {DirectionDetermined}, {NumMoves}"); |
| 110 | + } |
| 111 | + else if(!DirectionDetermined && NumMoves != 0) |
| 112 | + { |
| 113 | + if(GetCurrentDirection() == (CardinalDirection)(-1)) |
| 114 | + { |
| 115 | + CurrentDirection = GetNextDirection(); |
| 116 | + PluginLog.Information($"Determined next direction: {CurrentDirection}, {DirectionDetermined}, {NumMoves}"); |
| 117 | + DirectionDetermined = true; |
| 118 | + NumMoves = 0; |
| 119 | + } |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + public CardinalDirection GetNextDirection() |
| 125 | + { |
| 126 | + CardinalDirection[] cw = [CardinalDirection.North, CardinalDirection.East, CardinalDirection.South, CardinalDirection.West]; |
| 127 | + var currentIndex = cw.IndexOf(CurrentDirection); |
| 128 | + var nextCwPoint = cw.CircularSelect(currentIndex + 1); |
| 129 | + var isCw = IsPointGoingTowards(nextCwPoint); |
| 130 | + PluginLog.Information($"Num moves: {(isCw ? this.NumMoves : -this.NumMoves)}"); |
| 131 | + return cw.CircularSelect(currentIndex + (isCw ? this.NumMoves : -this.NumMoves)); |
| 132 | + } |
| 133 | + |
| 134 | + public CardinalDirection GetCurrentDirection() |
| 135 | + { |
| 136 | + if(Svc.Objects.TryGetFirst(x => x.DataId == DataId, out var obj)) |
| 137 | + { |
| 138 | + foreach(var p in Directions) |
| 139 | + { |
| 140 | + if(Vector2.Distance(p.Value, obj.Position.ToVector2()) < 1) |
| 141 | + { |
| 142 | + return p.Key; |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + return (CardinalDirection)(-1); |
| 147 | + } |
| 148 | + |
| 149 | + public bool IsPointGoingTowards(CardinalDirection direction) |
| 150 | + { |
| 151 | + return IsPointOnLine(Svc.Objects.First(x => x.DataId == DataId).Position.ToVector2(), Directions[CurrentDirection], Directions[direction]); |
| 152 | + } |
| 153 | + |
| 154 | + public bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd, float tolerance = 0.5f) |
| 155 | + { |
| 156 | + // Calculate the distance from point to the line segment |
| 157 | + Vector2 lineVector = lineEnd - lineStart; |
| 158 | + Vector2 pointVector = point - lineStart; |
| 159 | + |
| 160 | + // Calculate line length manually |
| 161 | + float lineLength = (float)Math.Sqrt(lineVector.X * lineVector.X + lineVector.Y * lineVector.Y); |
| 162 | + |
| 163 | + // Handle degenerate case where start and end are the same point |
| 164 | + if(lineLength < tolerance) |
| 165 | + { |
| 166 | + float distToStart = (float)Math.Sqrt( |
| 167 | + (point.X - lineStart.X) * (point.X - lineStart.X) + |
| 168 | + (point.Y - lineStart.Y) * (point.Y - lineStart.Y) |
| 169 | + ); |
| 170 | + return distToStart <= tolerance; |
| 171 | + } |
| 172 | + |
| 173 | + // Normalize the line vector |
| 174 | + Vector2 lineDirection = new Vector2(lineVector.X / lineLength, lineVector.Y / lineLength); |
| 175 | + |
| 176 | + // Project the point onto the line |
| 177 | + float projectionLength = pointVector.X * lineDirection.X + pointVector.Y * lineDirection.Y |
| 178 | + ; |
| 179 | + |
| 180 | + // Check if the projection is within the line segment bounds |
| 181 | + if(projectionLength < -tolerance || projectionLength > lineLength + tolerance) |
| 182 | + { |
| 183 | + return false; |
| 184 | + } |
| 185 | + |
| 186 | + // Calculate the perpendicular distance from point to line |
| 187 | + Vector2 projectedPoint = new Vector2( |
| 188 | + lineStart.X + lineDirection.X * projectionLength, |
| 189 | + lineStart.Y + lineDirection.Y * projectionLength |
| 190 | + ); |
| 191 | + |
| 192 | + float distance = (float)Math.Sqrt( |
| 193 | + (point.X - projectedPoint.X) * (point.X - projectedPoint.X) + |
| 194 | + (point.Y - projectedPoint.Y) * (point.Y - projectedPoint.Y) |
| 195 | + ); |
| 196 | + |
| 197 | + return distance <= tolerance; |
| 198 | + } |
| 199 | +} |
0 commit comments