Skip to content

Commit

Permalink
Merge pull request #449 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
Halatali modules
  • Loading branch information
CarnifexOptimus authored Nov 21, 2024
2 parents c35456b + a4d1d06 commit 5b37127
Show file tree
Hide file tree
Showing 17 changed files with 412 additions and 85 deletions.
18 changes: 15 additions & 3 deletions BossMod/BossModule/AIHints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public enum SpecialMode

// list of potential targets
public List<Enemy> PotentialTargets = [];
private int potentialTargetsCount;
public int HighestPotentialTargetPriority;

// forced target
Expand Down Expand Up @@ -99,6 +100,7 @@ public void Clear()
PathfindMapBounds = DefaultBounds;
PathfindMapObstacles = default;
PotentialTargets.Clear();
potentialTargetsCount = 0;
ForcedTarget = null;
ForcedMovement = null;
InteractWithTarget = null;
Expand Down Expand Up @@ -143,28 +145,38 @@ public void FillPotentialTargets(WorldState ws, bool playerIsDefaultTank)
{
Priority = allowedAttack ? 0 : Enemy.PriorityForbidAI
});
++potentialTargetsCount;
}
}

public void PrioritizeTargetsByOID(uint oid, int priority = 0)
{
foreach (var h in PotentialTargets)
for (var i = 0; i < potentialTargetsCount; ++i)
{
var h = PotentialTargets[i];
if (h.Actor.OID == oid)
h.Priority = Math.Max(priority, h.Priority);
}
}
public void PrioritizeTargetsByOID<OID>(OID oid, int priority = 0) where OID : Enum => PrioritizeTargetsByOID((uint)(object)oid, priority);

public void PrioritizeTargetsByOID(uint[] oids, int priority = 0)
{
foreach (var h in PotentialTargets)
for (var i = 0; i < potentialTargetsCount; ++i)
{
var h = PotentialTargets[i];
if (oids.Contains(h.Actor.OID))
h.Priority = Math.Max(priority, h.Priority);
}
}

public void PrioritizeAll()
{
foreach (var h in PotentialTargets)
for (var i = 0; i < potentialTargetsCount; ++i)
{
var h = PotentialTargets[i];
h.Priority = Math.Max(h.Priority, 0);
}
}

public void InteractWithOID(WorldState ws, uint oid) => InteractWithTarget = ws.Actors.FirstOrDefault(a => a.OID == oid && a.IsTargetable);
Expand Down
122 changes: 65 additions & 57 deletions BossMod/BossModule/BossModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public IReadOnlyList<Actor> Enemies(uint oid)
private readonly List<BossComponent> _components = [];
public IReadOnlyList<BossComponent> Components => _components;
public T? FindComponent<T>() where T : BossComponent => _components.OfType<T>().FirstOrDefault();
private int componentCount;

public void ActivateComponent<T>() where T : BossComponent
{
Expand All @@ -48,6 +49,7 @@ public void ActivateComponent<T>() where T : BossComponent
}
var comp = New<T>.Create(this);
_components.Add(comp);
++componentCount;

// execute callbacks for existing state
foreach (var actor in WorldState.Actors)
Expand All @@ -70,11 +72,16 @@ public void ActivateComponent<T>() where T : BossComponent
public void DeactivateComponent<T>() where T : BossComponent
{
var count = _components.RemoveAll(x => x is T);
componentCount -= count;
if (count == 0)
ReportError(null, $"State {StateMachine.ActiveState?.ID:X}: Could not find a component of type {typeof(T)} to deactivate");
}

public void ClearComponents(Predicate<BossComponent> condition) => _components.RemoveAll(condition);
public void ClearComponents(Predicate<BossComponent> condition)
{
_components.RemoveAll(condition);
componentCount = 0;
}

protected BossModule(WorldState ws, Actor primary, WPos center, ArenaBounds bounds)
{
Expand Down Expand Up @@ -134,8 +141,8 @@ public void Update()
if (StateMachine.ActiveState != null)
{
UpdateModule();
foreach (var comp in _components)
comp.Update();
for (var i = 0; i < componentCount; ++i)
_components[i].Update();
}
}

