Skip to content

Commit

Permalink
Merge pull request #519 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
merge vbm (FRU p4, chaotic WIP etc)
  • Loading branch information
CarnifexOptimus authored Dec 27, 2024
2 parents 64d8d56 + 1a7ba89 commit 8198911
Show file tree
Hide file tree
Showing 65 changed files with 2,256 additions and 191 deletions.
4 changes: 2 additions & 2 deletions BossMod/AI/AIConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ sealed class AIConfig : ConfigNode
public bool ShowDTR = false;

[PropertyDisplay("Show AI interface")]
public bool DrawUI = true;
public bool DrawUI = false;

[PropertyDisplay("Focus target master")]
public bool FocusTargetLeader = true;
public bool FocusTargetLeader = false;

[PropertyDisplay("Broadcast keypresses to other windows")]
public bool BroadcastToSlaves = false;
Expand Down
3 changes: 1 addition & 2 deletions BossMod/AI/AIController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ public void Update(Actor? player, AIHints hints, DateTime now)
var forbidMovement = moveRequested || !AllowInterruptingCastByMovement && _amex.MoveMightInterruptCast;
if (NaviTargetPos != null && !forbidMovement && (NaviTargetPos.Value - player.Position).LengthSq() > 0.001f)
{
var y = NaviTargetVertical != null && IsVerticalAllowed ? NaviTargetVertical.Value : player.PosRot.Y;
desiredPosition = new(NaviTargetPos.Value.X, y, NaviTargetPos.Value.Z);
desiredPosition = NaviTargetPos.Value.ToVec3(NaviTargetVertical != null && IsVerticalAllowed ? NaviTargetVertical.Value : player.PosRot.Y);
}
else
{
Expand Down
8 changes: 5 additions & 3 deletions BossMod/AI/AIRotationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ public abstract class AIRotationModule(RotationModuleManager manager, Actor play
protected float Deadline(DateTime deadline) => Math.Max(0, (float)(deadline - World.CurrentTime).TotalSeconds);
protected float Speed() => Player.FindStatus(50) != null ? 7.8f : 6;

protected bool InMeleeRange(Actor target)
protected bool InMeleeRange(Actor target, WPos position)
{
var maxRange = target.HitboxRadius + Player.HitboxRadius + 3;
return (target.Position - Player.Position).LengthSq() < maxRange * maxRange;
return (target.Position - position).LengthSq() < maxRange * maxRange;
}

protected bool InMeleeRange(Actor target) => InMeleeRange(target, Player.Position);

protected void SetForcedMovement(WPos? pos, float tolerance = 0.1f)
{
var dir = (pos ?? Player.Position) - Player.Position;
Hints.ForcedMovement = dir.LengthSq() > tolerance * tolerance ? new(dir.X, Player.PosRot.Y, dir.Z) : default;
Hints.ForcedMovement = dir.LengthSq() > tolerance * tolerance ? dir.ToVec3(Player.PosRot.Y) : default;
}

protected WPos ClosestInRange(WPos pos, WPos target, float maxRange)
Expand Down
8 changes: 8 additions & 0 deletions BossMod/Autorotation/Plan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ private void ReadEntryFields(ref Plan.Entry entry, in JsonElement jelem)
entry.Value.Target = Enum.Parse<StrategyTarget>(jtarget.GetString() ?? "");
if (jelem.TryGetProperty(nameof(StrategyValue.TargetParam), out var jtp))
entry.Value.TargetParam = jtp.GetInt32();
if (jelem.TryGetProperty(nameof(StrategyValue.Offset1), out var joff1))
entry.Value.Offset1 = joff1.GetSingle();
if (jelem.TryGetProperty(nameof(StrategyValue.Offset2), out var joff2))
entry.Value.Offset2 = joff2.GetSingle();
if (jelem.TryGetProperty(nameof(StrategyValue.Comment), out var jcomment))
entry.Value.Comment = jcomment.GetString() ?? "";
}
Expand All @@ -189,6 +193,10 @@ private void WriteEntryFields(Utf8JsonWriter writer, in Plan.Entry entry)
writer.WriteString(nameof(StrategyValue.Target), entry.Value.Target.ToString());
if (entry.Value.TargetParam != 0)
writer.WriteNumber(nameof(StrategyValue.TargetParam), entry.Value.TargetParam);
if (entry.Value.Offset1 != 0)
writer.WriteNumber(nameof(StrategyValue.Offset1), entry.Value.Offset1);
if (entry.Value.Offset2 != 0)
writer.WriteNumber(nameof(StrategyValue.Offset2), entry.Value.Offset2);
if (entry.Value.Comment.Length > 0)
writer.WriteString(nameof(StrategyValue.Comment), entry.Value.Comment);
}
Expand Down
8 changes: 8 additions & 0 deletions BossMod/Autorotation/Preset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public class JsonPresetConverter : JsonConverter<Preset>
s.Value.Target = Enum.Parse<StrategyTarget>(jtarget.GetString() ?? "");
if (js.TryGetProperty(nameof(StrategyValue.TargetParam), out var jtp))
s.Value.TargetParam = jtp.GetInt32();
if (js.TryGetProperty(nameof(StrategyValue.Offset1), out var joff1))
s.Value.Offset1 = joff1.GetSingle();
if (js.TryGetProperty(nameof(StrategyValue.Offset2), out var joff2))
s.Value.Offset2 = joff2.GetSingle();
if (js.TryGetProperty(nameof(StrategyValue.Comment), out var jcomment))
s.Value.Comment = jcomment.GetString() ?? "";

