Compare commits

..

No commits in common. "7ea7c9aab19d1c3a2a06b29b087d6818f26aa387" and "0278218756f9c95ae34234f9af046a9b38d237d0" have entirely different histories.

7 changed files with 744 additions and 2108 deletions

View File

@ -11,7 +11,7 @@
1. [普通副本](https://github.com/RedAsteroid/FFXIV_Triggers/blob/main/demo/img1.md)
2. [亚历山大绝境战(暂缺)](https://github.com/RedAsteroid/FFXIV_Triggers/blob/main/demo/img2.md)
### 零式万魔殿天狱篇施工中,预设参考请访问 [**此处**](https://github.com/RedAsteroid/FFXIV_Triggers/blob/main/src/Endwalker/9-12savage.md)
- 零式万魔殿天狱篇施工中,预设参考请访问 [**此处**](https://github.com/RedAsteroid/FFXIV_Triggers/blob/main/src/Endwalker/9-12savage.md)
## 请注意:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,143 +0,0 @@
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<uint> ValidTerritories => new() { 1150 };
public override Metadata? Metadata => new(2, "NightmareXIV, RedAsteroid 修改");
List<TetherData> 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<Config>();
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;
}
}
}

View File

@ -1,258 +0,0 @@
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<uint> 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<uint> StackSpreadRecord = new HashSet<uint>();
List<TickScheduler> Sch = new List<TickScheduler>();
private bool debug = false;
Dictionary<uint, float> distanceDebug = new Dictionary<uint, float>();
Dictionary<uint, Vector2> positionDebug = new Dictionary<uint, Vector2>();
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<Config>();
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}");
}
}
}
}
}
}
}

View File

@ -1,263 +0,0 @@
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<uint> 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<TickScheduler> 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<Config>();
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);
}
}
}
}

View File

@ -1,488 +0,0 @@
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<uint> 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<string> order = new List<string> { 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<uint> desiredOrder = new List<uint> { 21, 32, 37, 19, 24, 33, 40, 28, 34, 20, 30, 22, 39, 23, 38, 31, 25, 27, 35 };
List<PlayerCharacter> debuff0 = new List<PlayerCharacter>();
List<PlayerCharacter> debuff1 = new List<PlayerCharacter>();
Config C => Controller.GetConfig<Config>();
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;
}
}
}