Expand Down Expand Up @@ -169,8 +176,9 @@ public virtual void DrawArena(int pcSlot, Actor pc, bool haveRisks)
{
// draw background
DrawArenaBackground(pcSlot, pc);
foreach (var comp in _components)
comp.DrawArenaBackground(pcSlot, pc);

for (var i = 0; i < componentCount; ++i)
_components[i].DrawArenaBackground(pcSlot, pc);

// draw borders
if (WindowConfig.ShowBorder)
Expand All @@ -185,13 +193,13 @@ public virtual void DrawArena(int pcSlot, Actor pc, bool haveRisks)

// draw foreground
DrawArenaForeground(pcSlot, pc);
foreach (var comp in _components)
comp.DrawArenaForeground(pcSlot, pc);
for (var i = 0; i < componentCount; ++i)
_components[i].DrawArenaForeground(pcSlot, pc);
if (WindowConfig.ShowMeleeRangeIndicator)
{
var enemy = WorldState.Actors.FirstOrDefault(a => a.IsTargetable && !a.IsDead && !a.IsAlly && a.InCombat);
var enemy = WorldState.Actors.FirstOrDefault(a => !a.IsAlly && a.IsTargetable && !a.IsDead && a.InCombat);
if (enemy != null)
Arena.ZoneDonut(enemy.Position, enemy.HitboxRadius + 2.6f - 0.3f, enemy.HitboxRadius + 2.6f, Colors.MeleeRangeIndicator);
Arena.ZoneDonut(enemy.Position, enemy.HitboxRadius + 2.6f, enemy.HitboxRadius + 2.9f, Colors.MeleeRangeIndicator);
}
// draw enemies & player
DrawEnemies(pcSlot, pc);
Expand All @@ -201,35 +209,35 @@ public virtual void DrawArena(int pcSlot, Actor pc, bool haveRisks)
public BossComponent.TextHints CalculateHintsForRaidMember(int slot, Actor actor)
{
BossComponent.TextHints hints = [];
foreach (var comp in _components)
comp.AddHints(slot, actor, hints);
for (var i = 0; i < componentCount; ++i)
_components[i].AddHints(slot, actor, hints);
return hints;
}

public BossComponent.MovementHints CalculateMovementHintsForRaidMember(int slot, Actor actor)
{
BossComponent.MovementHints hints = [];
foreach (var comp in _components)
comp.AddMovementHints(slot, actor, hints);
for (var i = 0; i < componentCount; ++i)
_components[i].AddMovementHints(slot, actor, hints);
return hints;
}

public BossComponent.GlobalHints CalculateGlobalHints()
{
BossComponent.GlobalHints hints = [];
foreach (var comp in _components)
comp.AddGlobalHints(hints);
for (var i = 0; i < componentCount; ++i)
_components[i].AddGlobalHints(hints);
return hints;
}

public void CalculateAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints)
{
hints.PathfindMapCenter = Center;
hints.PathfindMapBounds = Bounds;
foreach (var comp in _components)
comp.AddAIHints(slot, actor, assignment, hints);
for (var i = 0; i < componentCount; ++i)
_components[i].AddAIHints(slot, actor, assignment, hints);
CalculateModuleAIHints(slot, actor, assignment, hints);
if (!WindowConfig.AllowAutomaticActions)
if (!WindowConfig.AllowAutomaticActions || AI.AIManager.Instance?.Beh != null)
hints.ActionsToExecute.Clear();
}

Expand All @@ -245,7 +253,7 @@ public void ReportError(BossComponent? comp, string message)

// called during update if module is not yet active, should return true if it is to be activated
// default implementation activates if primary target is both targetable and in combat
protected virtual bool CheckPull() { return PrimaryActor.IsTargetable && PrimaryActor.InCombat; }
protected virtual bool CheckPull() => PrimaryActor.IsTargetable && PrimaryActor.InCombat;