Expand Down Expand Up @@ -144,6 +148,10 @@ public override void Write(Utf8JsonWriter writer, Preset value, JsonSerializerOp
writer.WriteString(nameof(StrategyValue.Target), s.Value.Target.ToString());
if (s.Value.TargetParam != 0)
writer.WriteNumber(nameof(StrategyValue.TargetParam), s.Value.TargetParam);
if (s.Value.Offset1 != 0)
writer.WriteNumber(nameof(StrategyValue.Offset1), s.Value.Offset1);
if (s.Value.Offset2 != 0)
writer.WriteNumber(nameof(StrategyValue.Offset2), s.Value.Offset2);
if (s.Value.Comment.Length > 0)
writer.WriteString(nameof(StrategyValue.Comment), s.Value.Comment);
writer.WriteEndObject();
Expand Down
1 change: 1 addition & 0 deletions BossMod/Autorotation/RotationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public bool TraitUnlocked(uint id)
// utility to resolve the target overrides; returns null on failure - in this case module is expected to run smart-targeting logic
// expected usage is `ResolveTargetOverride(strategy) ?? CustomSmartTargetingLogic(...)`
protected Actor? ResolveTargetOverride(in StrategyValue strategy) => Manager.ResolveTargetOverride(strategy.Target, strategy.TargetParam);
protected WPos ResolveTargetLocation(in StrategyValue strategy) => Manager.ResolveTargetLocation(strategy.Target, strategy.TargetParam, strategy.Offset1, strategy.Offset2);

protected float StatusDuration(DateTime expireAt) => Math.Max((float)(expireAt - World.CurrentTime).TotalSeconds, 0.0f);

Expand Down
9 changes: 8 additions & 1 deletion BossMod/Autorotation/RotationModuleManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public void Update(float estimatedAnimLockDelay, bool isMoving)
{
Hints.ForcedTarget = forced.Value.Target != StrategyTarget.Automatic
? ResolveTargetOverride(forced.Value.Target, forced.Value.TargetParam)
: (ResolveTargetOverride(StrategyTarget.EnemyWithHighestPriority, 0) ?? Bossmods.ActiveModule?.PrimaryActor);
: (ResolveTargetOverride(StrategyTarget.EnemyWithHighestPriority, 0) ?? (Bossmods.ActiveModule?.PrimaryActor is var primary && primary != null && !primary.IsDeadOrDestroyed && primary.IsTargetable ? primary : null));
}

// auto actions
Expand All @@ -119,6 +119,13 @@ public void Update(float estimatedAnimLockDelay, bool isMoving)
_ => null
};

public WPos ResolveTargetLocation(StrategyTarget strategy, int param, float off1, float off2) => strategy switch
{
StrategyTarget.PointAbsolute => new(off1, off2),
StrategyTarget.PointCenter or StrategyTarget.Automatic => (Bossmods.ActiveModule?.Center + off1 * off2.Degrees().ToDirection()) ?? Player?.Position ?? default,
_ => (ResolveTargetOverride(strategy, param)?.Position + off1 * off2.Degrees().ToDirection()) ?? Player?.Position ?? default,
};

