Skip to content

Commit

Permalink
Merge pull request #584 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
merge vbm + merge fixes
  • Loading branch information
CarnifexOptimus authored Jan 29, 2025
2 parents 66c20c6 + 7e1ecfe commit f0664d5
Show file tree
Hide file tree
Showing 232 changed files with 9,007 additions and 2,095 deletions.
39 changes: 37 additions & 2 deletions BossMod/ActionQueue/ActionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,30 @@ public enum ActionTargets
All = (1 << 9) - 1,
}

// some debuffs prevent specific categories of action - amnesia, silence, pacification, etc
public enum ActionCategory : byte
{
None,
Autoattack,
Spell,
Weaponskill,
Ability,
Item,
DoLAbility,
DoHAbility,
Event,
LimitBreak9,
System10,
System11,
Mount,
Special,
ItemManipulation,
LimitBreak15,
Unk1,
Artillery,
Unk2
}

// used for BLM calculations and possibly BLU optimization
public enum ActionAspect : byte
{
Expand Down Expand Up @@ -47,6 +71,7 @@ public sealed record class ActionDefinition(ActionID ID)
public ActionTargets AllowedTargets;
public float Range; // 0 for self-targeted abilities
public float CastTime; // 0 for instant-cast; can be adjusted by a number of factors (TODO: add functor)
public ActionCategory Category;
public int MainCooldownGroup = -1;
public int ExtraCooldownGroup = -1;
public float Cooldown; // for single charge (if multi-charge action); can be adjusted by a number of factors (TODO: add functor)
Expand Down Expand Up @@ -194,9 +219,13 @@ private ActionDefinitions()
RegisterPotion(IDPotionInt);
RegisterPotion(IDPotionMnd);

// bozja actions
// special content actions - bozja, deep dungeons, etc
for (var i = BozjaHolsterID.None + 1; i < BozjaHolsterID.Count; ++i)
RegisterBozja(i);
for (var i = PomanderID.Safety; i < PomanderID.Count; ++i)
RegisterDeepDungeon(new(ActionType.Pomander, (uint)i));
for (var i = 1u; i <= 3; i++)
RegisterDeepDungeon(new(ActionType.Magicite, i));
}

public void Dispose()
Expand Down Expand Up @@ -340,7 +369,8 @@ public void RegisterSpell(ActionID aid, bool isPhysRanged = false, float instant
MaxChargesBase = SpellBaseMaxCharges(data),
InstantAnimLock = instantAnimLock,
CastAnimLock = castAnimLock,
IsRoleAction = data.IsRoleAction
IsRoleAction = data.IsRoleAction,
Category = (ActionCategory)data.ActionCategory.RowId
};
Register(aid, def);
}
Expand Down Expand Up @@ -395,6 +425,11 @@ private void RegisterBozja(BozjaHolsterID id)
}
}

private void RegisterDeepDungeon(ActionID id)
{
_definitions[id] = new(id) { AllowedTargets = ActionTargets.Self, InstantAnimLock = 2.1f };
}

