From 8064349e740e89c0423335b6e3f6fe107d973849 Mon Sep 17 00:00:00 2001 From: RedAsteroid <123588653+RedAsteroid@users.noreply.github.com> Date: Sat, 29 Jun 2024 01:39:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=20=E5=89=A9=E4=BD=99?= =?UTF-8?q?=E7=9A=84=E9=9B=B6=E5=BC=8F=E8=84=9A=E6=9C=AC=20P10S=20Tether?= =?UTF-8?q?=20=E6=89=87=E5=BD=A2=E8=BF=9E=E7=BA=BF=20P12S=20Caloric=20Theo?= =?UTF-8?q?ry=20=E7=83=AD=E8=B4=A8=E8=AF=B4=20P12S=20Classical=20Concepts?= =?UTF-8?q?=20=E5=85=83=E7=B4=A0=E7=90=86=E5=BF=B5=20P12S=20Pangenesis=20?= =?UTF-8?q?=E6=B3=9B=E7=94=9F=E8=AE=BA(=E6=96=B0=E5=A2=9E=E8=8F=93?= =?UTF-8?q?=E5=AD=90=E6=89=93=E6=B3=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Endwalker/P10S Tethers 扇形连线.cs | 143 +++++ src/Endwalker/P12S Caloric Theory 热质说.cs | 258 +++++++++ .../P12S Classical Concepts 元素理念.cs | 263 ++++++++++ src/Endwalker/P12S Pangenesis 泛生论.cs | 488 ++++++++++++++++++ 4 files changed, 1152 insertions(+) create mode 100644 src/Endwalker/P10S Tethers 扇形连线.cs create mode 100644 src/Endwalker/P12S Caloric Theory 热质说.cs create mode 100644 src/Endwalker/P12S Classical Concepts 元素理念.cs create mode 100644 src/Endwalker/P12S Pangenesis 泛生论.cs diff --git a/src/Endwalker/P10S Tethers 扇形连线.cs b/src/Endwalker/P10S Tethers 扇形连线.cs new file mode 100644 index 0000000..cfbcf92 --- /dev/null +++ b/src/Endwalker/P10S Tethers 扇形连线.cs @@ -0,0 +1,143 @@ +using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.ClientState.Objects.Types; +using ECommons; +using ECommons.Configuration; +using ECommons.GameHelpers; +using ECommons.Hooks; +using ECommons.ImGuiMethods; +using ECommons.Logging; +using ECommons.MathHelpers; +using ImGuiNET; +using Splatoon.SplatoonScripting; +using Splatoon.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace SplatoonScriptsOfficial.Duties.Endwalker +{ + public class P10S_Tethers_ : SplatoonScript + { + public override HashSet ValidTerritories => new() { 1150 }; + public override Metadata? Metadata => new(2, "NightmareXIV, RedAsteroid ޸"); + List Tethers = new(); + + public class TetherData + { + public uint source; + public uint target; + public long time = Environment.TickCount64; + public float Age => (float)(Environment.TickCount64 - time) / 1000f; + } + + public override void OnSetup() + { + var code = "{\"Name\":\"\",\"type\":5,\"refX\":103.03228,\"refY\":99.94743,\"radius\":20.0,\"coneAngleMin\":-61,\"coneAngleMax\":61,\"color\":3355506687,\"FillStep\":2.0,\"includeRotation\":true,\"AdditionalRotation\":3.1415927,\"Filled\":true}"; + Controller.RegisterElementFromCode("Cone1", code); + Controller.RegisterElementFromCode("Cone2", code); + Controller.RegisterElementFromCode("Tether", "{\"Name\":\"\",\"Enabled\":false,\"radius\":0.0,\"thicc\":5.0,\"tether\":true}"); + } + + public override void OnEnable() + { + ActionEffect.ActionEffectEvent += ActionEffect_ActionEffectEvent; + Off(); + } + + private void ActionEffect_ActionEffectEvent(ECommons.Hooks.ActionEffectTypes.ActionEffectSet set) + { + if (set.Action.RowId == 33432) + { + Off(); + } + } + + public override void OnDisable() + { + ActionEffect.ActionEffectEvent -= ActionEffect_ActionEffectEvent; + Off(); + } + + public override void OnTetherCreate(uint source, uint target, uint data2, uint data3, uint data5) + { + Tethers.Add(new() { source = source, target = target }); + Tethers.RemoveAll(x => x.Age > 30f); + } + + void Off() + { + Tethers.Clear(); + Controller.GetRegisteredElements().Each(x => x.Value.Enabled = false); + } + + public override void OnDirectorUpdate(DirectorUpdateCategory category) + { + if (category.EqualsAny(DirectorUpdateCategory.Commence, DirectorUpdateCategory.Recommence, DirectorUpdateCategory.Wipe)) + { + Off(); + } + } + + public override void OnSettingsDraw() + { + ImGui.ColorEdit4(" ɫ", ref C.ColorSelf, ImGuiColorEditFlags.NoInputs); // Self color + ImGui.Checkbox("ʾԼ", ref C.TetherSelf); // Highlight own tether + ImGui.ColorEdit4(" ɫ", ref C.Color, ImGuiColorEditFlags.NoInputs); // Other player color + ImGui.SetNextItemWidth(150f); + ImGui.SliderFloat("ϸ", ref C.Thick, 1f, 10f); // Cone line thickness + ImGui.SetNextItemWidth(150f); + ImGui.SliderFloat("䲽", ref C.Interval, 1f, 20f); // Cone fill step + ImGui.SetNextItemWidth(150f); + ImGui.SliderFloat("", ref C.radius, 5f, 40f); // Cone length + if (ImGui.CollapsingHeader("debug")) + { + foreach (var x in Tethers) + { + ImGuiEx.Text($"{x.source.GetObject()}->{x.target.GetObject()}, {x.Age}s"); + } + } + } + + public override void OnUpdate() + { + int num = 1; + foreach (var x in Tethers) + { + if (x.source.TryGetObject(out var pillar) && pillar is BattleChara p && p.NameId == 12354 && x.target.TryGetObject(out var player) && player is PlayerCharacter pc && Controller.TryGetElementByName($"Cone{num}", out var e)) + { + num++; + e.Enabled = true; + e.AdditionalRotation = (180 + MathHelper.GetRelativeAngle(p.Position, pc.Position)).DegreesToRadians(); + e.SetRefPosition(p.Position); + e.color = C.Color.ToUint(); + e.thicc = C.Thick; + e.FillStep = C.Interval; + e.radius = C.radius; + if (pc.Address == Player.Object.Address) + { + e.color = C.ColorSelf.ToUint(); + if (C.TetherSelf && Controller.TryGetElementByName("Tether", out var t)) + { + t.Enabled = true; + t.SetRefPosition(p.Position); + } + } + } + } + } + + Config C => Controller.GetConfig(); + public class Config : IEzConfig + { + public Vector4 Color = 0xFFF700C8.SwapBytes().ToVector4(); + public Vector4 ColorSelf = 0xFFAD00C8.SwapBytes().ToVector4(); + public float Thick = 4f; + public float Interval = 10f; + public bool TetherSelf = true; + public float radius = 10f; + } + } +} \ No newline at end of file diff --git a/src/Endwalker/P12S Caloric Theory 热质说.cs b/src/Endwalker/P12S Caloric Theory 热质说.cs new file mode 100644 index 0000000..12f71e9 --- /dev/null +++ b/src/Endwalker/P12S Caloric Theory 热质说.cs @@ -0,0 +1,258 @@ +using Dalamud.Interface.Colors; +using ECommons; +using ECommons.Configuration; +using ECommons.DalamudServices; +using ECommons.GameFunctions; +using ECommons.Hooks; +using ECommons.MathHelpers; +using ECommons.Schedulers; +using Splatoon; +using ImGuiNET; +using Splatoon.SplatoonScripting; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using PluginLog = ECommons.Logging.PluginLog; + +namespace SplatoonScriptsOfficial.Duties.Endwalker +{ + public class P12S_Caloric_Theory_热质说 : SplatoonScript + { + public override HashSet ValidTerritories => new() { 1154 }; + public override Metadata? Metadata => new(1, "tatad2, RedAsteroid 修改"); + + private string ElementNamePrefix = "P12SCaloricTheory123"; + + private int closeCaloricStatusId = 3589; + private int spreadStatusId = 3591; // atmosfaction + private int stackStatusId = 3590; // entropifaction + + private bool lastHasBuff = false; + + // the distance player can move in one layer of close caloric buff. + // may not very accurate. 9.2 meters has been tested to be safe and 9.4 meters are unsafe, but the data may affected by server latency. + private float maxDistancePerBuff = 9.2f; + + // change the color of Indicator when the remaining distance is less than this value. + // better stop moving when the color is changed. + private float changeColorDistance = 0.5f; + + private float spreadRadius = 7.0f; + private float stackRadius = 4.0f; + private float distancePassed = 0; + + private Vector2 lastPosition; + private int caloricTheoryCount = 0; + + private Element? Indicator1; + private Element? Indicator2; + HashSet StackSpreadRecord = new HashSet(); + + List Sch = new List(); + + private bool debug = false; + Dictionary distanceDebug = new Dictionary(); + Dictionary positionDebug = new Dictionary(); + + private void AddStackSpreadElement(uint objectId, bool isStack) + { + // {"Name":"","type":1,"Enabled":false,"radius":5.0,"refActorObjectID":291,"refActorComparisonType":2} + + StackSpreadRecord.Add(objectId); + Element e = new Element(1); + e.refActorObjectID = objectId; + e.refActorComparisonType = 2; + e.radius = isStack ? stackRadius : spreadRadius; + e.color = isStack ? ImGuiColors.DPSRed.ToUint() : ImGuiColors.TankBlue.ToUint(); + Controller.RegisterElement(ElementNamePrefix + objectId.ToString(), e, true); + } + + private void ClearStackSpreadElements() + { + foreach(uint objectId in StackSpreadRecord) + Controller.TryUnregisterElement(ElementNamePrefix + objectId.ToString()); + StackSpreadRecord.Clear(); + } + + private void Reset() + { + PluginLog.Debug("caloric theory RESET"); + Sch.Each(x => x.Dispose()); + Indicator1.Enabled = false; + Indicator2.Enabled = false; + lastHasBuff = false; + caloricTheoryCount = 0; + ClearStackSpreadElements(); + } + + public override void OnEnable() + { + Reset(); + } + + public override void OnSetup() + { + // {"Name":"","type":1,"radius":5.0,"refActorType":1} + + Element e1 = new Element(1); + e1.refActorType = 1; + e1.Enabled = false; + Controller.RegisterElement(ElementNamePrefix + "Indicator1", e1, true); + Indicator1 = Controller.GetElementByName(ElementNamePrefix + "Indicator1"); + + + Element e2 = new Element(1); + e2.refActorType = 1; + e2.Enabled = false; + Controller.RegisterElement(ElementNamePrefix + "Indicator2", e2, true); + Indicator2 = Controller.GetElementByName(ElementNamePrefix + "Indicator2"); + } + + public override void OnMessage(string Message) + { + } + + public override void OnDirectorUpdate(DirectorUpdateCategory category) + { + if (category == DirectorUpdateCategory.Commence || category == DirectorUpdateCategory.Recommence || category == DirectorUpdateCategory.Wipe) + Reset(); + } + + private void Init(bool isPhaseTwo) + { + Indicator1.radius = maxDistancePerBuff; + Indicator2.radius = maxDistancePerBuff * 2; + Indicator1.Enabled = true; + Indicator2.Enabled = isPhaseTwo; + Indicator1.color = ImGuiColors.HealerGreen.ToUint(); + Indicator2.color = ImGuiColors.HealerGreen.ToUint(); + distancePassed = 0; + //lastPosition = FakeParty.Get().First(x => x.ObjectId == 0x1017913F).Position.ToVector2(); + lastPosition = Svc.ClientState.LocalPlayer.Position.ToVector2(); + + if (debug) + { + foreach (var player in FakeParty.Get()) + { + distanceDebug[player.ObjectId] = 0; + positionDebug[player.ObjectId] = player.Position.ToVector2(); + } + } + } + + public override void OnUpdate() + { + bool hasBuff = Svc.ClientState.LocalPlayer.StatusList.Any(x => x.StatusId == closeCaloricStatusId); + if (hasBuff) + { + if (!lastHasBuff) + { + caloricTheoryCount++; + Init(caloricTheoryCount >= 2); + } + else + { + //Vector2 Position = FakeParty.Get().First(x => x.ObjectId == 0x1017913F).Position.ToVector2(); + Vector2 Position = Svc.ClientState.LocalPlayer.Position.ToVector2(); + float distance = Vector2.Distance(Position, lastPosition); + //PluginLog.Information($"pos:{Position}, lastPos:{lastPosition}, dis: {distance}"); + lastPosition = Position; + distancePassed += distance; + Indicator1.radius -= distance; + Indicator2.radius -= distance; + if (distancePassed >= maxDistancePerBuff - changeColorDistance) + Indicator1.color = ImGuiColors.DalamudRed.ToUint(); + if (distancePassed >= maxDistancePerBuff * 2 - changeColorDistance) + Indicator2.color = ImGuiColors.DalamudRed.ToUint(); + + if(debug) + { + foreach (var player in FakeParty.Get()) + { + Position = player.Position.ToVector2(); + distance = Vector2.Distance(Position, positionDebug[player.ObjectId]); + positionDebug[player.ObjectId] = Position; + distanceDebug[player.ObjectId] += distance; + } + } + } + lastHasBuff = hasBuff; + + if (Conf.StakcSpreadShowTime > 0 && Conf.StakcSpreadShowTime < 7) + { + if (Conf.DrawStack) + { + // display stack/spread range + var stackers = FakeParty.Get().Where(x => x.StatusList.Any(x => x.StatusId == stackStatusId && x.RemainingTime <= Conf.StakcSpreadShowTime)); + foreach (var stacker in stackers) + { + uint objectId = stacker.ObjectId; + if (StackSpreadRecord.Contains(objectId)) continue; + AddStackSpreadElement(objectId, true); + if (StackSpreadRecord.Count == 1) + Sch.Add(new TickScheduler(ClearStackSpreadElements, Conf.StakcSpreadShowTime * 1000)); + } + } + + var spreaders = FakeParty.Get().Where(x => x.StatusList.Any(x => x.StatusId == spreadStatusId && x.RemainingTime <= Conf.StakcSpreadShowTime)); + + if (Conf.DrawSpread) + { + foreach (var spreader in spreaders) + { + uint objectId = spreader.ObjectId; + if (StackSpreadRecord.Contains(objectId)) continue; + AddStackSpreadElement(objectId, false); + if (StackSpreadRecord.Count == 1) + Sch.Add(new TickScheduler(ClearStackSpreadElements, Conf.StakcSpreadShowTime * 1000)); + } + } + } + } + + if (!hasBuff && lastHasBuff) + { + lastHasBuff = false; + Indicator1.Enabled = false; + Indicator2.Enabled = false; + ClearStackSpreadElements(); + } + } + public class Config : IEzConfig + { + public int StakcSpreadShowTime = 2; + public bool DrawStack = false; + public bool DrawSpread = false; + } + + Config Conf => Controller.GetConfig(); + public override void OnSettingsDraw() + { + ImGui.InputInt("显示分摊/分散 AoE 范围(单位:秒,最长6秒)", ref Conf.StakcSpreadShowTime); // the time to show stack/spread aoe(seconds, max=6) + ImGui.Checkbox("启用 分摊绘制", ref Conf.DrawStack); + ImGui.Checkbox("启用 分散绘制", ref Conf.DrawSpread); + ImGui.Text("预设已有分散分摊绘制,可以不启用脚本的分散分摊绘制。"); + ImGui.Text("随移动缩小的绿色圆形线为移动距离提醒,存在误差请不要卡极限距离移动。"); + + + if (ImGui.CollapsingHeader("Debug")) + { + ImGui.Checkbox("debug", ref debug); + ImGui.Text($"Position: {lastPosition}, distance: {distancePassed}"); + ImGui.Text($"hasBuff: {lastHasBuff}"); + ImGui.Text($"StackSpread buff count: {StackSpreadRecord.Count()}"); + + if (debug) + { + foreach (var player in FakeParty.Get()) + { + if(distanceDebug.ContainsKey(player.ObjectId)) + { + ImGui.Text($"{player.Name}, dis: {distanceDebug[player.ObjectId]}, pos: {player.Position}"); + } + } + } + } + } + } +} diff --git a/src/Endwalker/P12S Classical Concepts 元素理念.cs b/src/Endwalker/P12S Classical Concepts 元素理念.cs new file mode 100644 index 0000000..244b038 --- /dev/null +++ b/src/Endwalker/P12S Classical Concepts 元素理念.cs @@ -0,0 +1,263 @@ +using ECommons; +using ECommons.MathHelpers; +using ECommons.DalamudServices; +using ECommons.Logging; +using Splatoon.SplatoonScripting; +using Splatoon; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Dalamud.Game.ClientState.Objects.Types; +using ECommons.Hooks; +using ECommons.Schedulers; +using Dalamud.Interface.Colors; +using ECommons.GameFunctions; +using ECommons.Configuration; +using ECommons.ImGuiMethods; +using ImGuiNET; + +namespace SplatoonScriptsOfficial.Duties.Endwalker +{ + public class P12S_Classical_Concepts_元素理念 : SplatoonScript + { + public override HashSet ValidTerritories => new() { 1154 }; + public override Metadata? Metadata => new(5, "tatad2"); + + private string ElementNamePrefix = "P12SSC"; + + private int cubeCount = 0; + private int[,] cube = new int[4, 3]; + + bool isBlinking = false; + + List Schedulers = new(); + + private void Reset() + { + Hide(); + Schedulers.Each(x => x.Dispose()); + PluginLog.Debug("classical concepts RESET"); + cubeCount = 0; + } + + void Hide() + { + Controller.ClearRegisteredElements(); + isBlinking = false; + } + + public override void OnEnable() + { + Reset(); + } + + public override void OnUpdate() + { + if(Svc.ClientState.LocalPlayer.StatusList.Any(x => x.StatusId == 3588 && x.RemainingTime < 1f)) + { + Hide(); + } + if (isBlinking) + { + foreach(var e in Controller.GetRegisteredElements()) + { + if (e.Key.StartsWith("Red")) + { + e.Value.color = (GradientColor.Get(ImGuiColors.DalamudRed, ImGuiColors.DalamudRed / 2, 333) with { W = Conf.Trans }).ToUint(); + } + if (e.Key.StartsWith("Yellow")) + { + e.Value.color = (GradientColor.Get(ImGuiColors.DalamudYellow, ImGuiColors.DalamudYellow / 2, 333) with { W = Conf.Trans }).ToUint(); + } + } + } + } + + public override void OnMessage(string Message) + { + if (Message.EqualsAny(">33574)")) + { + Reset(); + } + } + + public override void OnDirectorUpdate(DirectorUpdateCategory category) + { + if (category == DirectorUpdateCategory.Commence || category == DirectorUpdateCategory.Recommence || category == DirectorUpdateCategory.Wipe) + Reset(); + } + + + List<(int, int)> bias = new List<(int, int)> { (1, 0), (-1, 0), (0, 1), (0, -1) }; + private void DrawLines(bool swap) + { + PluginLog.Debug($"swap: {swap}"); + if (swap) + { + for(int x = 0; x < 4; x ++) + { + (cube[x, 0], cube[3-x, 2]) = (cube[3-x, 2], cube[x, 0]); + if (x < 2) + (cube[x, 1], cube[3 - x, 1]) = (cube[3 - x, 1], cube[x, 1]); + } + } + + for (int y = 0; y < 3; y++) + PluginLog.Debug($"{cube[0, y]}, {cube[1, y]}, {cube[2, y]}, {cube[3, y]}"); + for (int x = 0; x < 4; x++) + for (int y = 0; y < 3; y++) + { + if (cube[x, y] != 2) continue; + // blue + List<(int, int)> Red = new List<(int, int)>(); + List<(int, int)> Yellow = new List<(int, int)>(); + + foreach((int, int) b in bias) + { + int xx = x + b.Item1; + int yy = y + b.Item2; + if (xx < 0 || xx > 3 || yy < 0 || yy > 2) continue; + if (cube[xx, yy] == 1) Red.Add((xx, yy)); + if (cube[xx, yy] == 3) Yellow.Add((xx, yy)); + } + + PluginLog.Debug($"(x, y): {x}, {y} redcount:{Red.Count}, yellowcount:{Yellow.Count}"); + + if (Red.Count == 1) + DrawLine(x, y, Red[0].Item1, Red[0].Item2, true); + else + { + int blueCount = 0; + foreach ((int, int) b in bias) + { + int xx = Red[0].Item1 + b.Item1; + int yy = Red[0].Item2 + b.Item2; + if (xx < 0 || xx > 3 || yy < 0 || yy > 2) continue; + if (cube[xx, yy] == 2) blueCount++; + } + int index = blueCount == 2 ? 1 : 0; + DrawLine(x, y, Red[index].Item1, Red[index].Item2, true); + } + if (Yellow.Count == 1) + DrawLine(x, y, Yellow[0].Item1, Yellow[0].Item2, false); + else + { + int blueCount = 0; + foreach ((int, int) b in bias) + { + int xx = Yellow[0].Item1 + b.Item1; + int yy = Yellow[0].Item2 + b.Item2; + if (xx < 0 || xx > 3 || yy < 0 || yy > 2) continue; + if (cube[xx, yy] == 2) blueCount++; + } + int index = blueCount == 2 ? 1 : 0; + DrawLine(x, y, Yellow[index].Item1, Yellow[index].Item2, false); + } + } + } + + private void DrawLine(int x1, int y1, int x2, int y2, bool isRed) + { + //{"Name":"","type":2,"refX":88.0,"refY":92.0,"offX":96.0,"offY":92.0,"offZ":-3.8146973E-06,"radius":0.5,"refActorRequireCast":true,"refActorComparisonType":3,"includeRotation":true,"Filled":true} + + PluginLog.Debug($"draw: ({x1}, {y1}) => ({x2}, {y2})"); + x1 = x1 * 8 + 88; + y1 = y1 * 8 + 84; + x2 = x2 * 8 + 88; + y2 = y2 * 8 + 84; + + Element e = new(2) + { + refX = x1, + refY = y1, + offX = x2, + offY = y2, + radius = Conf.LineWidth, + color = ((isRed?ImGuiColors.DalamudRed:ImGuiColors.DalamudYellow) with { W = Conf.Trans }).ToUint(), + thicc = Conf.LineThickness + }; + + string elementName = x1.ToString() + y1.ToString() + x2.ToString() + y2.ToString(); + Controller.RegisterElement((isRed?"Red":"Yellow") + elementName, e, true); + + Schedulers.Add(new TickScheduler(() => + { + e.Enabled = false; + }, 20000)); + } + + public override void OnObjectCreation(nint newObjectPtr) + { + Schedulers.Add(new TickScheduler(() => + { + GameObject? obj = Svc.Objects.FirstOrDefault(x => x.Address == newObjectPtr); + if (!(obj?.DataId == 0x3F37 || obj?.DataId == 0x3F38 || obj?.DataId == 0x3F39)) + return; + + string color = obj.DataId == 0x3F37 ? "red" : obj.DataId == 0x3F38 ? "blue" : "yellow"; + Vector2 position = obj.Position.ToVector2(); + PluginLog.Debug($"cube color:{color}, position:{position.ToString()}"); + + int xIndex = ((int)position.X - 88) / 8; + int yIndex = ((int)position.Y - 84) / 8; + cube[xIndex, yIndex] = (int)obj.DataId - 0x3F36; + cubeCount++; + if (cubeCount == 12) + DrawLines(false); + if (cubeCount == 24) + { + if (Conf.SwapSecond) + { + if (Conf.SwapSecondDelay == 0) + { + DrawLines(true); + } + else + { + DrawLines(false); + isBlinking = true; + Schedulers.Add(new TickScheduler(() => + { + Hide(); + DrawLines(true); + }, Conf.SwapSecondDelay * 1000)); + } + } + else + { + DrawLines(false); + } + } + }, 100 )); + } + + public class Config : IEzConfig + { + public bool SwapSecond = true; + public int SwapSecondDelay = 0; + public float LineWidth = 0.5f; + public float LineThickness = 2f; + public float Trans = 0.3f; + } + + Config Conf => Controller.GetConfig(); + + public override void OnSettingsDraw() + { + ImGui.Checkbox($"第 2 次元素理念交换线条", ref Conf.SwapSecond); // Swap lines for second classical concepts + ImGui.SetNextItemWidth(100); + ImGui.InputInt("交换延迟,单位(秒)", ref Conf.SwapSecondDelay.ValidateRange(0, 15)); // Swap delay, seconds + ImGui.Separator(); + ImGui.SetNextItemWidth(100); + ImGui.DragFloat("线条宽度", ref Conf.LineWidth.ValidateRange(0f, 5f), 0.01f); // Line width + ImGui.SetNextItemWidth(100); + ImGui.DragFloat("线条粗细", ref Conf.LineThickness.ValidateRange(1, 20f), 0.01f); // Line thickness + ImGui.SetNextItemWidth(100); + ImGui.DragFloat("透明度", ref Conf.Trans.ValidateRange(0.1f, 1f), 0.01f); // Transparency + if (ImGui.CollapsingHeader("Debug")) + { + ImGui.InputInt("num cubes", ref cubeCount); + } + } + } +} diff --git a/src/Endwalker/P12S Pangenesis 泛生论.cs b/src/Endwalker/P12S Pangenesis 泛生论.cs new file mode 100644 index 0000000..8d1dfd5 --- /dev/null +++ b/src/Endwalker/P12S Pangenesis 泛生论.cs @@ -0,0 +1,488 @@ +using System; +using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Game.ClientState.Statuses; +using Dalamud.Interface.Components; +using ECommons.Configuration; +using ECommons.DalamudServices; +using ECommons.GameFunctions; +using ECommons.Hooks; +using ECommons.ImGuiMethods; +using ECommons.MathHelpers; +using ECommons.Schedulers; +using ImGuiNET; +using Splatoon; +using Splatoon.SplatoonScripting; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using ECommons; +using ECommons.Logging; +using PluginLog = ECommons.Logging.PluginLog; + +namespace SplatoonScriptsOfficial.Duties.Endwalker +{ + public class P12S_Pangenesis_ : SplatoonScript + { + public enum DebuffType { None, Short_2, Long_2, One } + DebuffType MyDebuff = DebuffType.None; + + public override HashSet ValidTerritories => new() { 1154 }; + public override Metadata? Metadata => new(4, "tatad2-fra, RedAsteroid ޸"); + + private string ElementNamePrefix = "P12SSC"; + private int towerCount = 0; + + private int whiteTowerCast = 33603; + private int blackTowerCast = 33604; + + private int whiteDebuff = 3576; + private int blackDebuff = 3577; + private int DNABuff = 3593; + + private Element? Indicator; + private Element? Indicator1; + + private bool directionRight = false; // 0=>left, 1=>right + private bool lastTowerBlack = false; // 0=>white, 1=>black + + string TestOverride = ""; + + PlayerCharacter PC => TestOverride != "" && FakeParty.Get().FirstOrDefault(x => x.Name.ToString() == TestOverride) is PlayerCharacter pc ? pc : Svc.ClientState.LocalPlayer!; + + public override void OnEnable() + { + Reset(); + } + + private void Reset() + { + PluginLog.Information("pangenesis RESET"); + towerCount = 0; + Indicator.Enabled = false; + Indicator1.Enabled = false; + MyDebuff = DebuffType.None; + } + + public override void OnSetup() + { + // {"Name":"","refX":100.0,"refY":95.0,"refActorDataID":16182,"refActorComparisonType":3,"tether":true} + + Element e = new Element(0); + e.tether = true; + e.Enabled = false; + e.thicc = 5.0f; + e.color = 4294967295; + Controller.RegisterElement(ElementNamePrefix + "Indicator", e, true); + Indicator = Controller.GetElementByName(ElementNamePrefix + "Indicator"); + + Element e1 = new Element(0); + e1.tether = true; + e1.Enabled = false; + e1.thicc = 2.0f; + e1.color = 4294907904; + Controller.RegisterElement(ElementNamePrefix + "Indicator1", e1, true); + Indicator1 = Controller.GetElementByName(ElementNamePrefix + "Indicator1"); + + } + + private void FirstTower() + { + BattleChara whiteTower = (BattleChara)Svc.Objects.First(x => x is BattleChara o && o.IsCasting == true && o.CastActionId == whiteTowerCast && o.CurrentCastTime < 1); + BattleChara blackTower = (BattleChara)Svc.Objects.First(x => x is BattleChara o && o.IsCasting == true && o.CastActionId == blackTowerCast && o.CurrentCastTime < 1); + + PluginLog.Information($"tower casting time: {blackTower.CurrentCastTime}"); + + Vector2 whitePos = whiteTower.Position.ToVector2(); + Vector2 blackPos = blackTower.Position.ToVector2(); + + PluginLog.Information($"wtower: {whiteTower.ObjectId}, blacktower: {blackTower.ObjectId}, casttime: {whiteTower.CurrentCastTime}, {blackTower.CurrentCastTime}, position: {whiteTower.Position.ToVector2().ToString()}, {blackTower.Position.ToVector2().ToString()}"); + PluginLog.Information($": {whiteTower.ObjectId}, : {blackTower.ObjectId}, ӽʱ: {whiteTower.CurrentCastTime}, {blackTower.CurrentCastTime}, λ: {whiteTower.Position.ToVector2().ToString()}, {blackTower.Position.ToVector2().ToString()}"); + + StatusList statusList = PC.StatusList; + if (statusList.Any(x => x.StatusId == whiteDebuff && x.RemainingTime <= 8) && !(C.Strat == Strat.First_2_0_Ǒ)) + { + // short white, go black tower + Indicator.refX = blackPos.X; + Indicator.refY = blackPos.Y; + Indicator1.refX = blackPos.X; + Indicator1.refY = blackPos.Y; + lastTowerBlack = true; + MyDebuff = DebuffType.Short_2; + } + else if (statusList.Any(x => x.StatusId == whiteDebuff && x.RemainingTime > 8) && !(C.Strat == Strat.First_2_0_Ǒ)) + { + // long white, wait + int biasX = blackPos.X < 100 ? 5 : -5; + Indicator.refX = blackPos.X + biasX; + Indicator.refY = blackPos.Y; + Indicator1.refX = blackPos.X + biasX; + Indicator1.refY = blackPos.Y; + lastTowerBlack = true; + MyDebuff = DebuffType.Long_2; + } + else if (statusList.Any(x => x.StatusId == blackDebuff && x.RemainingTime <= 8) && !(C.Strat == Strat.First_2_0_Ǒ)) + { + // short black, go white tower + Indicator.refX = whitePos.X; + Indicator.refY = whitePos.Y; + Indicator1.refX = whitePos.X; + Indicator1.refY = whitePos.Y; + lastTowerBlack = false; + MyDebuff = DebuffType.Short_2; + } + else if (statusList.Any(x => x.StatusId == blackDebuff && x.RemainingTime > 8) && !(C.Strat == Strat.First_2_0_Ǒ)) + { + // long black, wait + int biasX = whitePos.X < 100 ? 5 : -5; + Indicator.refX = whitePos.X + biasX; + Indicator.refY = whitePos.Y; + Indicator1.refX = whitePos.X + biasX; + Indicator1.refY = whitePos.Y; + lastTowerBlack = false; + MyDebuff = DebuffType.Long_2; + } + // Ǒ2+0ħ + if (statusList.Any(x => x.StatusId == whiteDebuff && x.RemainingTime <= 8) && (C.Strat == Strat.First_2_0_Ǒ)) + { + // short white, go black tower + Indicator.refX = blackPos.X; + Indicator.refY = blackPos.Y - 2; + Indicator1.refX = blackPos.X; + Indicator1.refY = blackPos.Y - 2; + lastTowerBlack = true; + MyDebuff = DebuffType.Short_2; + } + else if (statusList.Any(x => x.StatusId == whiteDebuff && x.RemainingTime > 8) && (C.Strat == Strat.First_2_0_Ǒ)) + { + // long white, wait + int biasX = blackPos.X < 100 ? 5 : -5; + Indicator.refX = blackPos.X + biasX; + Indicator.refY = blackPos.Y; + Indicator1.refX = blackPos.X + biasX; + Indicator1.refY = blackPos.Y; + lastTowerBlack = true; + MyDebuff = DebuffType.Long_2; + } + else if (statusList.Any(x => x.StatusId == blackDebuff && x.RemainingTime <= 8) && (C.Strat == Strat.First_2_0_Ǒ)) + { + // short black, go white tower + Indicator.refX = whitePos.X; + Indicator.refY = whitePos.Y - 2; + Indicator1.refX = whitePos.X; + Indicator1.refY = whitePos.Y - 2; + lastTowerBlack = false; + MyDebuff = DebuffType.Short_2; + } + else if (statusList.Any(x => x.StatusId == blackDebuff && x.RemainingTime > 8) && (C.Strat == Strat.First_2_0_Ǒ)) + { + // long black, wait + int biasX = whitePos.X < 100 ? 5 : -5; + Indicator.refX = whitePos.X + biasX; + Indicator.refY = whitePos.Y; + Indicator1.refX = whitePos.X + biasX; + Indicator1.refY = whitePos.Y; + lastTowerBlack = false; + MyDebuff = DebuffType.Long_2; + } + else + { + if (C.Strat == Strat.First_2_1) + { + if (statusList.Any(x => x.StatusId == DNABuff)) + { + // 1 buff, go first tower + Indicator.refX = debuff1.IndexOf(PC) < 1 ? 85 : 115; + Indicator.refY = 91; + Indicator1.refX = debuff1.IndexOf(PC) < 1 ? 85 : 115; + Indicator1.refY = 91; + lastTowerBlack = (Indicator.refX < 100) == (blackPos.X < 100); + MyDebuff = DebuffType.One; + } + else + { + // 0 buff, wait; + Indicator.refX = debuff0.IndexOf(PC) < 1 ? 90 : 110; + Indicator.refY = 91; + Indicator1.refX = debuff0.IndexOf(PC) < 1 ? 90 : 110; + Indicator1.refY = 91; + lastTowerBlack = (Indicator.refX < 100) != (blackPos.X < 100); + MyDebuff = DebuffType.None; + } + } + else if (C.Strat == Strat.First_2_0) + { + if (statusList.Any(x => x.StatusId == DNABuff)) + { + // 1 buff, wait + Indicator.refX = PC.Position.ToVector2().X < 100 ? 90 : 110; + Indicator.refY = 91; + Indicator1.refX = PC.Position.ToVector2().X < 100 ? 90 : 110; + Indicator1.refY = 91; + lastTowerBlack = (Indicator.refX < 100) == (blackPos.X < 100); + MyDebuff = DebuffType.One; + } + else + { + // 0 buff, go first tower; + Indicator.refX = PC.Position.ToVector2().X < 100 ? 85 : 115; + Indicator.refY = 91; + Indicator1.refX = PC.Position.ToVector2().X < 100 ? 85 : 115; + Indicator1.refY = 91; + lastTowerBlack = (Indicator.refX < 100) != (blackPos.X < 100); + MyDebuff = DebuffType.None; + } + } + else if (C.Strat == Strat.First_2_0_Ǒ) + { + if (statusList.Any(x => x.StatusId == DNABuff)) + { + // 1 buff, go first tower + Indicator.refX = debuff1.IndexOf(PC) < 1 ? 85 : 115; + Indicator.refY = 93.5f; + Indicator1.refX = debuff1.IndexOf(PC) < 1 ? 85 : 115; + Indicator1.refY = 93.5f; + lastTowerBlack = (Indicator.refX < 100) == (blackPos.X < 100); + MyDebuff = DebuffType.One; + } + else + { + // 0 buff, wait; + Indicator.refX = debuff0.IndexOf(PC) < 1 ? 85 : 115; + Indicator.refY = 94.5f; + Indicator1.refX = debuff0.IndexOf(PC) < 1 ? 85 : 115; + Indicator1.refY = 94.5f; + lastTowerBlack = (Indicator.refX < 100) != (blackPos.X < 100); + MyDebuff = DebuffType.None; + } + } + } + + if (C.Strat == Strat.First_2_0 && MyDebuff == DebuffType.Short_2) + { + lastTowerBlack = !lastTowerBlack; + } + + directionRight = (int)Indicator.refX < 100 ? false : true; + Indicator.Enabled = true; + Indicator1.Enabled = true; + + PluginLog.Information($"first tower, {Indicator.refX}, {Indicator.refY}, colorBlack?: {lastTowerBlack}"); + + } + + private void SecondTower() + { + BattleChara whiteTower; + BattleChara blackTower; + if (directionRight) + { + // right + whiteTower = (BattleChara)Svc.Objects.First(x => x is BattleChara o && o.IsCasting == true && o.CastActionId == whiteTowerCast && o.Position.ToVector2().X > 100 && o.CurrentCastTime < 1); + blackTower = (BattleChara)Svc.Objects.First(x => x is BattleChara o && o.IsCasting == true && o.CastActionId == blackTowerCast && o.Position.ToVector2().X > 100 && o.CurrentCastTime < 1); + } + else + { + // left + whiteTower = (BattleChara)Svc.Objects.First(x => x is BattleChara o && o.IsCasting == true && o.CastActionId == whiteTowerCast && o.Position.ToVector2().X < 100 && o.CurrentCastTime < 1); + blackTower = (BattleChara)Svc.Objects.First(x => x is BattleChara o && o.IsCasting == true && o.CastActionId == blackTowerCast && o.Position.ToVector2().X < 100 && o.CurrentCastTime < 1); + } + + Vector2 whitePos = whiteTower.Position.ToVector2(); + Vector2 blackPos = blackTower.Position.ToVector2(); + + new TickScheduler(() => + { + StatusList statusList = PC.StatusList; + if (statusList.Any(x => x.StatusId == whiteDebuff)) + { + // white, go black + Indicator.refX = blackPos.X; + Indicator.refY = blackPos.Y; + Indicator1.refX = blackPos.X; + Indicator1.refY = blackPos.Y; + lastTowerBlack = true; + } + else if (statusList.Any(x => x.StatusId == blackDebuff)) + { + // black, go white + Indicator.refX = whitePos.X; + Indicator.refY = whitePos.Y; + Indicator1.refX = whitePos.X; + Indicator1.refY = whitePos.Y; + lastTowerBlack = false; + } + else if (C.Strat == Strat.First_2_0_Ǒ) + { + Indicator.refX = lastTowerBlack ? whitePos.X : blackPos.X; + Indicator.refY = lastTowerBlack ? whitePos.Y : blackPos.Y; + Indicator1.refX = lastTowerBlack ? whitePos.X : blackPos.X; + Indicator1.refY = lastTowerBlack ? whitePos.Y : blackPos.Y; + } + else if (!(C.Strat == Strat.First_2_0_Ǒ)) + { + Indicator.refX = lastTowerBlack ? blackPos.X : whitePos.X; + Indicator.refY = lastTowerBlack ? blackPos.Y : whitePos.Y; + Indicator1.refX = lastTowerBlack ? blackPos.X : whitePos.X; + Indicator1.refY = lastTowerBlack ? blackPos.Y : whitePos.Y; + } + + PluginLog.Information($"second/third tower, {Indicator.refX}, {Indicator.refY}"); + PluginLog.Information($"2/3, {Indicator.refX}, {Indicator.refY}"); + }, 1500); + } + + private void ThirdTower() + { + SecondTower(); + new TickScheduler(() => + { + Indicator.Enabled = false; + Indicator1.Enabled = false; + }, 6000); + } + + public override void OnMessage(string Message) + { + if (Message.Contains("(12383>33603)") || Message.Contains("(12383>33604)")) + { + // tower appear + PluginLog.Information($"tower appear!"); + towerCount++; + if (towerCount == 2) + FirstTower(); + if (towerCount == 6) + SecondTower(); + if (towerCount == 10) + ThirdTower(); + } + + if (Message.Contains("(12382>33602)")) + { + debuff1.Clear(); + debuff0.Clear(); + CheckBuff(); + } + } + + public void CheckBuff() + { + var Party = FakeParty.Get(); + foreach (var pc in Party) + { + if (pc.StatusList.Any(x => x.StatusId == DNABuff)) + { + if (pc.StatusList.Any(x => x.StatusId == DNABuff && x.StackCount == 1)) + { + debuff1.Add(pc); + } + } + else + { + debuff0.Add(pc); + } + } + List order = new List { C.MT, C.ST, C.H1, C.H2, C.D1, C.D2, C.D3, C.D4 }; + debuff0 = debuff0.OrderBy(p => order.IndexOf(p.Name.ToString())).ToList(); + debuff1 = debuff1.OrderBy(p => order.IndexOf(p.Name.ToString())).ToList(); + } + public override void OnDirectorUpdate(DirectorUpdateCategory category) + { + if (category == DirectorUpdateCategory.Commence || category == DirectorUpdateCategory.Recommence) + Reset(); + } + + + public override void OnSettingsDraw() + { + ImGui.SetNextItemWidth(200f); + ImGuiEx.EnumCombo("ѡ", ref C.Strat); // Select strat + ImGui.Text("ʹǰDebug2гʼ飬СӳԱΪȷְ"); + ImGui.Text("ʹǑӹԷ۲ \"ѡ\" л"); + + if (ImGui.CollapsingHeader("Debug")) + { + ImGuiEx.Text($"LastTowerBlack: {lastTowerBlack}"); + ImGuiEx.Text($"towerCount: {towerCount}"); + ImGuiEx.Text($"MyDebuff: {MyDebuff}"); + if (ImGui.Button("Reset")) Reset(); + ImGui.SetNextItemWidth(200f); + ImGui.InputText("TestOverride", ref TestOverride, 50); + ImGuiEx.Text($"{PC}"); + } + + if (ImGui.CollapsingHeader("Debug2")) + { + ImGui.Text("=====debuff====="); + if (debuff0.Count >= 2) + { + ImGui.Text($"ȼ:{debuff0[0].Name}"); + ImGui.Text($"ȼ:{debuff0[1].Name}"); + } + ImGui.Text("=====1debuff====="); + if (debuff1.Count >= 2) + { + ImGui.Text($"ȼ:{debuff1[0].Name}"); + ImGui.Text($"ȼ:{debuff1[1].Name}"); + } + } + DrawPartySelection("MT", ref C.MT); + DrawPartySelection("ST", ref C.ST); + DrawPartySelection("H1", ref C.H1); + DrawPartySelection("H2", ref C.H2); + DrawPartySelection("D1", ref C.D1); + DrawPartySelection("D2", ref C.D2); + DrawPartySelection("D3", ref C.D3); + DrawPartySelection("D4", ref C.D4); + if (ImGui.Button("ʼ")) + { + var orderlist = FakeParty.Get(); + orderlist = orderlist.OrderBy(p => desiredOrder.IndexOf(p.ClassJob.Id)).ToList(); + foreach (var pc in orderlist) + { + DuoLog.Information($"{pc.ClassJob.Id}-{pc.ClassJob.GameData.Name}"); + } + C.MT = orderlist.ToList()[0].Name.ToString(); + C.ST = orderlist.ToList()[1].Name.ToString(); + C.H1 = orderlist.ToList()[2].Name.ToString(); + C.H2 = orderlist.ToList()[3].Name.ToString(); + C.D1 = orderlist.ToList()[4].Name.ToString(); + C.D2 = orderlist.ToList()[5].Name.ToString(); + C.D3 = orderlist.ToList()[6].Name.ToString(); + C.D4 = orderlist.ToList()[7].Name.ToString(); + } + } + void DrawPartySelection(string label, ref string selectedParty) + { + string tempSelectedParty = selectedParty; + + ImGui.Text(label); + ImGui.SameLine(); + ImGui.SetNextItemWidth(120f); + if (ImGui.BeginCombo($"##partysel+{label}", tempSelectedParty)) + { + FakeParty.Get().Each((x) => { if (ImGui.Selectable(x.Name.ToString())) tempSelectedParty = x.Name.ToString(); }); + ImGui.EndCombo(); + } + + selectedParty = tempSelectedParty; + } + public enum Strat { First_2_1, First_2_0, First_2_0_Ǒ } + List desiredOrder = new List { 21, 32, 37, 19, 24, 33, 40, 28, 34, 20, 30, 22, 39, 23, 38, 31, 25, 27, 35 }; + List debuff0 = new List(); + List debuff1 = new List(); + Config C => Controller.GetConfig(); + public class Config : IEzConfig + { + public Strat Strat = Strat.First_2_1; + public string MT = String.Empty; + public string ST = String.Empty; + public string H1 = String.Empty; + public string H2 = String.Empty; + public string D1 = String.Empty; + public string D2 = String.Empty; + public string D3 = String.Empty; + public string D4 = String.Empty; + } + } +} \ No newline at end of file