private Plan? CalculateExpectedPlan()
{
var player = Player;
Expand Down
4 changes: 4 additions & 0 deletions BossMod/Autorotation/Strategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public enum StrategyTarget
PartyWithLowestHP, // parameter is whether self is allowed (1) or not (0)
EnemyWithHighestPriority, // selects closest if there are multiple
EnemyByOID, // parameter is oid; not really useful outside planner; selects closest if there are multiple
PointAbsolute, // absolute x/y coordinates
PointCenter, // offset from arena center

Count
}
Expand Down Expand Up @@ -49,6 +51,8 @@ public record struct StrategyValue()
public float PriorityOverride = float.NaN; // priority override for the action controlled by the config; not all configs support it, if not set the default priority is used
public StrategyTarget Target; // target selection strategy
public int TargetParam; // strategy-specific parameter
public float Offset1; // x or r coordinate
public float Offset2; // y or phi coordinate
public string Comment = ""; // user-editable comment string
public float ExpireIn = float.MaxValue; // time until strategy expires
}
Expand Down
23 changes: 21 additions & 2 deletions BossMod/Autorotation/UIStrategyValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public static string PreviewTarget(ref StrategyValue value, BossModuleRegistry.I
StrategyTarget.EnemyByOID => $"{(moduleInfo?.ObjectIDType != null ? Enum.ToObject(moduleInfo.ObjectIDType, (uint)value.TargetParam).ToString() : "???")} (0x{value.TargetParam:X})",
_ => ""
};
return targetDetails.Length > 0 ? $"{value.Target} ({targetDetails})" : $"{value.Target}";
var offsetDetails = value.Target == StrategyTarget.PointAbsolute ? $" {value.Offset1}x{value.Offset2}" : value.Offset1 != 0 ? $" + R{value.Offset1}, dir={value.Offset2}" : "";
return (targetDetails.Length > 0 ? $"{value.Target} ({targetDetails})" : $"{value.Target}") + offsetDetails;
}

public static bool DrawEditor(ref StrategyValue value, StrategyConfig cfg, BossModuleRegistry.Info? moduleInfo, int? level)
Expand Down Expand Up @@ -186,16 +187,34 @@ public static bool DrawEditorTarget(ref StrategyValue value, ActionTargets suppo
}
break;
}

if (supportedTargets.HasFlag(ActionTargets.Area))
{
if (value.Target == StrategyTarget.PointAbsolute)
{
modified |= ImGui.InputFloat("X", ref value.Offset1);
modified |= ImGui.InputFloat("Z", ref value.Offset2);
}
else
{
modified |= ImGui.DragFloat("Offset", ref value.Offset1, 0.1f, 0, 30);
modified |= ImGui.DragFloat("Direction", ref value.Offset2, 1, -180, 180);
if (ImGui.IsItemHovered())
ImGui.SetTooltip($"In degrees; 0 is south, increases CCW (so 90 is E, 180 is N, -90 is W)");
}
}

return modified;
}

public static bool AllowTarget(StrategyTarget t, ActionTargets supported, BossModuleRegistry.Info? moduleInfo) => t switch
public static bool AllowTarget(StrategyTarget t, ActionTargets supported, BossModuleRegistry.Info? moduleInfo) => supported.HasFlag(ActionTargets.Area) || t switch
{
StrategyTarget.Self => supported.HasFlag(ActionTargets.Self),
StrategyTarget.PartyByAssignment => supported.HasFlag(ActionTargets.Party),
StrategyTarget.PartyWithLowestHP => supported.HasFlag(ActionTargets.Party),
StrategyTarget.EnemyWithHighestPriority => supported.HasFlag(ActionTargets.Hostile),
StrategyTarget.EnemyByOID => supported.HasFlag(ActionTargets.Hostile) && moduleInfo != null,
StrategyTarget.PointAbsolute or StrategyTarget.PointCenter => false,
_ => true
};
}
2 changes: 1 addition & 1 deletion BossMod/Autorotation/xan/Healers/SCH.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ void autoplace()
if (FairyOrder != PetOrder.Place && (Player.InCombat || CountdownRemaining > 0))
{
if (Bossmods.ActiveModule?.Arena.Center is WPos p)
Hints.ActionsToExecute.Push(new ActionID(ActionType.PetAction, 3), null, ActionQueue.Priority.VeryHigh, targetPos: new(p.X, Player.PosRot.Y, p.Z));
Hints.ActionsToExecute.Push(new ActionID(ActionType.PetAction, 3), null, ActionQueue.Priority.VeryHigh, targetPos: p.ToVec3(Player.PosRot.Y));
}
}