// hardcoded mechanic implementations
public void RegisterChargeIncreaseTrait(ActionID aid, uint traitId)
{
Expand Down
1 change: 1 addition & 0 deletions BossMod/ActionQueue/Casters/SMN.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public enum SID : uint
GarudasFavor = 2725, // applied by Summon Garuda II to self
RubysGlimmer = 3873, // applied by Searing Light to self
RefulgentLux = 3874, // applied by Summon Solar Bahamut to self
CrimsonStrikeReady = 4403, // applied by Crimson Cyclone to self

//Shared
Addle = ClassShared.SID.Addle, // applied by Addle to target
Expand Down
12 changes: 12 additions & 0 deletions BossMod/ActionQueue/ClassShared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ public enum SID : uint
Addle = 1203, // applied by Addle to target
Swiftcast = 167, // applied by Swiftcast to self
Raise = 148, // applied by Raise to target

// Bozja
LostChainspell = 2560, // instant cast

MagicBurst = 1652, // magic damage buff
BannerOfNobleEnds = 2326, // damage buff + healing disable
BannerOfHonoredSacrifice = 2327, // damage buff + hp drain
LostFontOfPower = 2346, // damage/crit buff
ClericStance = 2484, // damage buff (from seraph strike)
LostExcellence = 2564, // damage buff + invincibility
Memorable = 2565, // damage buff
BloodRush = 2567, // damage buff + ability haste
#endregion

#region PvP
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Legacy/LegacyBRD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public LegacyBRD(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
if (_state.AnimationLockDelay < 0.1f)
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Legacy/LegacyDNC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public LegacyDNC(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.AnimationLockDelay = Math.Max(0.1f, _state.AnimationLockDelay);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Legacy/LegacyDRG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public LegacyDRG(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);

Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Legacy/LegacyGNB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public LegacyGNB(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.HaveTankStance = Player.FindStatus(GNB.SID.RoyalGuard) != null;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Legacy/LegacyRPR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public LegacyRPR(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.HasSoulsow = Player.FindStatus(RPR.SID.Soulsow) != null;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Legacy/LegacyWAR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public LegacyWAR(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.HaveTankStance = Player.FindStatus(WAR.SID.Defiance) != null;
Expand Down
99 changes: 99 additions & 0 deletions BossMod/Autorotation/MiscAI/AutoFarm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
namespace BossMod.Autorotation.MiscAI;

public sealed class AutoFarm(RotationModuleManager manager, Actor player) : RotationModule(manager, player)
{
public enum Track { General, Fate, Specific }
public enum GeneralStrategy { AllowPull, FightBack, Aggressive, Passive }
public enum PriorityStrategy { None, Prioritize }

public static RotationModuleDefinition Definition()
{
RotationModuleDefinition res = new("Misc AI: Automatic farming", "Make sure this is ordered before standard rotation modules!", "Misc", "veyn", RotationModuleQuality.Basic, new(~0ul), 1000);

res.Define(Track.General).As<GeneralStrategy>("General")
.AddOption(GeneralStrategy.AllowPull, "AllowPull", "Automatically engage any mobs that are in combat with player; if player is not in combat, pull new mobs")
.AddOption(GeneralStrategy.FightBack, "FightBack", "Automatically engage any mobs that are in combat with player, but don't pull new mobs")
.AddOption(GeneralStrategy.Aggressive, "Aggressive", "Aggressively pull all mobs that are not yet in combat")
.AddOption(GeneralStrategy.Passive, "Passive", "Do nothing");

res.Define(Track.Fate).As<PriorityStrategy>("FATE")
.AddOption(PriorityStrategy.None, "None", "Do not do anything about fate mobs")
.AddOption(PriorityStrategy.Prioritize, "Prioritize", "Prioritize mobs in active fate");

res.Define(Track.Specific).As<PriorityStrategy>("Specific")
.AddOption(PriorityStrategy.None, "None", "Do not do anything special")
.AddOption(PriorityStrategy.Prioritize, "Prioritize", "Prioritize specific mobs by targeting criterion");

return res;
}

public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
var generalStrategy = strategy.Option(Track.General).As<GeneralStrategy>();
if (generalStrategy == GeneralStrategy.Passive)
return;

var allowPulling = generalStrategy switch
{
GeneralStrategy.AllowPull => !Player.InCombat,
GeneralStrategy.Aggressive => true,
_ => false
};

Actor? closestTargetToSwitchTo = null; // non-null if we bump any priorities
float closestTargetDistSq = float.MaxValue;
void prioritize(AIHints.Enemy e, int prio)
{
e.Priority = prio;

var distSq = (e.Actor.Position - Player.Position).LengthSq();
if (distSq < closestTargetDistSq)
{
closestTargetToSwitchTo = e.Actor;
closestTargetDistSq = distSq;
}
}

// first deal with pulling new enemies
if (allowPulling)
{
if (World.Client.ActiveFate.ID != 0 && Player.Level <= Service.LuminaRow<Lumina.Excel.Sheets.Fate>(World.Client.ActiveFate.ID)?.ClassJobLevelMax && strategy.Option(Track.Fate).As<PriorityStrategy>() == PriorityStrategy.Prioritize)
{
foreach (var e in Hints.PotentialTargets)
{
if (e.Actor.FateID == World.Client.ActiveFate.ID && e.Priority == AIHints.Enemy.PriorityUndesirable)
{
prioritize(e, 1);
}
}
}

var specific = strategy.Option(Track.Specific);
if (specific.As<PriorityStrategy>() == PriorityStrategy.Prioritize && Hints.FindEnemy(ResolveTargetOverride(specific.Value)) is var target && target != null)
{
prioritize(target, 2);
}
}

// if we're not going to pull anyone, but we are already in combat and not targeting aggroed enemy, find one to target
if (closestTargetToSwitchTo == null && Player.InCombat && !(primaryTarget?.AggroPlayer ?? false))
{
foreach (var e in Hints.PotentialTargets)
{
if (e.Actor.AggroPlayer)
{
prioritize(e, 3);
}
}
}

// if we have target to attack, do that
if (closestTargetToSwitchTo != null)
{
// if we've updated any priorities, we need to re-sort target array
Hints.PotentialTargets.SortByReverse(x => x.Priority);
Hints.HighestPotentialTargetPriority = Math.Max(0, Hints.PotentialTargets[0].Priority);
primaryTarget = Hints.ForcedTarget = closestTargetToSwitchTo;
}
}
}
3 changes: 1 addition & 2 deletions BossMod/Autorotation/MiscAI/StayCloseToTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ namespace BossMod.Autorotation.MiscAI;

public sealed class StayCloseToTarget(RotationModuleManager manager, Actor player) : RotationModule(manager, player)
{

public enum Tracks
{
Range
Expand All @@ -28,7 +27,7 @@ public static RotationModuleDefinition Definition()
return def;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
if (primaryTarget != null)
Hints.GoalZones.Add(Hints.GoalSingleTarget(primaryTarget.Position, (strategy.Option(Tracks.Range).Value.Option + 10f) / 10f + primaryTarget.HitboxRadius, 0.5f));
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/MiscAI/StayWithinLeylines.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static RotationModuleDefinition Definition()
return def;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving)
{
bool InLeyLines = Player.FindStatus(BLM.SID.CircleOfPower) != null;

Expand Down
15 changes: 4 additions & 11 deletions BossMod/Autorotation/PlanDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ public PlanDatabase(string rootPath)
{
try
{
using var json = Serialization.ReadJson(f.FullName);
var version = json.RootElement.GetProperty("version").GetInt32();
var payload = json.RootElement.GetProperty("payload");
var plan = payload.Deserialize<Plan>(serOptions);
var data = PlanPresetConverter.PlanSchema.Load(f);
using var json = data.document;
var plan = data.payload.Deserialize<Plan>(serOptions);
if (plan != null)
{
plan.Guid = f.Name[..^5];
Expand Down Expand Up @@ -204,13 +203,7 @@ private void SavePlan(Plan plan)
var filename = $"{_planStore.FullName}/{plan.Guid}.json";
try
{
using var fstream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
using var jwriter = Serialization.WriteJson(fstream);
jwriter.WriteStartObject();
jwriter.WriteNumber("version", 0);
jwriter.WritePropertyName("payload");
JsonSerializer.Serialize(jwriter, plan, Serialization.BuildSerializationOptions());
jwriter.WriteEndObject();
PlanPresetConverter.PlanSchema.Save(new(filename), jwriter => JsonSerializer.Serialize(jwriter, plan, Serialization.BuildSerializationOptions()));
Service.Log($"Plan saved successfully to '{filename}'");
}
catch (Exception ex)
Expand Down
Loading

0 comments on commit f0664d5

Please sign in to comment.