diff --git a/Splatoon/Gui/Layouts/Elements/LayoutDrawElement.cs b/Splatoon/Gui/Layouts/Elements/LayoutDrawElement.cs index 51b1c764..e740feaa 100644 --- a/Splatoon/Gui/Layouts/Elements/LayoutDrawElement.cs +++ b/Splatoon/Gui/Layouts/Elements/LayoutDrawElement.cs @@ -1,14 +1,12 @@ -using Dalamud; -using Dalamud.Game; +using Dalamud.Game; using Dalamud.Interface.Components; +using Dalamud.Interface.Utility.Raii; using ECommons.GameFunctions; -using ECommons.ImGuiMethods; using ECommons.LanguageHelpers; using Lumina.Excel.GeneratedSheets; using Newtonsoft.Json; +using Splatoon.RenderEngines; using Splatoon.Serializables; -using Splatoon.Utility; -using System; namespace Splatoon; @@ -862,7 +860,62 @@ internal void LayoutDrawElement(Layout l, Element el, bool forceEnable = false) { el.SetDisplayStyle(style); } + using (ImRaii.Disabled(!el.Filled)) + { + if (el.type.EqualsAny(1, 3, 4) && el.Filled) + { + bool canSetCastAnimation = el.refActorRequireCast && el.ConfiguredRenderEngineKind() == RenderEngineKind.DirectX11; + using (ImRaii.Disabled(!canSetCastAnimation)) + { + ImGuiUtils.SizedText("Cast Animation:".Loc(), WidthElement); + ImGui.SameLine(); + } + ImGuiEx.HelpMarker("Choose a cast animation for this element. Requires 'While Casting' checked.\nUnsupported in ImGui Legacy renderer"); + ImGui.SameLine(); + using (ImRaii.Disabled(!canSetCastAnimation)) + { + ImGui.SetNextItemWidth(WidthElement); + ImGuiUtils.EnumCombo("##castanimation" + i + k, ref el.castAnimation, CastAnimations.Names, CastAnimations.Tooltips); + using (ImRaii.Disabled(el.castAnimation is CastAnimationKind.Unspecified)) + { + ImGui.SameLine(); + ImGuiEx.Text("Color:".Loc()); + ImGui.SameLine(); + var v4 = ImGui.ColorConvertU32ToFloat4(el.animationColor); + if (ImGui.ColorEdit4("##animationcolorbutton" + i + k, ref v4, ImGuiColorEditFlags.NoInputs)) + { + el.animationColor = ImGui.ColorConvertFloat4ToU32(v4); + } + ImGui.SameLine(); + if (ImGui.Button("Copy".Loc() + "##copyfromstroke" + i + k)) + { + el.animationColor = style.strokeColor; + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Copy Stroke Color".Loc()); + } + if (el.castAnimation is CastAnimationKind.Pulse) + { + ImGuiUtils.SizedText("Pulse:".Loc(), WidthElement); + ImGui.SameLine(); + + ImGuiEx.Text("Size:".Loc()); + ImGui.SameLine(); + ImGui.SetNextItemWidth(60f); + el.pulseSize = MathF.Min(el.pulseSize, el.EffectiveLength()); + ImGui.DragFloat("##animationsize" + i + k, ref el.pulseSize, 0.01f, 0.1f, el.EffectiveLength()); + ImGui.SameLine(); + ImGuiEx.Text("Frequency (s):".Loc()); + ImGui.SameLine(); + ImGui.SetNextItemWidth(60f); + ImGui.DragFloat("##animationfreq" + i + k, ref el.pulseFrequency, 0.01f, 1, 10); + } + } + } + } + } if ((el.type != 3) || el.includeRotation) { if (!(el.type == 3 && !el.includeRotation)) @@ -1028,7 +1081,7 @@ internal void LayoutDrawElement(Layout l, Element el, bool forceEnable = false) ImGuiEx.HelpMarker("Choose a mechanic type that best represents this element.\n" + "This is used for automatically setting default colors.\nOnly for DirectX11 renderer."); ImGui.SameLine(); - ImGui.SetNextItemWidth(WidthCombo); + ImGui.SetNextItemWidth(WidthElement); ImGuiUtils.EnumCombo("##mechtype" + i + k, ref el.mechanicType, MechanicTypes.Names, MechanicTypes.Tooltips); if ((el.type.EqualsAny(0, 1) && el.Donut > 0) || el.type == 4 || (el.type.EqualsAny(2, 3) && (el.radius > 0 || el.includeHitbox || el.includeOwnHitbox))) diff --git a/Splatoon/RenderEngines/DirectX11/DirectX11DisplayObjects.cs b/Splatoon/RenderEngines/DirectX11/DirectX11DisplayObjects.cs index 5f9eb71e..89fd4101 100644 --- a/Splatoon/RenderEngines/DirectX11/DirectX11DisplayObjects.cs +++ b/Splatoon/RenderEngines/DirectX11/DirectX11DisplayObjects.cs @@ -77,7 +77,13 @@ public DisplayObjectLine(float ax, float ay, float az, float bx, float by, float this.startStyle = startStyle; this.endStyle = endStyle; } - + public float Length + { + get + { + return (stop - start).Length(); + } + } public Vector3 Direction { get @@ -107,10 +113,10 @@ public Vector2[] Bounds { return [ (start - PerpendicularRadius).ToVector2(), - (start + PerpendicularRadius).ToVector2(), - (stop - PerpendicularRadius).ToVector2(), - (stop + PerpendicularRadius).ToVector2(), - ]; + (start + PerpendicularRadius).ToVector2(), + (stop - PerpendicularRadius).ToVector2(), + (stop + PerpendicularRadius).ToVector2(), + ]; } } } diff --git a/Splatoon/RenderEngines/DirectX11/DirectX11Renderer.cs b/Splatoon/RenderEngines/DirectX11/DirectX11Renderer.cs index c3c334a9..551a5782 100644 --- a/Splatoon/RenderEngines/DirectX11/DirectX11Renderer.cs +++ b/Splatoon/RenderEngines/DirectX11/DirectX11Renderer.cs @@ -60,12 +60,11 @@ internal void DrawCircle(Element e, float x, float y, float z, float r, float an { if (e.Donut > 0) { - DisplayObjects.Add(new DisplayObjectDonut(new(cx, z + e.offZ, cy), r, e.Donut, e.GetDisplayStyleWithOverride())); + DisplayObjects.Add(new DisplayObjectDonut(new(cx, z + e.offZ, cy), r, e.Donut, e.GetDisplayStyleWithOverride(go))); } else { - var style = e.GetDisplayStyleWithOverride(); - DisplayObjects.Add(new DisplayObjectCircle(new(cx, z + e.offZ, cy), r, style)); + DisplayObjects.Add(new DisplayObjectCircle(new(cx, z + e.offZ, cy), r, e.GetDisplayStyleWithOverride(go))); } } else @@ -88,7 +87,7 @@ void DrawText(Element e, IGameObject go, float cx, float cy, float z) } } - internal void DrawCone(Element e, Vector3 origin, float? radius = null, float baseAngle = 0f) + internal void DrawCone(Element e, Vector3 origin, float? radius = null, float baseAngle = 0f, IGameObject go = null) { if (e.coneAngleMax > e.coneAngleMin) { @@ -119,12 +118,13 @@ internal void DrawCone(Element e, Vector3 origin, float? radius = null, float ba } DisplayObjects.Add(new DisplayObjectLine(center, end, 0, e.GetDisplayStyleWithOverride(), e.LineEndA, e.LineEndB)); } + DisplayObjects.Add(new DisplayObjectFan(center, innerRadius, outerRadius, angleMin, angleMax, e.GetDisplayStyleWithOverride())); DrawText(e, null, center.X, center.Z, center.Y); } } - internal void AddRotatedLine(Vector3 tPos, float angle, Element e, float aradius, float hitboxRadius) + internal void AddRotatedLine(Vector3 tPos, float angle, Element e, float aradius, float hitboxRadius, IGameObject go = null) { if (e.includeRotation) { @@ -150,6 +150,7 @@ internal void AddRotatedLine(Vector3 tPos, float angle, Element e, float aradius tPos.Y + e.offY, tPos.Z + e.offZ)); + if(!LayoutUtils.ShouldDraw(start.X, Utils.GetPlayerPositionXZY().X, start.Y, Utils.GetPlayerPositionXZY().Y) && !LayoutUtils.ShouldDraw(stop.X, Utils.GetPlayerPositionXZY().X, stop.Y, Utils.GetPlayerPositionXZY().Y)) return; @@ -189,15 +190,15 @@ internal override void ProcessElement(Element e, Layout i = null, bool forceEnab { var pointPos = Utils.GetPlayerPositionXZY(); DrawCircle(e, pointPos.X, pointPos.Y, pointPos.Z, radius, e.includeRotation ? Svc.ClientState.LocalPlayer.Rotation : 0f, - e.overlayPlaceholders ? Svc.ClientState.LocalPlayer : null); + Svc.ClientState.LocalPlayer); } else if (e.type == 3) { - AddRotatedLine(Utils.GetPlayerPositionXZY(), Svc.ClientState.LocalPlayer.Rotation, e, radius, 0f); + AddRotatedLine(Utils.GetPlayerPositionXZY(), Svc.ClientState.LocalPlayer.Rotation, e, radius, 0f, Svc.ClientState.LocalPlayer); } else if (e.type == 4) { - DrawCone(e, Utils.GetPlayerPositionXZY(), radius, Svc.ClientState.LocalPlayer.Rotation); + DrawCone(e, Utils.GetPlayerPositionXZY(), radius, Svc.ClientState.LocalPlayer.Rotation, Svc.ClientState.LocalPlayer); } } else if (e.refActorType == 2 && Svc.Targets.Target != null @@ -210,19 +211,19 @@ internal override void ProcessElement(Element e, Layout i = null, bool forceEnab { DrawCircle(e, Svc.Targets.Target.GetPositionXZY().X, Svc.Targets.Target.GetPositionXZY().Y, Svc.Targets.Target.GetPositionXZY().Z, radius, e.includeRotation ? Svc.Targets.Target.Rotation : 0f, - e.overlayPlaceholders ? Svc.Targets.Target : null); + Svc.Targets.Target); } else if (e.type == 3) { var angle = e.FaceMe ? (180 - (MathHelper.GetRelativeAngle(Svc.Targets.Target.Position.ToVector2(), Marking.GetPlayer(e.faceplayer).Position.ToVector2()))).DegreesToRadians() : Svc.Targets.Target.Rotation; - AddRotatedLine(Svc.Targets.Target.GetPositionXZY(), angle, e, radius, Svc.Targets.Target.HitboxRadius); + AddRotatedLine(Svc.Targets.Target.GetPositionXZY(), angle, e, radius, Svc.Targets.Target.HitboxRadius, Svc.Targets.Target); } else if (e.type == 4) { var baseAngle = e.FaceMe ? (180 - (MathHelper.GetRelativeAngle(Svc.Targets.Target.Position.ToVector2(), Marking.GetPlayer(e.faceplayer).Position.ToVector2()))).DegreesToRadians() : Svc.Targets.Target.Rotation; - DrawCone(e, Svc.Targets.Target.GetPositionXZY(), radius, baseAngle); + DrawCone(e, Svc.Targets.Target.GetPositionXZY(), radius, baseAngle, Svc.Targets.Target); } } } @@ -242,21 +243,21 @@ internal override void ProcessElement(Element e, Layout i = null, bool forceEnab { DrawCircle(e, a.GetPositionXZY().X, a.GetPositionXZY().Y, a.GetPositionXZY().Z, aradius, e.includeRotation ? a.Rotation : 0f, - e.overlayPlaceholders ? a : null); + a); } else if (e.type == 3) { var angle = e.FaceMe ? (180 - (MathHelper.GetRelativeAngle(a.Position.ToVector2(), Marking.GetPlayer(e.faceplayer).Position.ToVector2()))).DegreesToRadians() : a.Rotation; - AddRotatedLine(a.GetPositionXZY(), angle, e, aradius, a.HitboxRadius); + AddRotatedLine(a.GetPositionXZY(), angle, e, aradius, a.HitboxRadius, a); } else if (e.type == 4) { var baseAngle = e.FaceMe ? (180 - (MathHelper.GetRelativeAngle(a.Position.ToVector2(), Marking.GetPlayer(e.faceplayer).Position.ToVector2()))).DegreesToRadians() : (a.Rotation); - DrawCone(e, a.GetPositionXZY(), aradius, baseAngle); + DrawCone(e, a.GetPositionXZY(), aradius, baseAngle, a); } } } diff --git a/Splatoon/RenderEngines/DirectX11/DirectX11Scene.cs b/Splatoon/RenderEngines/DirectX11/DirectX11Scene.cs index 72647a70..2e7b94aa 100644 --- a/Splatoon/RenderEngines/DirectX11/DirectX11Scene.cs +++ b/Splatoon/RenderEngines/DirectX11/DirectX11Scene.cs @@ -120,24 +120,7 @@ void Draw(PctTexture? texture) { if (element is DisplayObjectFan elementFan) { - if (elementFan.style.filled) - drawList.AddFanFilled( - elementFan.origin, - elementFan.innerRadius, - elementFan.outerRadius, - elementFan.angleMin, - elementFan.angleMax, - elementFan.style.originFillColor, - elementFan.style.endFillColor); - if (elementFan.style.IsStrokeVisible()) - drawList.AddFan( - elementFan.origin, - elementFan.innerRadius, - elementFan.outerRadius, - elementFan.angleMin, - elementFan.angleMax, - elementFan.style.strokeColor, - thickness: elementFan.style.strokeThickness); + DrawFan(elementFan, drawList); } else if (element is DisplayObjectLine elementLine) { @@ -169,51 +152,95 @@ void Draw(PctTexture? texture) return texture; } - public void DrawLine(DisplayObjectLine line, PctDrawList drawList) + public void DrawFan(DisplayObjectFan fan, PctDrawList drawList) { - if (line.radius == 0) + if (fan.style.filled) + drawList.AddFanFilled( + fan.origin, + fan.innerRadius, + fan.outerRadius, + fan.angleMin, + fan.angleMax, + fan.style.originFillColor, + fan.style.endFillColor); + if (fan.style.IsStrokeVisible()) + drawList.AddFan( + fan.origin, + fan.innerRadius, + fan.outerRadius, + fan.angleMin, + fan.angleMax, + fan.style.strokeColor, + thickness: fan.style.strokeThickness); + if (fan.style.castFraction > 0) { - drawList.PathLineTo(line.start); - drawList.PathLineTo(line.stop); - drawList.PathStroke(line.style.strokeColor, PctStrokeFlags.None, line.style.strokeThickness); - - float arrowScale = MathF.Max(1, line.style.strokeThickness / 7f); - if (line.startStyle == LineEnd.Arrow) + if (fan.style.animation.kind is Serializables.CastAnimationKind.Pulse) { - var arrowStart = line.start + arrowScale * 0.4f * line.Direction; - var offset = arrowScale * 0.3f * line.Perpendicular; - drawList.PathLineTo(arrowStart + offset); - drawList.PathLineTo(line.start); - drawList.PathLineTo(arrowStart - offset); - drawList.PathStroke(line.style.strokeColor, PctStrokeFlags.None, line.style.strokeThickness); + var size = fan.style.animation.size + fan.outerRadius - fan.innerRadius; + var pulsePosition = size * (float)((DateTime.Now - DateTime.MinValue).TotalMilliseconds / 1000f % fan.style.animation.frequency) / fan.style.animation.frequency; + drawList.AddFanFilled( + fan.origin, + MathF.Max(fan.innerRadius, fan.innerRadius + pulsePosition - fan.style.animation.size), + MathF.Min(fan.outerRadius, fan.innerRadius + pulsePosition), + fan.angleMin, + fan.angleMax, + fan.style.animation.color & 0x00FFFFFF, + fan.style.animation.color); } - - if (line.endStyle == LineEnd.Arrow) + else if (fan.style.animation.kind is Serializables.CastAnimationKind.Fill) { - var arrowStart = line.stop - arrowScale * 0.4f * line.Direction; - var offset = arrowScale * 0.3f * line.Perpendicular; - drawList.PathLineTo(arrowStart + offset); - drawList.PathLineTo(line.stop); - drawList.PathLineTo(arrowStart - offset); - drawList.PathStroke(line.style.strokeColor, PctStrokeFlags.None, line.style.strokeThickness); + var size = fan.outerRadius - fan.innerRadius; + var castRadius = size * fan.style.castFraction; + drawList.AddFanFilled( + fan.origin, + fan.innerRadius, + fan.innerRadius + castRadius, + fan.angleMin, + fan.angleMax, + fan.style.animation.color, + fan.style.animation.color); } } - else + } + + public void DrawLine(DisplayObjectLine line, PctDrawList drawList) + { + if (line.style.filled) + drawList.AddLineFilled( + line.start, + line.stop, + line.radius, + line.style.originFillColor, + line.style.endFillColor); + if (line.style.IsStrokeVisible()) + drawList.AddLine( + line.start, + line.stop, + line.radius, + line.style.strokeColor); + if (line.style.castFraction > 0) { - if (line.style.filled) + if (line.style.animation.kind is Serializables.CastAnimationKind.Pulse) + { + var length = line.style.animation.size + line.Length; + var pulsePosition = length * (float)((DateTime.Now - DateTime.MinValue).TotalMilliseconds / 1000f % line.style.animation.frequency) / line.style.animation.frequency; drawList.AddLineFilled( - line.start, - line.stop, + line.start + line.Direction * MathF.Max(0, pulsePosition - line.style.animation.size), + line.start + line.Direction * MathF.Min(pulsePosition, line.Length), line.radius, - line.style.originFillColor, - line.style.endFillColor); - if (line.style.IsStrokeVisible()) - drawList.AddLine( + line.style.animation.color & 0x00FFFFFF, + line.style.animation.color); + } + else if (line.style.animation.kind is Serializables.CastAnimationKind.Fill) + { + var castLength = line.style.castFraction * line.Length; + drawList.AddLineFilled( line.start, - line.stop, + line.start + line.Direction * castLength, line.radius, - line.style.strokeColor, - thickness: line.style.strokeThickness); + line.style.animation.color, + line.style.animation.color); + } } } diff --git a/Splatoon/Serializables/CastAnimationKind.cs b/Splatoon/Serializables/CastAnimationKind.cs new file mode 100644 index 00000000..d47f4b4c --- /dev/null +++ b/Splatoon/Serializables/CastAnimationKind.cs @@ -0,0 +1,33 @@ +using ECommons.LanguageHelpers; + +namespace Splatoon.Serializables; + +public enum CastAnimationKind +{ + // These names can be changed. + // These number values are used for serialization and must not be changed. + Unspecified = 0, + Pulse = 1, + ColorShift = 2, + Fill = 3, +} + + +public static class CastAnimations +{ + public static readonly string[] Names = + [ + "Unspecified".Loc(), + "Pulse".Loc(), + "ColorShift".Loc(), + "Fill".Loc(), + ]; + + public static readonly string[] Tooltips = + [ + "The default type for new elements. No cast animation is specified.".Loc(), + "Pulse with some frequency. This looks similar to the game's default VFX.".Loc(), + "Change the element's color based on the cast progress.".Loc(), + "Fill the element from start to end based on the cast progress.".Loc(), + ]; +} diff --git a/Splatoon/Serializables/DisplayStyle.cs b/Splatoon/Serializables/DisplayStyle.cs index 4ff20e03..585ce368 100644 --- a/Splatoon/Serializables/DisplayStyle.cs +++ b/Splatoon/Serializables/DisplayStyle.cs @@ -1,20 +1,31 @@ -namespace Splatoon.Serializables +namespace Splatoon.Serializables; + +public struct DisplayStyle( + uint strokeColor, + float strokeThickness, + float fillIntensity, + uint originFillColor, + uint endFillColor, + bool filled = true, + bool overrideFillColor = false, + float castFraction = 0, + AnimationStyle animation = default) { - public struct DisplayStyle( - uint strokeColor, - float strokeThickness, - float fillIntensity, - uint originFillColor, - uint endFillColor, - bool filled = true, - bool overrideFillColor = false) - { - public uint strokeColor = strokeColor; - public float strokeThickness = strokeThickness; - public float fillIntensity = fillIntensity; - public uint originFillColor = originFillColor; - public uint endFillColor = endFillColor; - public bool filled = filled; - public bool overrideFillColor = overrideFillColor; - } + public uint strokeColor = strokeColor; + public float strokeThickness = strokeThickness; + public float fillIntensity = fillIntensity; + public uint originFillColor = originFillColor; + public uint endFillColor = endFillColor; + public bool filled = filled; + public bool overrideFillColor = overrideFillColor; + public float castFraction = castFraction; + public AnimationStyle animation = animation; +} + +public struct AnimationStyle(CastAnimationKind kind, uint color, float size, float frequency) +{ + public CastAnimationKind kind = kind; + public uint color = color; + public float size = size; + public float frequency = frequency; } diff --git a/Splatoon/Serializables/Element.cs b/Splatoon/Serializables/Element.cs index 9f0548cb..fd342b0b 100644 --- a/Splatoon/Serializables/Element.cs +++ b/Splatoon/Serializables/Element.cs @@ -1,9 +1,7 @@ using ECommons.LanguageHelpers; using Splatoon.RenderEngines; using Splatoon.Serializables; -using Splatoon.Utility; using System.ComponentModel; -using System.Runtime.Serialization; namespace Splatoon; @@ -87,6 +85,10 @@ public Element(int t) [DefaultValue(null)] public uint? endFillColor = null; [DefaultValue(0x70000000)] public uint overlayBGColor = 0x70000000; [DefaultValue(0xC8FFFFFF)] public uint overlayTextColor = 0xC8FFFFFF; + [DefaultValue(CastAnimationKind.Unspecified)] public CastAnimationKind castAnimation = CastAnimationKind.Unspecified; + [DefaultValue(0xc80000ff)] public uint animationColor = 0xc80000ff; + [DefaultValue(0.5f)] public float pulseSize = 0.5f; + [DefaultValue(1.5f)] public float pulseFrequency = 1.5f; [DefaultValue(0f)] public float overlayVOffset = 0f; [DefaultValue(1f)] public float overlayFScale = 1f; [DefaultValue(false)] public bool overlayPlaceholders = false; @@ -346,6 +348,35 @@ public bool ShouldSerializeDonut() { return type.EqualsAny(0, 1, 2, 3) && Donut > 0; } + public bool ShouldSerializeoverrideFillColor() + { + return Filled && overrideFillColor; + } + public bool ShouldSerializeoriginFillColor() + { + return ShouldSerializeoverrideFillColor(); + } + public bool ShouldSerializeendFillColor() + { + return ShouldSerializeoverrideFillColor(); + } + public bool ShouldSerializecastAnimation() + { + return refActorRequireCast && castAnimation is not CastAnimationKind.Unspecified; + } + public bool ShouldSerializeanimationColor() + { + return ShouldSerializecastAnimation(); + } + public bool ShouldSerializepulseSize() + { + return ShouldSerializecastAnimation() && castAnimation is CastAnimationKind.Pulse; + } + public bool ShouldSerializepulseFrequency() + { + return ShouldSerializecastAnimation() && castAnimation is CastAnimationKind.Pulse; + } public bool ShouldSerializerefActorTetherConnectedWithPlayer() => refActorTether; + } diff --git a/Splatoon/Splatoon.csproj b/Splatoon/Splatoon.csproj index 9c48fa6f..df27de53 100644 --- a/Splatoon/Splatoon.csproj +++ b/Splatoon/Splatoon.csproj @@ -2,7 +2,7 @@ NightmareXIV - 3.6.1.0 + 3.7.0.1 diff --git a/Splatoon/Utility/Colors.cs b/Splatoon/Utility/Colors.cs index 0601a77d..e2a414c5 100644 --- a/Splatoon/Utility/Colors.cs +++ b/Splatoon/Utility/Colors.cs @@ -18,4 +18,12 @@ public static uint MultiplyAlpha(uint color, float amount) alpha = Math.Clamp(alpha, 0x00, 0xFF); return color & 0x00FFFFFF | (alpha << 24); } + + // Linear interpolation between 1-byte components of uint32 + // Intended for interpolating colors + public static uint Lerp(uint v1, uint v2, float amount) + { + if (v1 == v2) return v1; + return Vector4.Lerp(v1.ToVector4(), v2.ToVector4(), amount).ToUint(); + } } diff --git a/Splatoon/Utility/ElementExtensions.cs b/Splatoon/Utility/ElementExtensions.cs index 931ec0d3..00339a7c 100644 --- a/Splatoon/Utility/ElementExtensions.cs +++ b/Splatoon/Utility/ElementExtensions.cs @@ -1,4 +1,5 @@ -using Splatoon.Serializables; +using Splatoon.RenderEngines; +using Splatoon.Serializables; namespace Splatoon.Utility; public static class ElementExtensions @@ -62,11 +63,11 @@ public static DisplayStyle GetDisplayStyle(this Element e) uint originFillColor = e.originFillColor ?? Colors.MultiplyAlpha(e.color, fillIntensity); uint endFillColor = e.endFillColor ?? Colors.MultiplyAlpha(e.color, fillIntensity); - return new DisplayStyle(e.color, e.thicc, fillIntensity, originFillColor, endFillColor, e.Filled, e.overrideFillColor); + return new DisplayStyle(e.color, e.thicc, fillIntensity, originFillColor, endFillColor, e.Filled, e.overrideFillColor, 0, e.GetAnimationStyle()); } - public static DisplayStyle GetDisplayStyleWithOverride(this Element e) + public static DisplayStyle GetDisplayStyleWithOverride(this Element e, IGameObject go = null) { DisplayStyle style = e.GetDisplayStyle(); @@ -84,9 +85,18 @@ public static DisplayStyle GetDisplayStyleWithOverride(this Element e) style.originFillColor = defaultColor; style.endFillColor = defaultColor; } - - style.originFillColor = P.Config.ClampFillColorAlpha(style.originFillColor); - style.endFillColor = P.Config.ClampFillColorAlpha(style.endFillColor); + style.animation = e.GetAnimationStyle(); + style.castFraction = e.refActorRequireCast ? LayoutUtils.CastFraction(e, go) : 0f; + if (style.animation.kind is CastAnimationKind.ColorShift) + { + style.originFillColor = P.Config.ClampFillColorAlpha(Colors.Lerp(style.originFillColor, style.animation.color, style.castFraction)); + style.endFillColor = P.Config.ClampFillColorAlpha(Colors.Lerp(style.endFillColor, style.animation.color, style.castFraction)); + } + else + { + style.originFillColor = P.Config.ClampFillColorAlpha(style.originFillColor); + style.endFillColor = P.Config.ClampFillColorAlpha(style.endFillColor); + } return style; } @@ -99,4 +109,37 @@ public static bool IsDangerous(this Element e) { return e.mechanicType == MechanicType.Danger; } + + public static AnimationStyle GetAnimationStyle(this Element e) + { + return new(e.castAnimation, e.animationColor, e.pulseSize, e.pulseFrequency); + } + + public static float EffectiveLength(this Element e) + { + if (e.type.EqualsAny(0, 1)) + { + if (e.Donut > 0) + return e.Donut; + return e.radius; + } + if (e.type.EqualsAny(2, 3)) + { + return (new Vector3(e.refX, e.refY, e.refZ) - new Vector3(e.offX, e.offY, e.offZ)).Length(); + } + if (e.type.EqualsAny(4, 5)) + { + return e.radius; + } + return 0; + } + + public static RenderEngineKind ConfiguredRenderEngineKind(this Element e) + { + if (e.RenderEngineKind != RenderEngineKind.Unspecified) + return e.RenderEngineKind; + if (P.Config.RenderEngineKind != RenderEngineKind.Unspecified) + return P.Config.RenderEngineKind; + return RenderEngineKind.DirectX11; + } } diff --git a/Splatoon/Utility/LayoutUtils.cs b/Splatoon/Utility/LayoutUtils.cs index 03056b5f..ec4258d3 100644 --- a/Splatoon/Utility/LayoutUtils.cs +++ b/Splatoon/Utility/LayoutUtils.cs @@ -206,6 +206,35 @@ public static bool IsCastingMatches(Element e, IBattleChara chr) } } + public static float CastFraction(Element e, IGameObject go) + { + if (go is IBattleChara chr) + { + float castTime = -1; + float totalCastTime = 1; + if (chr.IsCasting(e.refActorCastId)) + { + castTime = chr.CurrentCastTime; + totalCastTime = chr.TotalCastTime; + } + else if (!(e.refActorUseOvercast && AttachedInfo.TryGetCastTime(chr.Address, e.refActorCastId, out castTime))) + { + return 0; + } + + if (e.refActorUseCastTime) + { + castTime -= e.refActorCastTimeMin; + totalCastTime = e.refActorCastTimeMax - e.refActorCastTimeMin; + } + if (castTime <= 0 || totalCastTime <= 0) return 0; + if (castTime > totalCastTime) return 1; + + return castTime / totalCastTime; + } + return 0; + } + public static bool CheckEffect(Element e, IBattleChara c) { if (e.refActorRequireAllBuffs) diff --git a/SplatoonScripts/update.csv b/SplatoonScripts/update.csv index 6a0c32f2..e69de29b 100644 --- a/SplatoonScripts/update.csv +++ b/SplatoonScripts/update.csv @@ -1,56 +0,0 @@ -SplatoonScriptsOfficial.Generic@ZoneNameToast,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/ZoneNameToast.cs -SplatoonScriptsOfficial.Generic@ActReminder,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/ActReminder.cs -SplatoonScriptsOfficial.Generic@AutoFateSync,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/AutoFateSync.cs -SplatoonScriptsOfficial.Generic@ShowEmote,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/ShowEmote.cs -SplatoonScriptsOfficial.Generic@PluginInstallerWindowCollapsible,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/PluginInstallerWindowCollapsible.cs -SplatoonScriptsOfficial.Generic@ShowTooltipOnKey,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/ShowTooltipOnKey.cs -SplatoonScriptsOfficial.Generic@QuestHighlighter,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/QuestHighlighter.cs -SplatoonScriptsOfficial.Generic@CastExplorer,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Generic/CastExplorer.cs -SplatoonScriptsOfficial.Tests@DMParser,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Tests/DMParser.cs -SplatoonScriptsOfficial.Duties.Endwalker@P9S_Dualspell_InOut,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P9S Dualspell InOut.cs -SplatoonScriptsOfficial.Duties.Endwalker@P8S2_Dancer_HC_Step,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P8S2 Dancer HC Step.cs -SplatoonScriptsOfficial.Duties.Endwalker@DSR_Wrath,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/DSR Wrath.cs -SplatoonScriptsOfficial.Duties.Endwalker@P12S_Wing_Cleaves,6,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P12S Wing Cleaves.cs -SplatoonScriptsOfficial.Duties.Endwalker@P12S_Pangenesis,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P12S Pangenesis.cs -SplatoonScriptsOfficial.Duties.Endwalker@DSR_Towers,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/DSR Towers.cs -SplatoonScriptsOfficial.Duties.Endwalker@P9S_JP_LC_Strat,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P9S JP LC Strat.cs -SplatoonScriptsOfficial.Duties.Endwalker@P12S_Caloric_Theory,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P12S Caloric Theory.cs -SplatoonScriptsOfficial.Duties.Endwalker@P10S_Tethers,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P10S Tethers.cs -SplatoonScriptsOfficial.Duties.Endwalker@P11S_Multiscript,4,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P11S Multiscript.cs -SplatoonScriptsOfficial.Duties.Endwalker@P10S_Debuffs,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P10S Debuffs.cs -SplatoonScriptsOfficial.Duties.Endwalker@P8S2_Dominion,8,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P8S2 Dominion.cs -SplatoonScriptsOfficial.Duties.Endwalker@P12S_Classical_Concepts,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P12S Classical Concepts.cs -SplatoonScriptsOfficial.Duties.Endwalker@Aloalo_Bombs,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/Aloalo Bombs.cs -SplatoonScriptsOfficial.Duties.Endwalker@P12S_Tethers,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P12S Tethers.cs -SplatoonScriptsOfficial.Duties.Endwalker@P8S2_Limitless_Desolation,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P8S2 Limitless Desolation.cs -SplatoonScriptsOfficial.Duties.Endwalker@P12S_Limit_Cut,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P12S Limit Cut.cs -SplatoonScriptsOfficial.Duties.Endwalker@DSR_P6_Cauterize_Unsafe,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/DSR_P6_Cauterize_Unsafe.cs -SplatoonScriptsOfficial.Duties.Endwalker@P12S_Superchain,7,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/P12S Superchain.cs -SplatoonScriptsOfficial.Duties.Endwalker@DSR_Dooms,5,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/DSR Dooms.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@MF_Target_Enforcer,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/MF Target Enforcer.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Party_Synergy,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Party Synergy.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Limitless_Synergy,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Limitless Synergy.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Dynamis_Sigma,7,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Dynamis Sigma.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Oversampled_Wave_Cannon,5,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Oversampled Wave Cannon.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Hello_Near_Far_World,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Hello Near Far World.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Pantokrator,4,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Pantokrator.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Dynamis_Delta,9,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Dynamis Delta.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Exasquares,5,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Exasquares.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Beyond_Defense,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Beyond Defense.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Hello_World,9,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Hello World.cs -SplatoonScriptsOfficial.Duties.Endwalker.The_Omega_Protocol@Program_Loop,4,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Endwalker/The Omega Protocol/Program Loop.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R1S_Raining_Cats,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R1S Raining Cats.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R2S_Venom_Love_Pair_Split,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R2S Venom Love Pair Split.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R4S_Chain_Lightning,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R4S Chain Lightning.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R1S_Multiscript,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R1S Multiscript.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R1S_Protean_Highlight,1,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R1S Protean Highlight.cs -SplatoonScriptsOfficial.Duties.Dawntrail@EX2_Projection_of_Triumph,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/EX2 Projection of Triumph.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R4S_Unsafe_Cannon,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R4S Unsafe Cannon.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R4S_Electrope_Edge,5,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R4S Electrope Edge.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R4S_Witch_Hunt,4,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R4S Witch Hunt.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R4S_Midnight_Sabbath,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R4S Midnight Sabbath.cs -SplatoonScriptsOfficial.Duties.Dawntrail@R4S_Sunrise_Sabbath,5,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Dawntrail/R4S Sunrise Sabbath.cs -SplatoonScriptsOfficial.Duties.Stormblood@UCOB_Heavensfall_Trio_Towers,6,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Stormblood/UCOB Heavensfall Trio Towers.cs -SplatoonScriptsOfficial.Duties.Stormblood@UCOB_dragon_baits,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Stormblood/UCOB dragon baits.cs -SplatoonScriptsOfficial.Duties.Stormblood@UCOB_Tethers,3,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Stormblood/UCOB Tethers.cs -SplatoonScriptsOfficial.Duties.Shadowbringers@TEA_P2_Transition,2,https://github.com/PunishXIV/Splatoon/raw/main/SplatoonScripts/Duties/Shadowbringers/TEA_P2_Transition.cs \ No newline at end of file