Expand Down
2 changes: 1 addition & 1 deletion BossMod/BossModule/AIHintsVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void Draw(UITree tree)
{
tree.LeafNodes(hints.PotentialTargets, e => $"[{e.Priority}] {e.Actor} (str={e.AttackStrength:f2}), dist={(e.Actor.Position - player.Position).Length():f2}, tank={e.ShouldBeTanked}/{e.PreferProvoking}/{e.DesiredPosition}/{e.DesiredRotation}");
}
tree.LeafNode($"Forced target: {hints.ForcedTarget}");
tree.LeafNode($"Forced target: {hints.ForcedTarget}{((hints.ForcedTarget?.IsTargetable ?? true) ? "" : " (untargetable)")}");
tree.LeafNode($"Forced movement: {hints.ForcedMovement} (misdirection threshold={hints.MisdirectionThreshold})");
tree.LeafNode($"Special movement: {hints.ImminentSpecialMode.mode} in {Math.Max(0, (hints.ImminentSpecialMode.activation - ws.CurrentTime).TotalSeconds):f3}s");
foreach (var _1 in tree.Node("Forbidden zones", hints.ForbiddenZones.Count == 0))
Expand Down
1 change: 1 addition & 0 deletions BossMod/BossModule/BossModuleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public enum Category
Ultimate,
Unreal,
Alliance,
Chaotic,
Foray,
VariantCriterion,
DeepDungeon,
Expand Down
4 changes: 2 additions & 2 deletions BossMod/BossModule/BossModuleMainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ private void DrawMovementHints(BossComponent.MovementHints? arrows, float y)

foreach ((var start, var end, var color) in arrows)
{
Vector3 start3 = new(start.X, y, start.Z);
Vector3 end3 = new(end.X, y, end.Z);
Vector3 start3 = start.ToVec3(y);
Vector3 end3 = end.ToVec3(y);
Camera.Instance.DrawWorldLine(start3, end3, color);
var dir = Vector3.Normalize(end3 - start3);
var arrowStart = end3 - 0.4f * dir;
Expand Down
1 change: 1 addition & 0 deletions BossMod/Config/ModuleViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public ModuleViewer(PlanDatabase? planDB, WorldState ws)
Customize(BossModuleInfo.Category.DeepDungeon, contentType.GetRow(21));
Customize(BossModuleInfo.Category.Ultimate, contentType.GetRow(28));
Customize(BossModuleInfo.Category.VariantCriterion, contentType.GetRow(30));
Customize(BossModuleInfo.Category.Chaotic, contentType.GetRow(37));

var playStyle = Service.LuminaSheet<CharaCardPlayStyle>()!;
Customize(BossModuleInfo.Category.Foray, playStyle.GetRow(6));
Expand Down
1 change: 1 addition & 0 deletions BossMod/Data/Actor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public sealed class Actor(ulong instanceID, uint oid, int spawnIndex, string nam
public ClassCategory ClassCategory => Class.GetClassCategory();
public WPos Position => new(PosRot.X, PosRot.Z);
public WPos PrevPosition => new(PrevPosRot.X, PrevPosRot.Z);
public WDir LastFrameMovement => Position - PrevPosition;
public Angle Rotation => PosRot.W.Radians();
public bool Omnidirectional => Utils.CharacterIsOmnidirectional(OID);
public bool IsDeadOrDestroyed => IsDead || IsDestroyed;
Expand Down
3 changes: 1 addition & 2 deletions BossMod/Debug/DebugInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ public void Draw()
}
if (_wannaMove)
{
var dir = _moveDir.Degrees().ToDirection();
_move.DesiredDirection = new(dir.X, 0, dir.Z);
_move.DesiredDirection = _moveDir.Degrees().ToDirection().ToVec3();
}
//_navi.Update(player);

Expand Down
6 changes: 6 additions & 0 deletions BossMod/Debug/MainDebugWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ private unsafe void DrawStatuses()
var player = (Character*)GameObjectManager.Instance()->Objects.IndexSorted[0].Value;
player->GetStatusManager()->SetStatus(20, 3909, 20.0f, 100, 0xE0000000, true);
}
ImGui.SameLine();
if (ImGui.Button("Add thin ice"))
{
var player = (Character*)GameObjectManager.Instance()->Objects.IndexSorted[0].Value;
player->GetStatusManager()->SetStatus(20, 911, 20.0f, 320, 0xE0000000, true); // param = distance * 10
}

