-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP deep dungeon auto clear modules #580
Merged
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
a8e6498
Auto-engage preset
xanunderscore 5805fe7
deep dungeon modules
xanunderscore 5f95e89
add maps
xanunderscore 7998936
update rotations
xanunderscore 517c914
forgot to display da window
xanunderscore de433e1
oh whoops
xanunderscore cef92dd
minor fixes
xanunderscore 0259655
oopC
xanunderscore 03b4d45
add los check to amex
xanunderscore 8418449
basexan fixes
xanunderscore 2a1e048
interaction cleanup stuff
xanunderscore 7f5a570
lol?
xanunderscore 4910879
add transform statuses
xanunderscore df6a048
fix multi charge stuff
xanunderscore b1747f8
one more fix
xanunderscore 203614e
Merge branch 'master' of https://github.com/awgil/ffxiv_bossmod into wip
xanunderscore 32156d3
maybe?
xanunderscore dea1e4a
surely
xanunderscore 2d96749
specify version
xanunderscore ad54ea4
mark generic AI functionality as usable while transformed
xanunderscore d7573c8
minify walls file to reduce PR sive
xanunderscore 4efc8ac
Merge remote-tracking branch 'origin/patch-19' into wip
xanunderscore 280ead8
github stuff
xanunderscore 9600985
fix some interact stuff
xanunderscore 8d23034
clarify comment
xanunderscore c3ed5bc
fix autohint forbidden zone size
xanunderscore 643c70e
add vscode config stuff back in
xanunderscore a1d207e
vsc stuff fix
xanunderscore fcbf212
prevent preemptive use of potion for % based damage
xanunderscore 461c8d4
bomb enrage
xanunderscore 181677b
this doesnt work i guess whatever
xanunderscore ed78262
remove leftover shit
xanunderscore 19fb91e
leftover from bmx
xanunderscore ed99643
remove thing from other pr
xanunderscore File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--- | ||
name: Rotation bug report | ||
about: Unexpected rotation behavior, crash, error in logs, etc. | ||
title: "[BUG] L100 JobNameHere: Issue Summary Here" | ||
labels: '' | ||
assignees: '' | ||
|
||
--- | ||
|
||
**Bug description** | ||
e.g. "Reaper using Enshroud too early before raid buffs" | ||
|
||
**Replay info** - only one choice is needed | ||
- [ ] I have a(n anonymized) video recording of this interaction | ||
- [ ] I have a replay file and I will DM it to you upon request (or just post it here if I don't care about privacy) | ||
- [ ] I can attach my `/xllog` from when the issue occurred | ||
- [ ] I have a screenshot of or link to xivanalysis |
10 changes: 10 additions & 0 deletions
10
.github/ISSUE_TEMPLATE/something-that-isn-t-a-rotation-bug.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
name: Something that isn't a rotation bug | ||
about: Not a rotation bug | ||
title: '' | ||
labels: '' | ||
assignees: '' | ||
|
||
--- | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
namespace BossMod.Autorotation.xan; | ||
|
||
public class DeepDungeonAI(RotationModuleManager manager, Actor player) : AIBase(manager, player) | ||
{ | ||
public enum Track { Potion, Kite } | ||
|
||
public static RotationModuleDefinition Definition() | ||
{ | ||
var def = new RotationModuleDefinition("Deep Dungeon AI", "Utilities for deep dungeon - potion/pomander user", "AI (xan)", "xan", RotationModuleQuality.Basic, new BitMask(~0ul), 100, CanUseWhileRoleplaying: true); | ||
|
||
def.AbilityTrack(Track.Potion, "Potion"); | ||
def.AbilityTrack(Track.Kite, "Kite enemies"); | ||
|
||
return def; | ||
} | ||
|
||
enum OID : uint | ||
{ | ||
Unei = 0x3E1A, | ||
} | ||
|
||
enum Transformation : uint | ||
{ | ||
None, | ||
Manticore, | ||
Succubus, | ||
Kuribu, | ||
Dreadnaught | ||
} | ||
|
||
enum SID : uint | ||
{ | ||
Transfiguration = 565, | ||
ItemPenalty = 1094, | ||
} | ||
|
||
public override void Execute(StrategyValues strategy, ref Actor? primaryTarget, float estimatedAnimLockDelay, bool isMoving) | ||
{ | ||
if (World.DeepDungeon.DungeonId == 0) | ||
return; | ||
|
||
var transformation = Transformation.None; | ||
if (Player.FindStatus(SID.Transfiguration) is { } status) | ||
{ | ||
transformation = (status.Extra & 0xFF) switch | ||
{ | ||
42 => Transformation.Manticore, | ||
43 => Transformation.Succubus, | ||
49 => Transformation.Kuribu, | ||
244 => Transformation.Dreadnaught, | ||
_ => Transformation.None | ||
}; | ||
} | ||
|
||
if (transformation != Transformation.None) | ||
{ | ||
DoTransformActions(strategy, primaryTarget, transformation); | ||
return; | ||
} | ||
|
||
if (IsRanged && !Player.InCombat && primaryTarget is Actor target && !target.InCombat && !target.IsAlly) | ||
// bandaid fix to help deal with constant LOS issues | ||
Hints.GoalZones.Add(Hints.GoalSingleTarget(target, 3, 0.1f)); | ||
|
||
SetupKiteZone(strategy, primaryTarget); | ||
|
||
if (Player.FindStatus(SID.ItemPenalty) != null) | ||
return; | ||
|
||
var (regenAction, potAction) = World.DeepDungeon.DungeonId switch | ||
{ | ||
DeepDungeonState.DungeonType.POTD => (ActionDefinitions.IDSustainingPotion, ActionDefinitions.IDMaxPotion), | ||
DeepDungeonState.DungeonType.HOH => (ActionDefinitions.IDEmpyreanPotion, ActionDefinitions.IDSuperPotion), | ||
DeepDungeonState.DungeonType.EO => (ActionDefinitions.IDOrthosPotion, ActionDefinitions.IDHyperPotion), | ||
_ => (default, default) | ||
}; | ||
|
||
if (regenAction != default && ShouldPotion(strategy)) | ||
Hints.ActionsToExecute.Push(regenAction, Player, ActionQueue.Priority.Medium); | ||
|
||
if (potAction != default && Player.HPRatio <= 0.3f) | ||
Hints.ActionsToExecute.Push(potAction, Player, ActionQueue.Priority.VeryHigh); | ||
} | ||
|
||
private bool IsRanged => Player.Class.GetRole() is Role.Ranged or Role.Healer; | ||
|
||
private static readonly HashSet<uint> NoMeleeAutos = [ | ||
// hoh | ||
0x22C3, // heavenly onibi | ||
0x22C5, // heavenly dhruva | ||
0x22C6, // heavenly sai taisui | ||
0x22DC, // heavenly dogu | ||
0x22DE, // heavenly ganseki | ||
0x22ED, // heavenly kongorei | ||
0x22EF, // heavenly maruishi | ||
0x22F3, // heavenly rachimonai | ||
0x22FC, // heavenly doguzeri | ||
0x2320, // heavenly nuppeppo (WHM) (uses stone) | ||
|
||
// orthos | ||
0x3DCC, // orthos imp | ||
0x3DCE, // orthos fachan | ||
0x3DD2, // orthos water sprite | ||
0x3DD4, // orthos microsystem | ||
0x3DD5, // orthosystem β | ||
0x3DE0, // orthodemolisher | ||
0x3DE2, // orthodroid | ||
0x3DFD, // orthos apa | ||
0x3E10, // orthos ice sprite | ||
0x3E5C, // orthos ahriman | ||
0x3E62, // orthos abyss | ||
0x3E63, // orthodrone | ||
0x3E64, // orthosystem γ | ||
0x3E66, // orthosystem α | ||
]; | ||
|
||
private void SetupKiteZone(StrategyValues strategy, Actor? primaryTarget) | ||
{ | ||
if (!IsRanged || primaryTarget == null || !Player.InCombat || !strategy.Enabled(Track.Kite)) | ||
return; | ||
|
||
// wew | ||
if (NoMeleeAutos.Contains(primaryTarget.OID)) | ||
return; | ||
|
||
// assume we don't need to kite if mob is busy casting (TODO: some mob spells can be cast while moving, maybe there's a column in sheets for it) | ||
if (primaryTarget.CastInfo != null) | ||
return; | ||
|
||
float maxRange = 25; | ||
float maxKite = 9; | ||
|
||
var primaryPos = primaryTarget.Position; | ||
var total = maxRange + Player.HitboxRadius + primaryTarget.HitboxRadius; | ||
var totalKite = maxKite + Player.HitboxRadius + primaryTarget.HitboxRadius; | ||
float goalFactor = 0.05f; | ||
Hints.GoalZones.Add(pos => | ||
{ | ||
var dist = (pos - primaryPos).Length(); | ||
return dist <= total && dist >= totalKite ? goalFactor : 0; | ||
}); | ||
} | ||
|
||
private void DoTransformActions(StrategyValues strategy, Actor? primaryTarget, Transformation t) | ||
{ | ||
if (primaryTarget == null) | ||
return; | ||
|
||
Func<WPos, float> goal; | ||
ActionID attack; | ||
int numTargets; | ||
var castTime = 0f; | ||
|
||
switch (t) | ||
{ | ||
case Transformation.Manticore: | ||
goal = Hints.GoalSingleTarget(primaryTarget, 3); | ||
numTargets = 1; | ||
attack = ActionID.MakeSpell(Roleplay.AID.Pummel); | ||
break; | ||
case Transformation.Succubus: | ||
goal = Hints.GoalSingleTarget(primaryTarget, 25); | ||
numTargets = Hints.NumPriorityTargetsInAOECircle(primaryTarget.Position, 5); | ||
attack = ActionID.MakeSpell(Roleplay.AID.VoidFireII); | ||
castTime = 2.5f; | ||
break; | ||
case Transformation.Kuribu: | ||
// heavenly judge is ground targeted | ||
goal = Hints.GoalSingleTarget(primaryTarget.Position, 25); | ||
numTargets = Hints.NumPriorityTargetsInAOECircle(primaryTarget.Position, 6); | ||
attack = ActionID.MakeSpell(Roleplay.AID.HeavenlyJudge); | ||
castTime = 2.5f; | ||
break; | ||
case Transformation.Dreadnaught: | ||
goal = Hints.GoalSingleTarget(primaryTarget, 3); | ||
numTargets = 1; | ||
attack = ActionID.MakeSpell(Roleplay.AID.Rotosmash); | ||
break; | ||
default: | ||
return; | ||
} | ||
|
||
if (numTargets == 0) | ||
return; | ||
|
||
Hints.GoalZones.Add(goal); | ||
Hints.ActionsToExecute.Push(attack, primaryTarget, ActionQueue.Priority.High, targetPos: primaryTarget.PosRot.XYZ(), castTime: castTime - 0.5f); | ||
} | ||
|
||
private bool ShouldPotion(StrategyValues strategy) | ||
{ | ||
if (World.Actors.Any(w => w.OID == (uint)OID.Unei) || !strategy.Enabled(Track.Potion)) | ||
return false; | ||
|
||
var ratio = Player.ClassCategory is ClassCategory.Tank ? 0.4f : 0.6f; | ||
return Player.PredictedHPRatio < ratio && Player.FindStatus(648) == null && Player.InCombat; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I don't understand this change... Can you elaborate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have the level 94 trait Enhanced Multiweapon on machinist, Drill stops being affected by skill speed/haste/slows, so the separate cooldown is always 20s and using both charges will set it to 40. before then it is affected by haste despite still technically having multiple charges, so like in Palace of the Dead, where you have some inherent skillspeed from the aetherpool gear, the single charge cooldown of Drill is 19.2s and using the one charge you have at that level will set the cooldown to 38.4s. also, if you use a single charge of drill at these levels while slowed or hasted, you can get a cooldown total of like 32 or 54 seconds, and checking Cooldown against that gives you incorrect results.
so what this line is doing is just dividing cdg.Total by the maximum number of charges of the ability, which SHOULD give us the effective single charge CD.
i do not think it's possible to accurately calculate this information based on only the user's stats, because the total cooldown is basically snapshotting the stats we had when the skill was used, which may not be the ones we have now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then why can't we just always return
cdg.Total / MaxChargesAtCap() - cdg.Elapsed
, clamped to 0? Why do we need IsGCD etc checks here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that should work in theory yeah. this code was originally only checking for specifically Drill, since it's the only action that is affected and i wanted to avoid introducing other bugs, but it seemed to work fine in practice