// called during update if module is active; should return true if module is to be reset (i.e. deleted and new instance recreated for same actor)
// default implementation never resets, but it's useful for outdoor bosses that can be leashed
Expand All @@ -259,7 +267,7 @@ protected virtual void CalculateModuleAIHints(int slot, Actor actor, PartyRolesC
// called at the very end to draw important enemies, default implementation draws primary actor
protected virtual void DrawEnemies(int pcSlot, Actor pc)
{
Arena.Actor(PrimaryActor, Colors.Enemy);
Arena.Actor(PrimaryActor);
}

private void DrawGlobalHints(BossComponent.GlobalHints hints)
Expand Down Expand Up @@ -312,7 +320,7 @@ private void DrawPartyMembers(int pcSlot, Actor pc)
{
var (prio, color) = CalculateHighestPriority(pcSlot, pc, slot, player);

bool isFocus = WorldState.Client.FocusTargetId == player.InstanceID;
var isFocus = WorldState.Client.FocusTargetId == player.InstanceID;
if (prio == BossComponent.PlayerPriority.Irrelevant && !WindowConfig.ShowIrrelevantPlayers && !(isFocus && WindowConfig.ShowFocusTargetPlayer))
continue;

Expand Down Expand Up @@ -355,10 +363,10 @@ private void DrawPartyMembers(int pcSlot, Actor pc)
{
uint color = 0;
var highestPrio = BossComponent.PlayerPriority.Irrelevant;
foreach (var s in _components)
for (var i = 0; i < componentCount; ++i)
{
uint subColor = 0;
var subPrio = s.CalcPriority(pcSlot, pc, playerSlot, player, ref subColor);
var subPrio = _components[i].CalcPriority(pcSlot, pc, playerSlot, player, ref subColor);
if (subPrio > highestPrio)
{
highestPrio = subPrio;
Expand All @@ -372,109 +380,109 @@ private void OnActorCreated(Actor actor)
{
_relevantEnemies.GetValueOrDefault(actor.OID)?.Add(actor);
if (actor.Type is not ActorType.Player and not ActorType.Pet and not ActorType.Chocobo and not ActorType.Buddy)
foreach (var comp in _components)
comp.OnActorCreated(actor);
for (var i = 0; i < componentCount; ++i)
_components[i].OnActorCreated(actor);
}

private void OnActorDestroyed(Actor actor)
{
_relevantEnemies.GetValueOrDefault(actor.OID)?.Remove(actor);
if (actor.Type is not ActorType.Player and not ActorType.Pet and not ActorType.Chocobo and not ActorType.Buddy)
foreach (var comp in _components)
comp.OnActorDestroyed(actor);
for (var i = 0; i < componentCount; ++i)
_components[i].OnActorDestroyed(actor);
}

private void OnActorCastStarted(Actor actor)
{
if (actor.Type is not ActorType.Player and not ActorType.Pet and not ActorType.Chocobo and not ActorType.Buddy && (actor.CastInfo?.IsSpell() ?? false))
foreach (var comp in _components)
comp.OnCastStarted(actor, actor.CastInfo);
for (var i = 0; i < componentCount; ++i)
_components[i].OnCastStarted(actor, actor.CastInfo);
}

private void OnActorCastFinished(Actor actor)
{
if (actor.Type is not ActorType.Player and not ActorType.Pet and not ActorType.Chocobo and not ActorType.Buddy && (actor.CastInfo?.IsSpell() ?? false))
foreach (var comp in _components)
comp.OnCastFinished(actor, actor.CastInfo);
for (var i = 0; i < componentCount; ++i)
_components[i].OnCastFinished(actor, actor.CastInfo);
}

private void OnActorTethered(Actor actor)
{
foreach (var comp in _components)
comp.OnTethered(actor, actor.Tether);
for (var i = 0; i < componentCount; ++i)
_components[i].OnTethered(actor, actor.Tether);
}

private void OnActorUntethered(Actor actor)
{
foreach (var comp in _components)
comp.OnUntethered(actor, actor.Tether);
for (var i = 0; i < componentCount; ++i)
_components[i].OnUntethered(actor, actor.Tether);
}

private void OnActorStatusGain(Actor actor, int index)
{
foreach (var comp in _components)
comp.OnStatusGain(actor, actor.Statuses[index]);
for (var i = 0; i < componentCount; ++i)
_components[i].OnStatusGain(actor, actor.Statuses[index]);
}

private void OnActorStatusLose(Actor actor, int index)
{
foreach (var comp in _components)
comp.OnStatusLose(actor, actor.Statuses[index]);
for (var i = 0; i < componentCount; ++i)
_components[i].OnStatusLose(actor, actor.Statuses[index]);
}

private void OnActorIcon(Actor actor, uint iconID, ulong targetID)
{
foreach (var comp in _components)
comp.OnEventIcon(actor, iconID, targetID);
for (var i = 0; i < componentCount; ++i)
_components[i].OnEventIcon(actor, iconID, targetID);
}

private void OnActorCastEvent(Actor actor, ActorCastEvent cast)
{
if (actor.Type is not ActorType.Player and not ActorType.Pet and not ActorType.Chocobo and not ActorType.Buddy && cast.IsSpell())
foreach (var comp in _components)
comp.OnEventCast(actor, cast);
for (var i = 0; i < componentCount; ++i)
_components[i].OnEventCast(actor, cast);
}

private void OnActorEState(Actor actor, ushort state)
{
foreach (var comp in _components)
comp.OnActorEState(actor, state);
for (var i = 0; i < componentCount; ++i)
_components[i].OnActorEState(actor, state);
}

private void OnActorEAnim(Actor actor, ushort p1, ushort p2)
{
var state = ((uint)p1 << 16) | p2;
foreach (var comp in _components)
comp.OnActorEAnim(actor, state);
for (var i = 0; i < componentCount; ++i)
_components[i].OnActorEAnim(actor, state);
}

private void OnActorPlayActionTimelineEvent(Actor actor, ushort id)
{
foreach (var comp in _components)
comp.OnActorPlayActionTimelineEvent(actor, id);
for (var i = 0; i < componentCount; ++i)
_components[i].OnActorPlayActionTimelineEvent(actor, id);
}

private void OnActorNpcYell(Actor actor, ushort id)
{
foreach (var comp in _components)
comp.OnActorNpcYell(actor, id);
for (var i = 0; i < componentCount; ++i)
_components[i].OnActorNpcYell(actor, id);
}

private void OnActorModelStateChange(Actor actor)
{
foreach (var comp in _components)
comp.OnActorModelStateChange(actor, actor.ModelState.ModelState, actor.ModelState.AnimState1, actor.ModelState.AnimState2);
for (var i = 0; i < componentCount; ++i)
_components[i].OnActorModelStateChange(actor, actor.ModelState.ModelState, actor.ModelState.AnimState1, actor.ModelState.AnimState2);
}

private void OnEnvControl(WorldState.OpEnvControl op)
{
foreach (var comp in _components)
comp.OnEventEnvControl(op.Index, op.State);
for (var i = 0; i < componentCount; ++i)
_components[i].OnEventEnvControl(op.Index, op.State);
}

private void OnDirectorUpdate(WorldState.OpDirectorUpdate op)
{
foreach (var comp in _components)
comp.OnEventDirectorUpdate(op.UpdateID, op.Param1, op.Param2, op.Param3, op.Param4);
for (var i = 0; i < componentCount; ++i)
_components[i].OnEventDirectorUpdate(op.UpdateID, op.Param1, op.Param2, op.Param3, op.Param4);
}
}
3 changes: 2 additions & 1 deletion BossMod/BossModule/BossModuleMainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ public override void Draw()
}
else
{
foreach (var m in _mgr.LoadedModules)
for (var i = 0; i < _mgr.LoadedModules.Count; ++i)
{
var m = _mgr.LoadedModules[i];
var oidType = BossModuleRegistry.FindByOID(m.PrimaryActor.OID)?.ObjectIDType;
var oidName = oidType?.GetEnumName(m.PrimaryActor.OID);
if (ImGui.Button($"{m.GetType()} ({m.PrimaryActor.InstanceID:X} '{m.PrimaryActor.Name}' {oidName})"))
Expand Down
Loading

0 comments on commit 5b37127

Please sign in to comment.