foreach (var elem in ws.Actors)
{
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Framework/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ private unsafe void ExecuteHints()
_movementOverride.DesiredDirection = _hints.ForcedMovement;
_movementOverride.MisdirectionThreshold = _hints.MisdirectionThreshold;
// update forced target, if needed (TODO: move outside maybe?)
if (_hints.ForcedTarget != null)
if (_hints.ForcedTarget != null && _hints.ForcedTarget.IsTargetable)
{
var obj = _hints.ForcedTarget.SpawnIndex >= 0 ? FFXIVClientStructs.FFXIV.Client.Game.Object.GameObjectManager.Instance()->Objects.IndexSorted[_hints.ForcedTarget.SpawnIndex].Value : null;
if (obj != null && obj->EntityId != _hints.ForcedTarget.InstanceID)
Expand Down
9 changes: 2 additions & 7 deletions BossMod/Modules/Dawntrail/Alliance/A11Prishe/ArenaChanges.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,12 @@ public override void OnEventEnvControl(byte index, uint state)
SetArena(ArenaENVC02000100);
break;
case 0x00080004 or 0x00800004:
SetDefaultArena();
Arena.Bounds = A11Prishe.DefaultBounds;
Arena.Center = A11Prishe.ArenaCenter;
break;
}
}

private void SetDefaultArena()
{
Arena.Bounds = A11Prishe.DefaultBounds;
Arena.Center = A11Prishe.ArenaCenter;
}

private void SetArena(ArenaBoundsComplex bounds)
{
Arena.Bounds = bounds;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace BossMod.Dawntrail.Chaotic.Ch01CloudOfDarkness;

class ActivePivotParticleBeam(BossModule module) : Components.GenericRotatingAOE(module)
{
private static readonly AOEShapeRect _shape = new(40, 9, 40);

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
var rotation = (AID)spell.Action.ID switch
{
AID.ActivePivotParticleBeamCW => -22.5f.Degrees(),
AID.ActivePivotParticleBeamCCW => 22.5f.Degrees(),
_ => default
};
if (rotation != default)
Sequences.Add(new(_shape, caster.Position, spell.Rotation, rotation, Module.CastFinishAt(spell, 0.6f), 1.6f, 5));
}

public override void OnEventCast(Actor caster, ActorCastEvent spell)
{
if ((AID)spell.Action.ID == AID.ActivePivotParticleBeamAOE && Sequences.Count > 0)
AdvanceSequence(0, WorldState.CurrentTime);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
namespace BossMod.Dawntrail.Chaotic.Ch01CloudOfDarkness;

class ArenaChanges(BossModule module) : Components.GenericAOEs(module)
{
private AOEInstance? _aoe;
private static readonly Square[] DefaultPolygon = [new(Ch01CloudOfDarkness.DefaultCenter, 40)];
private static readonly AOEShapeCustom P1Transition = new(DefaultPolygon, Ch01CloudOfDarkness.Diamond);
private static readonly AOEShapeCustom P2Transition = new(DefaultPolygon, Ch01CloudOfDarkness.Phase2ShapesWD);
private static readonly AOEShapeDonut donut = new(34, 40);

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe);

public override void OnEventEnvControl(byte index, uint state)
{
if (index == 0x00)
switch (state)
{
case 0x00200010:
SetAOE(P1Transition);
break;
case 0x00020001:
SetAOE(P2Transition);
break;
}
else if (index == 0x02)
switch (state)
{
case 0x00020001:
SetArena(Ch01CloudOfDarkness.Phase2BoundsND);
break;
case 0x00080004:
SetArena(Ch01CloudOfDarkness.Phase2BoundsWD);
break;
}
}

public override void OnEventDirectorUpdate(uint updateID, uint param1, uint param2, uint param3, uint param4)
{
if (updateID != 0x8000000D)
return;
switch (param1)
{
case 0x10000000: // default arena
Arena.Bounds = Ch01CloudOfDarkness.DefaultArena;
Arena.Center = Ch01CloudOfDarkness.DefaultCenter;
break;
case 0x20000000: // (phase 2)
SetArena(Ch01CloudOfDarkness.Phase2BoundsWD);
break;
case 0x40000000: // diamond arena (phase 1)
SetArena(Ch01CloudOfDarkness.Phase1Bounds);
break;
}
}

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
if ((AID)spell.Action.ID == AID.DarkDominion)
SetAOE(donut);
}

private void SetArena(ArenaBoundsComplex bounds)
{
Arena.Bounds = bounds;
Arena.Center = bounds.Center;
_aoe = null;
}

private void SetAOE(AOEShape shape)
{
_aoe = new(shape, Arena.Center, default, WorldState.FutureTime(9));
}
}
Loading

0 comments on commit 8198911

Please sign in to comment.