diff --git a/RotationSolver.Basic/Actions/ActionBasicInfo.cs b/RotationSolver.Basic/Actions/ActionBasicInfo.cs index 4ef37d51b..578bd4c42 100644 --- a/RotationSolver.Basic/Actions/ActionBasicInfo.cs +++ b/RotationSolver.Basic/Actions/ActionBasicInfo.cs @@ -5,7 +5,10 @@ namespace RotationSolver.Basic.Actions; -public struct ActionBasicInfo +/// +/// The action info for the . +/// +public readonly struct ActionBasicInfo { internal static readonly uint[] ActionsNoNeedCasting = [ @@ -15,25 +18,65 @@ public struct ActionBasicInfo ]; private readonly IBaseAction _action; + + /// + /// The name of the action. + /// public readonly string Name => _action.Action.Name; + + /// + /// The ID of the action. + /// public readonly uint ID => _action.Action.RowId; + + /// + /// The icon of the action. + /// public readonly uint IconID => ID == (uint)ActionID.SprintPvE ? 104u : _action.Action.Icon; + /// + /// The adjust id of this action. + /// public readonly uint AdjustedID => (uint)Service.GetAdjustedActionId((ActionID)ID); + /// + /// The attack type of this action. + /// public readonly AttackType AttackType => (AttackType)(_action.Action.AttackType.Value?.RowId ?? byte.MaxValue); + /// + /// The aspect of this action. + /// + public Aspect Aspect { get; } + + /// + /// The animation lock time of this action. + /// public readonly float AnimationLockTime => OtherConfiguration.AnimationLockTime?.TryGetValue(AdjustedID, out var time) ?? false ? time : 0.6f; + /// + /// The level of this action. + /// public readonly byte Level => _action.Action.ClassJobLevel; + + /// + /// If this action is enough level to use. + /// public readonly bool EnoughLevel => Player.Level >= Level; + /// + /// If this action a pvp action. + /// public readonly bool IsPvP => _action.Action.IsPvP; + /// /// Casting time. /// public readonly unsafe float CastTime => ((ActionID)AdjustedID).GetCastTime(); + /// + /// How many mp does this action needs. + /// public readonly unsafe uint MPNeed { get @@ -47,6 +90,9 @@ public readonly unsafe uint MPNeed } } + /// + /// Is thia action on the slot. + /// public readonly bool IsOnSlot { get @@ -64,12 +110,32 @@ public readonly bool IsOnSlot return IsPvP == DataCenter.Territory?.IsPvpZone; } } + + /// + /// Is this action is a lb action. + /// public bool IsLimitBreak { get; } + + /// + /// Is this action a general gcd. + /// public bool IsGeneralGCD { get; } + + /// + /// Is this action a real gcd. + /// public bool IsRealGCD { get; } + + /// + /// Is this action a duty action. + /// public bool IsDutyAction { get; } - public Aspect Aspect { get; } + /// + /// The basic way to create a basic info + /// + /// the action + /// if it is a duty action. public ActionBasicInfo(IBaseAction action, bool isDutyAction) { _action = action; @@ -81,7 +147,7 @@ public ActionBasicInfo(IBaseAction action, bool isDutyAction) Aspect = (Aspect)_action.Action.Aspect; } - internal readonly bool BasicCheck(bool skipStatusProvideCheck, bool skipCombo, bool ignoreCastingCheck) + internal readonly bool BasicCheck(bool skipStatusProvideCheck, bool skipComboCheck, bool skipCastingCheck) { if (!_action.Config.IsEnabled || !IsOnSlot) return false; @@ -112,7 +178,7 @@ internal readonly bool BasicCheck(bool skipStatusProvideCheck, bool skipCombo, b if (CustomRotation.LimitBreakLevel <= 1) return false; } - if (!skipCombo && IsGeneralGCD) + if (!skipComboCheck && IsGeneralGCD) { if (!CheckForCombo()) return false; } @@ -134,7 +200,7 @@ internal readonly bool BasicCheck(bool skipStatusProvideCheck, bool skipCombo, b //Is knocking back. if (DateTime.Now > DataCenter.KnockbackStart && DateTime.Now < DataCenter.KnockbackFinished) return false; - if (DataCenter.NoPoslock && DataCenter.IsMoving && !ignoreCastingCheck) return false; + if (DataCenter.NoPoslock && DataCenter.IsMoving && !skipCastingCheck) return false; } if (IsGeneralGCD && _action.Setting.StatusProvide?.Length > 0 && _action.Setting.IsFriendly diff --git a/RotationSolver.Basic/Actions/ActionConfig.cs b/RotationSolver.Basic/Actions/ActionConfig.cs index 695214103..4ea840efc 100644 --- a/RotationSolver.Basic/Actions/ActionConfig.cs +++ b/RotationSolver.Basic/Actions/ActionConfig.cs @@ -6,19 +6,48 @@ public class ActionConfig() { private bool _isEnable = true; + + /// + /// If this action is enabled. + /// public bool IsEnabled { get => IBaseAction.ForceEnable || _isEnable; set => _isEnable = value; } + /// + /// Should check the status for this action. + /// + public bool ShouldCheckStatus { get; set; } = true; + + /// + /// The status count in gcd for adding the status. + /// public byte StatusGcdCount { get; set; } = 2; + + /// + /// The aoe count of this action. + /// public byte AoeCount { get; set; } = 3; + + /// + /// How many ttk should this action use. + /// public float TimeToKill { get; set; } = 0; - public bool ShouldCheckStatus { get; set; } = true; + /// + /// The heal ratio for the auto heal. + /// public float AutoHealRatio { get; set; } = 0.8f; + /// + /// Is this action in the cd window. + /// public bool IsInCooldown { get; set; } = true; + + /// + /// Is this action should be a mistake action. + /// public bool IsInMistake { get; set; } } diff --git a/RotationSolver.Basic/Actions/ActionCooldownInfo.cs b/RotationSolver.Basic/Actions/ActionCooldownInfo.cs index 201169214..ddcdb4a0a 100644 --- a/RotationSolver.Basic/Actions/ActionCooldownInfo.cs +++ b/RotationSolver.Basic/Actions/ActionCooldownInfo.cs @@ -2,9 +2,17 @@ using FFXIVClientStructs.FFXIV.Client.Game; namespace RotationSolver.Basic.Actions; + +/// +/// The action cooldown information. +/// public readonly struct ActionCooldownInfo : ICooldown { private readonly IBaseAction _action; + + /// + /// The cd group. + /// public byte CoolDownGroup { get; } unsafe RecastDetail* CoolDownDetail => ActionIdHelper.GetCoolDownDetail(CoolDownGroup); @@ -61,6 +69,10 @@ namespace RotationSolver.Basic.Actions; float RecastTimeElapsedOneChargeRaw => RecastTimeElapsedRaw % RecastTimeOneChargeRaw; + /// + /// The default constructor. + /// + /// the action. public ActionCooldownInfo(IBaseAction action) { _action = action; diff --git a/RotationSolver.Basic/Actions/ActionSetting.cs b/RotationSolver.Basic/Actions/ActionSetting.cs index 3739bacb0..1c80ef255 100644 --- a/RotationSolver.Basic/Actions/ActionSetting.cs +++ b/RotationSolver.Basic/Actions/ActionSetting.cs @@ -5,16 +5,51 @@ /// public class ActionSetting() { + /// + /// The Ninjutsu action of this action. + /// public IBaseAction[]? Ninjutsu { get; set; } = null; + + /// + /// The override of the . + /// public Func? MPOverride { get; set; } = null; + + /// + /// Is this action in the melee range. + /// public bool IsMeleeRange { get; set; } = false; + + /// + /// Is this status is added by the plyer. + /// public bool StatusFromSelf { get; set; } = true; + + /// + /// The status that it provides to the target. + /// public StatusID[]? TargetStatusProvide { get; set; } = null; + + /// + /// The status that it needs on the target. + /// public StatusID[]? TargetStatusNeed { get; set; } = null; + + /// + /// Can the target be targeted. + /// public Func CanTarget { get; set; } = t => true; + + /// + /// The additional not combo ids. + /// public ActionID[]? ComboIdsNot { get; set; } + /// + /// The additional combo ids. + /// public ActionID[]? ComboIds { get; set; } + /// /// Status that this action provides. /// @@ -25,14 +60,25 @@ public class ActionSetting() /// public StatusID[]? StatusNeed { get; set; } = null; + /// + /// Your custom rotation check for your rotation. + /// public Func? RotationCheck { get; set; } = null; + internal Func? ActionCheck { get; set; } = null; internal Func? CreateConfig { get; set; } = null; + /// + /// Is this action friendly. + /// public bool IsFriendly { get; set; } private TargetType _type = TargetType.Big; + + /// + /// The strategy to target the target. + /// public TargetType TargetType { get @@ -56,8 +102,14 @@ public TargetType TargetType set => _type = value; } + /// + /// The enemy positional for this action. + /// public EnemyPositional EnemyPositional { get; set; } = EnemyPositional.None; + /// + /// Should end the special. + /// public bool EndSpecial { get; set; } } diff --git a/RotationSolver.Basic/Actions/ActionTargetInfo.cs b/RotationSolver.Basic/Actions/ActionTargetInfo.cs index ccbbc0d45..322def838 100644 --- a/RotationSolver.Basic/Actions/ActionTargetInfo.cs +++ b/RotationSolver.Basic/Actions/ActionTargetInfo.cs @@ -9,17 +9,31 @@ namespace RotationSolver.Basic.Actions; -public struct ActionTargetInfo(IBaseAction _action) +/// +/// The target info +/// +/// the input action. +public struct ActionTargetInfo(IBaseAction action) { - public readonly bool TargetArea => _action.Action.TargetArea; - - public readonly float Range => ActionManager.GetActionRange(_action.Info.ID); + /// + /// The range of this action. + /// + public readonly float Range => ActionManager.GetActionRange(action.Info.ID); - public readonly float EffectRange => (ActionID)_action.Info.ID == ActionID.LiturgyOfTheBellPvE ? 20 : _action.Action.EffectRange; + /// + /// The effect range of this action. + /// + public readonly float EffectRange => (ActionID)action.Info.ID == ActionID.LiturgyOfTheBellPvE ? 20 : action.Action.EffectRange; - public readonly bool IsSingleTarget => _action.Action.CastType == 1; + /// + /// Is this action single target. + /// + public readonly bool IsSingleTarget => action.Action.CastType == 1; + /// + /// Is this action target are. + /// - public readonly bool IsTargetArea => _action.Action.TargetArea; + public readonly bool IsTargetArea => action.Action.TargetArea; private static bool NoAOE { @@ -41,7 +55,7 @@ private static bool NoAOE #region Target Finder. //The delay of finding the targets. private readonly ObjectListDelay _canTargets = new (() => Service.Config.TargetDelay); - public readonly IEnumerable GetCanTargets(bool skipStatusProvideCheck, TargetType type) + private readonly IEnumerable GetCanTargets(bool skipStatusProvideCheck, TargetType type) { var items = TargetFilter.GetObjectInRadius(DataCenter.AllTargets, Range); var objs = new List(items.Count()); @@ -54,15 +68,15 @@ public readonly IEnumerable GetCanTargets(bool skipStatusProvideChe objs.Add(obj); } - _canTargets.Delay(objs.Where(CanUseTo).Where(InViewTarget).Where(_action.Setting.CanTarget)); + _canTargets.Delay(objs.Where(CanUseTo).Where(InViewTarget).Where(action.Setting.CanTarget)); return _canTargets; } - public readonly IEnumerable GetCanAffects(bool skipStatusProvideCheck, TargetType type) + private readonly IEnumerable GetCanAffects(bool skipStatusProvideCheck, TargetType type) { if (EffectRange == 0) return []; - var items = TargetFilter.GetObjectInRadius(_action.Setting.IsFriendly + var items = TargetFilter.GetObjectInRadius(action.Setting.IsFriendly ? DataCenter.PartyMembers : DataCenter.AllHostileTargets, Range + EffectRange); @@ -111,8 +125,8 @@ private readonly unsafe bool CanUseTo(GameObject tar) var tarAddress = tar.Struct(); if (tarAddress == null) return false; - if ((ActionID)_action.Info.ID != ActionID.AethericMimicryPvE - && !ActionManager.CanUseActionOnTarget(_action.Info.AdjustedID, tarAddress)) return false; + if ((ActionID)action.Info.ID != ActionID.AethericMimicryPvE + && !ActionManager.CanUseActionOnTarget(action.Info.AdjustedID, tarAddress)) return false; return tar.CanSee(); } @@ -140,18 +154,18 @@ private readonly bool GeneralCheck(BattleChara gameObject, bool skipStatusProvid private readonly bool CheckStatus(GameObject gameObject, bool skipStatusProvideCheck) { - if (!_action.Config.ShouldCheckStatus) return true; + if (!action.Config.ShouldCheckStatus) return true; - if (_action.Setting.TargetStatusNeed != null) + if (action.Setting.TargetStatusNeed != null) { if (gameObject.WillStatusEndGCD(0, 0, - _action.Setting.StatusFromSelf, _action.Setting.TargetStatusNeed)) return false; + action.Setting.StatusFromSelf, action.Setting.TargetStatusNeed)) return false; } - if (_action.Setting.TargetStatusProvide != null && !skipStatusProvideCheck) + if (action.Setting.TargetStatusProvide != null && !skipStatusProvideCheck) { - if (!gameObject.WillStatusEndGCD(_action.Config.StatusGcdCount, 0, - _action.Setting.StatusFromSelf, _action.Setting.TargetStatusProvide)) return false; + if (!gameObject.WillStatusEndGCD(action.Config.StatusGcdCount, 0, + action.Setting.StatusFromSelf, action.Setting.TargetStatusProvide)) return false; } return true; @@ -159,14 +173,14 @@ private readonly bool CheckStatus(GameObject gameObject, bool skipStatusProvideC private readonly bool CheckResistance(GameObject gameObject) { - if (_action.Info.AttackType == AttackType.Magic) + if (action.Info.AttackType == AttackType.Magic) { if (gameObject.HasStatus(false, StatusHelper.MagicResistance)) { return false; } } - else if(_action.Info.Aspect != Aspect.Piercing) // Physic + else if(action.Info.Aspect != Aspect.Piercing) // Physic { if (gameObject.HasStatus(false, StatusHelper.PhysicResistancec)) { @@ -188,7 +202,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) { if (gameObject is not BattleChara b) return false; var time = b.GetTimeToKill(); - return float.IsNaN(time) || time >= _action.Config.TimeToKill; + return float.IsNaN(time) || time >= action.Config.TimeToKill; } #endregion @@ -206,7 +220,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) { return new(player, [], player.Position); } - var type = _action.Setting.TargetType; + var type = action.Setting.TargetType; var canTargets = GetCanTargets(skipStatusProvideCheck, type); var canAffects = GetCanAffects(skipStatusProvideCheck, type); @@ -219,7 +233,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) { var t = Svc.Targets.Target as BattleChara; - if (t == null || !_action.Setting.CanTarget(t)) return null; + if (t == null || !action.Setting.CanTarget(t)) return null; if (type == TargetType.Move) { @@ -235,7 +249,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) else { var effects = GetAffects(t, canAffects).ToArray(); - if (effects.Length >= _action.Config.AoeCount || skipAoeCheck) + if (effects.Length >= action.Config.AoeCount || skipAoeCheck) { return new(t, effects, t.Position); } @@ -244,12 +258,12 @@ private readonly bool CheckTimeToKill(GameObject gameObject) } var targets = GetMostCanTargetObjects(canTargets, canAffects, - skipAoeCheck ? 0 : _action.Config.AoeCount); - if (type == TargetType.BeAttacked && !_action.Setting.IsFriendly) + skipAoeCheck ? 0 : action.Config.AoeCount); + if (type == TargetType.BeAttacked && !action.Setting.IsFriendly) { type = TargetType.Big; } - var target = FindTargetByType(targets, type, _action.Config.AutoHealRatio, _action.Setting.IsMeleeRange); + var target = FindTargetByType(targets, type, action.Config.AutoHealRatio, action.Setting.IsMeleeRange); if (target == null) return null; return new(target, [.. GetAffects(target, canAffects)], target.Position); @@ -258,11 +272,11 @@ private readonly bool CheckTimeToKill(GameObject gameObject) private readonly TargetResult? FindTargetArea(IEnumerable canTargets, IEnumerable canAffects, float range, PlayerCharacter player) { - if (_action.Setting.TargetType is TargetType.Move) + if (action.Setting.TargetType is TargetType.Move) { return FindTargetAreaMove(range); } - else if (_action.Setting.IsFriendly) + else if (action.Setting.IsFriendly) { if (!Service.Config.UseGroundBeneficialAbility) return null; if (!Service.Config.UseGroundBeneficialAbilityWhenMoving && DataCenter.IsMoving) return null; @@ -271,7 +285,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) } else { - return FindTargetAreaHostile(canTargets, canAffects, _action.Config.AoeCount); + return FindTargetAreaHostile(canTargets, canAffects, action.Config.AoeCount); } } @@ -311,7 +325,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) { var availableCharas = DataCenter.AllTargets.Where(b => b.ObjectId != Player.Object.ObjectId); var target = FindTargetByType(TargetFilter.GetObjectInRadius(availableCharas, range), - TargetType.Move, _action.Config.AutoHealRatio, _action.Setting.IsMeleeRange); + TargetType.Move, action.Config.AutoHealRatio, action.Setting.IsMeleeRange); if (target == null) return null; return new(target, [], target.Position); } @@ -335,7 +349,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) DataCenter.TerritoryContentType == TerritoryContentType.Raids && DataCenter.AllianceMembers.Count(p => p is PlayerCharacter) == 8) { - pts = pts.Union(new Vector3[] { Vector3.Zero, new(100, 0, 100) }).ToArray(); + pts = pts.Union([Vector3.Zero, new(100, 0, 100)]).ToArray(); } } @@ -373,7 +387,7 @@ private readonly bool CheckTimeToKill(GameObject gameObject) { var effectRange = EffectRange; var attackT = FindTargetByType(DataCenter.AllianceMembers.GetObjectInRadius(range + effectRange), - TargetType.BeAttacked, _action.Config.AutoHealRatio, _action.Setting.IsMeleeRange); + TargetType.BeAttacked, action.Config.AutoHealRatio, action.Setting.IsMeleeRange); if (attackT == null) { @@ -425,7 +439,7 @@ private readonly IEnumerable GetAffects(BattleChara tar, IEnumerabl private readonly IEnumerable GetMostCanTargetObjects(IEnumerable canTargets, IEnumerable canAffects, int aoeCount) { if (IsSingleTarget || EffectRange <= 0) return canTargets; - if (!_action.Setting.IsFriendly && NoAOE) return []; + if (!action.Setting.IsFriendly && NoAOE) return []; List objectMax = new(canTargets.Count()); @@ -474,7 +488,7 @@ private readonly bool CanGetTarget(GameObject target, GameObject subTarget) Vector3 dir = target.Position - pPos; Vector3 tdir = subTarget.Position - pPos; - switch (_action.Action.CastType) + switch (action.Action.CastType) { case 2: // Circle return Vector3.Distance(target.Position, subTarget.Position) - subTarget.HitboxRadius <= EffectRange; @@ -495,7 +509,7 @@ private readonly bool CanGetTarget(GameObject target, GameObject subTarget) return dis <= EffectRange && dis >= 8; } - Svc.Log.Debug(_action.Action.Name.RawString + "'s CastType is not valid! The value is " + _action.Action.CastType.ToString()); + Svc.Log.Debug(action.Action.Name.RawString + "'s CastType is not valid! The value is " + action.Action.CastType.ToString()); return false; } #endregion @@ -799,64 +813,35 @@ private readonly bool CanGetTarget(GameObject target, GameObject subTarget) #endregion } +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public enum TargetType : byte { - /// - /// Find the target whose hit box is biggest. - /// Big, - - /// - /// Find the target whose hit box is smallest. - /// Small, - - /// - /// Find the target whose hp is highest. - /// HighHP, - - /// - /// Find the target whose hp is lowest. - /// LowHP, - - /// - /// Find the target whose max hp is highest. - /// HighMaxHP, - - /// - /// Find the target whose max hp is lowest. - /// LowMaxHP, - - Interrupt, - Provoke, - Death, - Dispel, - Move, - BeAttacked, - Heal, - Tank, - Melee, - Range, - Physical, - Magical, - Self, } - +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + +/// +/// The target result +/// +/// the target. +/// the targets that be affected by this action. +/// the position to use this action. public readonly record struct TargetResult(BattleChara? Target, BattleChara[] AffectedTargets, Vector3? Position); \ No newline at end of file diff --git a/RotationSolver.Basic/Actions/BaseAction.cs b/RotationSolver.Basic/Actions/BaseAction.cs index 94010c013..1c5b015d4 100644 --- a/RotationSolver.Basic/Actions/BaseAction.cs +++ b/RotationSolver.Basic/Actions/BaseAction.cs @@ -4,6 +4,10 @@ using Action = Lumina.Excel.GeneratedSheets.Action; namespace RotationSolver.Basic.Actions; + +/// +/// The base action for all actions. +/// public class BaseAction : IBaseAction { /// @@ -39,7 +43,7 @@ public class BaseAction : IBaseAction public uint SortKey => Cooldown.CoolDownGroup; /// - public uint IconID => ID == 3 ? 104 : Info.IconID; + public uint IconID => Info.IconID; /// public string Name => Info.Name; @@ -105,7 +109,7 @@ public BaseAction(ActionID actionID, bool isDutyAction = false) } /// - public bool CanUse(out IAction act, bool skipStatusProvideCheck = false, bool skipCombo = false, bool skipCastingCheck = false, + public bool CanUse(out IAction act, bool skipStatusProvideCheck = false, bool skipComboCheck = false, bool skipCastingCheck = false, bool usedUp = false, bool onLastAbility = false, bool skipClippingCheck = false, bool skipAoeCheck = false, byte gcdCountForAbility = 0) { act = this!; @@ -125,7 +129,7 @@ public bool CanUse(out IAction act, bool skipStatusProvideCheck = false, bool sk skipClippingCheck = true; } - if (!Info.BasicCheck(skipStatusProvideCheck, skipCombo, skipCastingCheck)) return false; + if (!Info.BasicCheck(skipStatusProvideCheck, skipComboCheck, skipCastingCheck)) return false; if (!Cooldown.CooldownCheck(usedUp, onLastAbility, skipClippingCheck, gcdCountForAbility)) return false; @@ -148,7 +152,7 @@ public bool CanUse(out IAction act, CanUseOption option, byte gcdCountForAbility { return CanUse(out act, option.HasFlag(CanUseOption.SkipStatusProvideCheck), - option.HasFlag(CanUseOption.SkipCombo), + option.HasFlag(CanUseOption.SkipComboCheck), option.HasFlag(CanUseOption.SkipCastingCheck), option.HasFlag(CanUseOption.UsedUp), option.HasFlag(CanUseOption.OnLastAbility), @@ -165,7 +169,7 @@ public unsafe bool Use() var target = Target.Value; var adjustId = AdjustedID; - if (TargetInfo.TargetArea) + if (TargetInfo.IsTargetArea) { if (adjustId != ID) return false; if (!target.Position.HasValue) return false; diff --git a/RotationSolver.Basic/Actions/BaseItem.cs b/RotationSolver.Basic/Actions/BaseItem.cs index 5d1ae08e4..1238187d2 100644 --- a/RotationSolver.Basic/Actions/BaseItem.cs +++ b/RotationSolver.Basic/Actions/BaseItem.cs @@ -56,6 +56,9 @@ readonly struct ItemCooldown(uint id) : ICooldown /// public string Name => _item.Name; + /// + /// The item configs. + /// public ItemConfig Config { get @@ -124,7 +127,8 @@ public bool IsInCooldown /// protected virtual bool CanUseThis => true; - public ICooldown Cooldown => throw new NotImplementedException(); + /// + public ICooldown Cooldown { get; } /// /// Create by row. @@ -149,6 +153,7 @@ public unsafe BaseItem(Item item) _ => 65535, //TODO: better A4! }; SortKey = (uint)ActionManager.Instance()->GetRecastGroup((int)ActionType.Item, ID); + Cooldown = new ItemCooldown(ID); } /// diff --git a/RotationSolver.Basic/Actions/IBaseAction.cs b/RotationSolver.Basic/Actions/IBaseAction.cs index e9e73ad1c..4c45d771f 100644 --- a/RotationSolver.Basic/Actions/IBaseAction.cs +++ b/RotationSolver.Basic/Actions/IBaseAction.cs @@ -2,6 +2,9 @@ namespace RotationSolver.Basic.Actions; +/// +/// The interface of the base action. +/// public interface IBaseAction : IAction { internal static TargetType? TargetOverride { get; set; } = null; @@ -12,17 +15,64 @@ public interface IBaseAction : IAction internal static bool AllEmpty { get; set; } = false; internal static bool ShouldEndSpecial { get; set; } = false; + /// + /// The action itself. + /// Action Action { get; } + + /// + /// The target to use on. + /// TargetResult? Target { get; set; } + + /// + /// The target for preview. + /// TargetResult? PreviewTarget { get; } + + /// + /// The information about the target. + /// ActionTargetInfo TargetInfo { get; } + + /// + /// The basic information of this action. + /// ActionBasicInfo Info { get; } + + /// + /// The cd information. + /// new ActionCooldownInfo Cooldown { get; } + + /// + /// The setting to use this action. + /// ActionSetting Setting { get; set; } - internal ActionConfig Config { get; } + internal ActionConfig Config { get; } - bool CanUse(out IAction act, bool skipStatusProvideCheck = false, bool skipCombo = false, bool skipCastingCheck = false, + /// + /// Can I use this action. + /// + /// The return action + /// Skip Status Provide Check + /// Skip Combo Check + /// Skip Casting and Moving Check + /// Is it used up all stacks + /// Is it on the last ability + /// Skip clipping Check + /// Skip aoe Check + /// the gcd count for the ability. + /// can I use it + bool CanUse(out IAction act, bool skipStatusProvideCheck = false, bool skipComboCheck = false, bool skipCastingCheck = false, bool usedUp = false, bool onLastAbility = false, bool skipClippingCheck = false, bool skipAoeCheck = false, byte gcdCountForAbility = 0); + /// + /// Can I use this action. + /// + /// The return action + /// The options + /// the gcd count for the ability. + /// can I use it bool CanUse(out IAction act, CanUseOption option, byte gcdCountForAbility = 0); } diff --git a/RotationSolver.Basic/Actions/ICooldown.cs b/RotationSolver.Basic/Actions/ICooldown.cs index 69b3afd12..ae27861a0 100644 --- a/RotationSolver.Basic/Actions/ICooldown.cs +++ b/RotationSolver.Basic/Actions/ICooldown.cs @@ -1,9 +1,25 @@ namespace RotationSolver.Basic.Actions; + +/// +/// The cd information. +/// public interface ICooldown { internal float RecastTimeOneChargeRaw { get; } internal float RecastTimeElapsedRaw { get; } + + /// + /// Is still in cooling down. + /// bool IsCoolingDown { get; } + + /// + /// The mac charges. + /// ushort MaxCharges { get; } + + /// + /// The current charges. + /// ushort CurrentCharges { get; } } diff --git a/RotationSolver.Basic/Actions/ItemConfig.cs b/RotationSolver.Basic/Actions/ItemConfig.cs index 82f35e1aa..62ed40689 100644 --- a/RotationSolver.Basic/Actions/ItemConfig.cs +++ b/RotationSolver.Basic/Actions/ItemConfig.cs @@ -1,6 +1,17 @@ namespace RotationSolver.Basic.Actions; + +/// +/// The item config. +/// public class ItemConfig { + /// + /// Is in the cooldown window. + /// public bool IsInCooldown { get; set; } + + /// + /// Is this action enabled. + /// public bool IsEnabled { get; set; } } diff --git a/RotationSolver.Basic/Attributes/DutyTerritoryAttribute.cs b/RotationSolver.Basic/Attributes/DutyTerritoryAttribute.cs index 4b9b7bd79..0b524bc45 100644 --- a/RotationSolver.Basic/Attributes/DutyTerritoryAttribute.cs +++ b/RotationSolver.Basic/Attributes/DutyTerritoryAttribute.cs @@ -1,8 +1,15 @@ namespace RotationSolver.Basic.Attributes; +/// +/// The duty territory attribute. which contains the +/// +/// [AttributeUsage(AttributeTargets.Class)] public class DutyTerritoryAttribute(params uint[] territoryIds) : Attribute { + /// + /// The terriotry ids. + /// public uint[] TerritoryIds => territoryIds; } diff --git a/RotationSolver.Basic/Attributes/IDAttribute.cs b/RotationSolver.Basic/Attributes/IDAttribute.cs index 7bb902337..8f426a571 100644 --- a/RotationSolver.Basic/Attributes/IDAttribute.cs +++ b/RotationSolver.Basic/Attributes/IDAttribute.cs @@ -1,7 +1,7 @@ namespace RotationSolver.Basic.Attributes; [AttributeUsage(AttributeTargets.Property)] -public class IDAttribute(uint id) : Attribute +internal class IDAttribute(uint id) : Attribute { public uint ID => id; } diff --git a/RotationSolver.Basic/Attributes/RangeAttribute.cs b/RotationSolver.Basic/Attributes/RangeAttribute.cs index e5a9ed216..cd7de460f 100644 --- a/RotationSolver.Basic/Attributes/RangeAttribute.cs +++ b/RotationSolver.Basic/Attributes/RangeAttribute.cs @@ -1,30 +1,73 @@ namespace RotationSolver.Basic.Attributes; +/// +/// The range of the configs. +/// +/// min value +/// max value +/// the unit type +/// the speed. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class RangeAttribute(float minValue, float maxValue, ConfigUnitType unitType, float speed = 0.005f) : Attribute { + /// + /// Min Value + /// public float MinValue => minValue; + + /// + /// Max Value + /// public float MaxValue => maxValue; + + /// + /// Speed + /// public float Speed => speed; + + /// + /// The unit type. + /// public ConfigUnitType UnitType => unitType; } +/// +/// The config unit type. +/// public enum ConfigUnitType : byte { + /// + /// None unit type. + /// None, + /// + /// + /// [Description("Time Unit, in seconds.")] Seconds, + /// + /// + /// [Description("Angle Unit, in degrees.")] Degree, + /// + /// + /// [Description("Distance Unit, in yalms.")] Yalms, + /// + /// + /// [Description("Ratio Unit, as percentage.")] Percent, + /// + /// + /// [Description("Display Unit, in pixels.")] Pixels, } \ No newline at end of file diff --git a/RotationSolver.Basic/Attributes/RotationAttribute.cs b/RotationSolver.Basic/Attributes/RotationAttribute.cs index 242cf8407..38f843a92 100644 --- a/RotationSolver.Basic/Attributes/RotationAttribute.cs +++ b/RotationSolver.Basic/Attributes/RotationAttribute.cs @@ -1,12 +1,30 @@ namespace RotationSolver.Basic.Attributes; +/// +/// Your custom rotation attribute. +/// +/// the name of this rotation. +/// the type of this rotation. [AttributeUsage(AttributeTargets.Class)] public class RotationAttribute(string name, CombatType type) : Attribute { + /// + /// The name of this rotation. + /// public string Name => name; + + /// + /// The type of this rotation. + /// public CombatType Type => type; + /// + /// Your description about this rotation. + /// public string? Description { get; set; } + /// + /// The Game version of this rotation. + /// public string? GameVersion { get; set; } } diff --git a/RotationSolver.Basic/Attributes/UIAttributes.cs b/RotationSolver.Basic/Attributes/UIAttributes.cs index b8f033b3d..408fac99e 100644 --- a/RotationSolver.Basic/Attributes/UIAttributes.cs +++ b/RotationSolver.Basic/Attributes/UIAttributes.cs @@ -1,21 +1,59 @@ namespace RotationSolver.Basic.Attributes; +/// +/// The attribute for the ui configs. +/// +/// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class UIAttribute(string name) : Attribute { + /// + /// The name of this config. + /// public string Name => name; + + /// + /// The description about this ui item. + /// public string Description { get; set; } = ""; + + /// + /// The parent of this ui item. + /// public string Parent { get; set; } = ""; + + /// + /// The filter to get this ui item. + /// public string Filter { get; set; } = ""; + + /// + /// The order of this item. + /// public byte Order { get; set; } = 0; + + /// + /// The section of this item. + /// public byte Section { get; set; } = 0; + /// + /// The action id + /// public ActionID Action { get; set; } + /// + /// The filter for the pvp. + /// public JobFilterType PvPFilter { get; set; } + + /// + /// The filter for the pve. + /// public JobFilterType PvEFilter { get; set; } } +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public enum JobFilterType : byte { None, @@ -28,6 +66,7 @@ public enum JobFilterType : byte Tank, Melee, } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] internal class JobConfigAttribute : Attribute diff --git a/RotationSolver.Basic/Configuration/Conditions/IConditionConverter.cs b/RotationSolver.Basic/Configuration/Conditions/IConditionConverter.cs index 32dfb726e..8e7c31ef5 100644 --- a/RotationSolver.Basic/Configuration/Conditions/IConditionConverter.cs +++ b/RotationSolver.Basic/Configuration/Conditions/IConditionConverter.cs @@ -4,7 +4,7 @@ namespace RotationSolver.Basic.Configuration.Conditions; internal class IConditionConverter : JsonCreationConverter { - protected override ICondition Create(JObject jObject) + protected override ICondition? Create(JObject jObject) { if (FieldExists(nameof(ConditionSet.Conditions), jObject)) { @@ -48,7 +48,7 @@ private static bool FieldExists(string fieldName, JObject jObject) internal abstract class JsonCreationConverter : JsonConverter { - protected abstract T Create(JObject jObject); + protected abstract T? Create(JObject jObject); public override bool CanConvert(Type objectType) { @@ -57,20 +57,23 @@ public override bool CanConvert(Type objectType) public override bool CanWrite => false; - public sealed override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { } - public sealed override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { // Load JObject from stream JObject jObject = JObject.Load(reader); // Create target object based on JObject - T target = Create(jObject); + var target = Create(jObject); // Populate the object properties - serializer.Populate(jObject.CreateReader(), target); + if (target != null) + { + serializer.Populate(jObject.CreateReader(), target); + } return target; } diff --git a/RotationSolver.Basic/Data/BeneficialAreaStrategy.cs b/RotationSolver.Basic/Data/BeneficialAreaStrategy.cs index 04c1628e4..d5ae4b209 100644 --- a/RotationSolver.Basic/Data/BeneficialAreaStrategy.cs +++ b/RotationSolver.Basic/Data/BeneficialAreaStrategy.cs @@ -1,15 +1,31 @@ namespace RotationSolver.Basic.Data; + +/// +/// The way to place the beneficial area action. +/// public enum BeneficialAreaStrategy : byte { + /// + /// On predefined location + /// [Description("On predefined location")] OnLocations, + /// + /// Only on predefined location + /// [Description("Only on predefined location")] OnlyOnLocations, + /// + /// On target + /// [Description("On target")] OnTarget, + /// + /// On the calculated location + /// [Description("On the calculated location")] OnCalculated, } \ No newline at end of file diff --git a/RotationSolver.Basic/Data/CanUseOption.cs b/RotationSolver.Basic/Data/CanUseOption.cs index d26a085b7..3d11060a0 100644 --- a/RotationSolver.Basic/Data/CanUseOption.cs +++ b/RotationSolver.Basic/Data/CanUseOption.cs @@ -27,7 +27,7 @@ public enum CanUseOption : byte /// Skip Combo Check /// [Description("Skip Combo Check")] - SkipCombo = 1 << 1, + SkipComboCheck = 1 << 1, /// /// Skip Casting and Moving Check diff --git a/RotationSolver.Basic/Data/ObjectListDelay.cs b/RotationSolver.Basic/Data/ObjectListDelay.cs index e0d943088..24dacb538 100644 --- a/RotationSolver.Basic/Data/ObjectListDelay.cs +++ b/RotationSolver.Basic/Data/ObjectListDelay.cs @@ -14,11 +14,15 @@ namespace RotationSolver.Basic.Data; public class ObjectListDelay(Func<(float min, float max)> getRange) : IEnumerable where T : GameObject { - IEnumerable _list = Array.Empty(); + IEnumerable _list = []; readonly Func<(float min, float max)> _getRange = getRange; SortedList _revealTime = []; readonly Random _ran = new(DateTime.Now.Millisecond); + /// + /// The default creator from the config. + /// + /// the way to get the config. public ObjectListDelay(Func getRange) : this(() => { diff --git a/RotationSolver.Basic/Data/RandomDelay.cs b/RotationSolver.Basic/Data/RandomDelay.cs index e768add33..aea427f58 100644 --- a/RotationSolver.Basic/Data/RandomDelay.cs +++ b/RotationSolver.Basic/Data/RandomDelay.cs @@ -20,6 +20,10 @@ public struct RandomDelay(Func<(float min, float max)> getRange) /// public readonly Func<(float min, float max)> GetRange => getRange; + /// + /// The constructor for the config. + /// + /// The way to get the config. public RandomDelay(Func getRange) : this(() => { @@ -66,6 +70,12 @@ public bool Delay(bool originData) return false; } + /// + /// The delay to get the item. + /// + /// the type of anything. + /// original data. + /// the value. public T? Delay(T? originData) where T : class { var b = originData != null; diff --git a/RotationSolver.Basic/Helpers/ActionIdHelper.cs b/RotationSolver.Basic/Helpers/ActionIdHelper.cs index 571a01692..3e7b91829 100644 --- a/RotationSolver.Basic/Helpers/ActionIdHelper.cs +++ b/RotationSolver.Basic/Helpers/ActionIdHelper.cs @@ -3,19 +3,38 @@ using Action = Lumina.Excel.GeneratedSheets.Action; namespace RotationSolver.Basic.Helpers; -public static class ActionIdHelper + +/// +/// The helper for the action id. +/// +public static class ActionIdHelper { + /// + /// Is this action cooling down. + /// + /// the action id. + /// public unsafe static bool IsCoolingDown(this ActionID actionID) { return IsCoolingDown(actionID.GetAction().GetCoolDownGroup()); } + /// + /// Is this action cooling down. + /// + /// + /// public unsafe static bool IsCoolingDown(byte cdGroup) { var detail = GetCoolDownDetail(cdGroup); return detail != null && detail->IsActive != 0; } + /// + /// The cd details + /// + /// + /// public static unsafe RecastDetail* GetCoolDownDetail(byte cdGroup) => ActionManager.Instance()->GetRecastGroupDetail(cdGroup - 1); @@ -24,6 +43,11 @@ private static Action GetAction(this ActionID actionID) return Svc.Data.GetExcelSheet()!.GetRow((uint)actionID)!; } + /// + /// The cast time. + /// + /// + /// public unsafe static float GetCastTime(this ActionID actionID) { return ActionManager.GetAdjustedCastTime(ActionType.Action, (uint)actionID) / 1000f; ; diff --git a/RotationSolver.Basic/Helpers/ObjectHelper.cs b/RotationSolver.Basic/Helpers/ObjectHelper.cs index a4331dfc8..8e1f248c0 100644 --- a/RotationSolver.Basic/Helpers/ObjectHelper.cs +++ b/RotationSolver.Basic/Helpers/ObjectHelper.cs @@ -30,10 +30,10 @@ public static class ObjectHelper return Service.GetSheet().GetRow(obj.DataId); } - public static bool CanProvoke(this GameObject target) + internal static bool CanProvoke(this GameObject target) { //Removed the listed names. - IEnumerable names = Array.Empty(); + IEnumerable names = []; if (OtherConfiguration.NoProvokeNames.TryGetValue(Svc.ClientState.TerritoryType, out var ns1)) names = names.Union(ns1); @@ -54,23 +54,13 @@ public static bool CanProvoke(this GameObject target) return false; } - /// - /// Is the target have positional. - /// - /// - /// - public static bool HasPositional(this GameObject obj) + internal static bool HasPositional(this GameObject obj) { if (obj == null) return false; return !(obj.GetObjectNPC()?.Unknown10 ?? false); } - /// - /// Is this target belongs to other players. - /// - /// - /// - public static unsafe bool IsOthersPlayers(this GameObject obj) + internal static unsafe bool IsOthersPlayers(this GameObject obj) { //SpecialType but no NamePlateIcon if (_eventType.Contains(obj.GetEventType())) @@ -80,7 +70,7 @@ public static unsafe bool IsOthersPlayers(this GameObject obj) return false; } - public static bool IsAttackable(this BattleChara battleChara) + internal static bool IsAttackable(this BattleChara battleChara) { //Dead. if (battleChara.CurrentHp <= 1) return false; @@ -90,7 +80,7 @@ public static bool IsAttackable(this BattleChara battleChara) if (Svc.ClientState == null) return false; //In No Hostiles Names - IEnumerable names = Array.Empty(); + IEnumerable names = []; if (OtherConfiguration.NoHostileNames.TryGetValue(Svc.ClientState.TerritoryType, out var ns1)) names = names.Union(ns1); @@ -142,7 +132,7 @@ public static bool IsAttackable(this BattleChara battleChara) }; } - public static unsafe bool IsInEnemiesList(this BattleChara battleChara) + internal static unsafe bool IsInEnemiesList(this BattleChara battleChara) { var addons = Service.GetAddons(); @@ -161,26 +151,16 @@ public static unsafe bool IsInEnemiesList(this BattleChara battleChara) return false; } - /// - /// Is this target an enemy (can be attacked). - /// - /// - /// - public static unsafe bool IsEnemy(this GameObject obj) + internal static unsafe bool IsEnemy(this GameObject obj) => obj != null && ActionManager.CanUseActionOnTarget((uint)ActionID.BlizzardPvE, obj.Struct()); - /// - /// Is alliance (can be healed). - /// - /// - /// - public static unsafe bool IsAlliance(this GameObject obj) + internal static unsafe bool IsAlliance(this GameObject obj) => obj != null && obj.ObjectId is not 0 and not GameObject.InvalidGameObjectId && (!(DataCenter.Territory?.IsPvpZone ?? false) && obj is PlayerCharacter || ActionManager.CanUseActionOnTarget((uint)ActionID.CurePvE, obj.Struct())); - public static bool IsParty(this GameObject gameObject) + internal static bool IsParty(this GameObject gameObject) { if (gameObject.ObjectId == Player.Object.ObjectId) return true; if (Svc.Party.Any(p => p.GameObject?.ObjectId == gameObject.ObjectId)) return true; @@ -188,12 +168,12 @@ public static bool IsParty(this GameObject gameObject) return false; } - public static bool IsTargetOnSelf(this BattleChara battleChara) + internal static bool IsTargetOnSelf(this BattleChara battleChara) { return battleChara.TargetObject?.TargetObject == battleChara; } - public static bool IsDeathToRaise(this GameObject obj) + internal static bool IsDeathToRaise(this GameObject obj) { if (obj == null) return false; if (!obj.IsDead) return false; @@ -210,12 +190,10 @@ public static bool IsDeathToRaise(this GameObject obj) return true; } - public static bool IsAlive(this GameObject obj) + internal static bool IsAlive(this GameObject obj) { if (obj is BattleChara b && b.CurrentHp <= 1) return false; - if (!obj.IsTargetable) return false; - return true; } @@ -258,16 +236,11 @@ or 71344 //Major Quest internal static unsafe uint GetNamePlateIcon(this GameObject obj) => obj.Struct()->NamePlateIconId; internal static unsafe EventHandlerType GetEventType(this GameObject obj) => obj.Struct()->EventId.Type; - /// - /// The sub kind of the target. - /// - /// - /// - public static unsafe BattleNpcSubKind GetBattleNPCSubKind(this GameObject obj) => (BattleNpcSubKind)obj.Struct()->SubKind; + internal static unsafe BattleNpcSubKind GetBattleNPCSubKind(this GameObject obj) => (BattleNpcSubKind)obj.Struct()->SubKind; internal static unsafe uint FateId(this GameObject obj) => obj.Struct()->FateId; - static readonly Dictionary _effectRangeCheck = new(); + static readonly Dictionary _effectRangeCheck = []; internal static bool CanInterrupt(this GameObject o) { if (o is not BattleChara b) return false; @@ -287,19 +260,9 @@ internal static bool CanInterrupt(this GameObject o) return _effectRangeCheck[id] = true; } - /// - /// Is object a dummy. - /// - /// - /// - public static bool IsDummy(this BattleChara obj) => obj?.NameId == 541; + internal static bool IsDummy(this BattleChara obj) => obj?.NameId == 541; - /// - /// Is character a boss? Calculate from ttk. - /// - /// - /// - public static bool IsBossFromTTK(this BattleChara obj) + internal static bool IsBossFromTTK(this BattleChara obj) { if (obj == null) return false; @@ -311,12 +274,7 @@ public static bool IsBossFromTTK(this BattleChara obj) return false; } - /// - /// Is character a boss? Calculated from the icon. - /// - /// - /// - public static bool IsBossFromIcon(this BattleChara obj) + internal static bool IsBossFromIcon(this BattleChara obj) { if (obj == null) return false; @@ -328,37 +286,21 @@ public static bool IsBossFromIcon(this BattleChara obj) return false; } - /// - /// Is character a dying? Current HP is below a certain amount. It is for running out of resources. - /// - /// - /// - public static bool IsDying(this BattleChara b) + internal static bool IsDying(this BattleChara b) { if (b == null) return false; if (b.IsDummy() && !Service.Config.ShowTargetTimeToKill) return false; return b.GetTimeToKill() <= Service.Config.DyingTimeToKill || b.GetHealthRatio() < 0.02f; } - /// - /// Whether the character is in combat. - /// - /// - /// - public static unsafe bool InCombat(this BattleChara obj) + internal static unsafe bool InCombat(this BattleChara obj) { return obj.Struct()->Character.InCombat; } private static readonly TimeSpan CheckSpan = TimeSpan.FromSeconds(2.5); - /// - /// How many seconds will the target die. - /// - /// - /// whole time to die. - /// - public static float GetTimeToKill(this BattleChara b, bool wholeTime = false) + internal static float GetTimeToKill(this BattleChara b, bool wholeTime = false) { if (b == null) return float.NaN; if (b.IsDummy()) return 999.99f; @@ -388,12 +330,7 @@ public static float GetTimeToKill(this BattleChara b, bool wholeTime = false) return (float)timespan.TotalSeconds / ratioReduce * (wholeTime ? 1 : ratioNow); } - /// - /// Whether the target is attacked. - /// - /// - /// - public static bool IsAttacked(this BattleChara b) + internal static bool IsAttacked(this BattleChara b) { foreach (var (id, time) in DataCenter.AttackedTargets) { @@ -405,12 +342,7 @@ public static bool IsAttacked(this BattleChara b) return false; } - /// - /// Can the player see the object. - /// - /// - /// - public static unsafe bool CanSee(this GameObject b) + internal static unsafe bool CanSee(this GameObject b) { var point = Player.Object.Position + Vector3.UnitY * Player.GameObject->Height; var tarPt = b.Position + Vector3.UnitY * b.Struct()->Height; @@ -451,24 +383,13 @@ internal static EnemyPositional FindEnemyPositional(this GameObject enemy) return EnemyPositional.Flank; } - /// - /// Get the face vector - /// - /// - /// - public static Vector2 GetFaceVector(this GameObject obj) + internal static Vector2 GetFaceVector(this GameObject obj) { float rotation = obj.Rotation; return new((float)Math.Cos(rotation), (float)Math.Sin(rotation)); } - /// - /// Get two vector's angle - /// - /// - /// - /// - public static double AngleTo(this Vector2 vec1, Vector2 vec2) + internal static double AngleTo(this Vector2 vec1, Vector2 vec2) { return Math.Acos(Vector2.Dot(vec1, vec2) / vec1.Length() / vec2.Length()); } diff --git a/RotationSolver.Basic/Helpers/TargetFilter.cs b/RotationSolver.Basic/Helpers/TargetFilter.cs index 838a462d0..05b3f310e 100644 --- a/RotationSolver.Basic/Helpers/TargetFilter.cs +++ b/RotationSolver.Basic/Helpers/TargetFilter.cs @@ -60,11 +60,18 @@ public static bool IsJobCategory(this GameObject obj, JobRole role) return obj.IsJobs(validJobs); } + /// + /// Is the target in the jobs. + /// + /// + /// + /// public static bool IsJobs(this GameObject obj, params Job[] validJobs) { return obj.IsJobs(new SortedSet( validJobs.Select(j => (byte)(uint)j))); } - public static bool IsJobs(this GameObject obj, SortedSet validJobs) + + private static bool IsJobs(this GameObject obj, SortedSet validJobs) { if(obj is not BattleChara b) return false; return validJobs.Contains((byte?)b.ClassJob.GameData?.RowId ?? 0); diff --git a/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs b/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs index c974535ec..c4548f4c5 100644 --- a/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/BlackMageRotation.cs @@ -56,7 +56,7 @@ partial class BlackMageRotation /// /// /// - public static float EnochianTime => EnochianTimeRaw + DataCenter.WeaponRemain; + public static float EnochianTime => EnochianTimeRaw - DataCenter.WeaponRemain; /// /// @@ -79,7 +79,7 @@ protected static bool EnchinaEndAfterGCD(uint gcdCount = 0, float offset = 0) /// /// /// - protected static float ElementTime => ElementTimeRaw + DataCenter.WeaponRemain; + protected static float ElementTime => ElementTimeRaw - DataCenter.WeaponRemain; /// /// diff --git a/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs b/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs index 889025079..6ce6c833f 100644 --- a/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/DragoonRotation.cs @@ -23,7 +23,7 @@ partial class DragoonRotation /// /// /// - public static float LOTDTime => LOTDTimeRaw + DataCenter.WeaponRemain; + public static float LOTDTime => LOTDTimeRaw - DataCenter.WeaponRemain; /// /// diff --git a/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs b/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs index 9014e2156..7a22740be 100644 --- a/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/MachinistRotation.cs @@ -26,7 +26,7 @@ partial class MachinistRotation /// /// /// - public static float OverheatTime => OverheatTimeRemainingRaw + DataCenter.WeaponRemain; + public static float OverheatTime => OverheatTimeRemainingRaw - DataCenter.WeaponRemain; /// /// diff --git a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs index fe78e9253..b0695f51c 100644 --- a/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/NinjaRotation.cs @@ -115,6 +115,9 @@ static partial void ModifyDotonPvE(ref ActionSetting setting) setting.StatusProvide = [StatusID.Doton]; } + /// + /// + /// public NinjaRotation() { FumaShurikenPvE.Setting.Ninjutsu = [TenPvE]; diff --git a/RotationSolver.Basic/Rotations/Basic/ScholarRotation.cs b/RotationSolver.Basic/Rotations/Basic/ScholarRotation.cs index b4f739574..f1858785d 100644 --- a/RotationSolver.Basic/Rotations/Basic/ScholarRotation.cs +++ b/RotationSolver.Basic/Rotations/Basic/ScholarRotation.cs @@ -21,7 +21,7 @@ partial class ScholarRotation /// /// /// - public static float SeraphTime => SeraphTimeRaw + DataCenter.WeaponRemain; + public static float SeraphTime => SeraphTimeRaw - DataCenter.WeaponRemain; #endregion private sealed protected override IBaseAction Raise => ResurrectionPvE; diff --git a/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs b/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs index ad7132cf6..146bb5357 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs @@ -132,6 +132,9 @@ static partial void ModifySprintPvP(ref ActionSetting setting) private protected virtual IBaseAction? LimitBreak3 => null; private protected virtual IBaseAction? LimitBreakPvP => null; + /// + /// All actions of this rotation. + /// public virtual IAction[] AllActions => [ .. AllBaseActions.Where(i => @@ -150,14 +153,29 @@ .. HpPotions.Where(i => i.HasIt), .. AllItems.Where(i => i.HasIt), ]; + /// + /// All traits of this action. + /// public virtual IBaseTrait[] AllTraits { get; } = []; PropertyInfo[]? _allBools; + + /// + /// All bools of this rotation. + /// public PropertyInfo[] AllBools => _allBools ??= GetType().GetStaticProperties(); PropertyInfo[]? _allBytes; + + /// + /// All bytes or integers of this rotation. + /// public PropertyInfo[] AllBytesOrInt => _allBytes ??= GetType().GetStaticProperties().Union(GetType().GetStaticProperties()).ToArray(); PropertyInfo[]? _allFloats; + + /// + /// All floats of this rotation. + /// public PropertyInfo[] AllFloats => _allFloats ??= GetType().GetStaticProperties(); } diff --git a/RotationSolver.Basic/Rotations/CustomRotation_BasicInfo.cs b/RotationSolver.Basic/Rotations/CustomRotation_BasicInfo.cs index 19fc7fd28..07d9690fd 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_BasicInfo.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_BasicInfo.cs @@ -4,15 +4,20 @@ namespace RotationSolver.Basic.Rotations; -[Jobs()] partial class CustomRotation : ICustomRotation { private Job? _job = null; + + /// public Job Job => _job ??= this.GetType().GetCustomAttribute()?.Jobs[0] ?? Job.ADV; private JobRole? _role = null; + + /// public JobRole Role => _role ??= Svc.Data.GetExcelSheet()!.GetRow((uint)Job)!.GetJobRole(); private string? _name = null; + + /// public string Name { get @@ -25,6 +30,7 @@ public string Name } } + /// public bool IsEnabled { get => !Service.Config.DisabledJobs.Contains(Job); @@ -41,52 +47,83 @@ public bool IsEnabled } } + /// public uint IconID { get; } + /// public IRotationConfigSet Configs { get; } + /// public static Vector3? MoveTarget { get; internal set; } + /// public string Description => this.GetType().GetCustomAttribute()?.Description ?? string.Empty; + /// public IAction? ActionHealAreaGCD { get; private set; } + /// public IAction? ActionHealAreaAbility { get; private set; } + /// public IAction? ActionHealSingleGCD { get; private set; } + /// public IAction? ActionHealSingleAbility { get; private set; } + /// public IAction? ActionDefenseAreaGCD { get; private set; } + /// public IAction? ActionDefenseAreaAbility { get; private set; } + /// public IAction? ActionDefenseSingleGCD { get; private set; } + /// public IAction? ActionDefenseSingleAbility { get; private set; } + /// public IAction? ActionMoveForwardGCD { get; private set; } + /// public IAction? ActionMoveForwardAbility { get; private set; } + /// public IAction? ActionMoveBackAbility { get; private set; } + /// public IAction? ActionSpeedAbility { get; private set; } + /// public IAction? ActionDispelStancePositionalGCD { get; private set; } + /// public IAction? ActionDispelStancePositionalAbility { get; private set; } + /// public IAction? ActionRaiseShirkGCD { get; private set; } + /// public IAction? ActionRaiseShirkAbility { get; private set; } + /// public IAction? ActionAntiKnockbackAbility { get; private set; } + /// + /// Is this action valid. + /// [Description("Is this rotation valid")] public bool IsValid { get; private set; } = true; + + /// + /// Why this action is not valid. + /// public string WhyNotValid { get; private set; } = string.Empty; + /// + /// Should show the status to the users. + /// [Description("Show the status")] public virtual bool ShowStatus => false; @@ -96,11 +133,16 @@ private protected CustomRotation() Configs = CreateConfiguration(); } + /// + /// The way to create the configurations. + /// + /// protected virtual IRotationConfigSet CreateConfiguration() { return new RotationConfigSet(); } + /// public override string ToString() => this.GetType().GetCustomAttribute()?.Name ?? this.GetType().Name; /// diff --git a/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs b/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs index f362116c0..6bd24dea7 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs @@ -181,12 +181,22 @@ bool RaiseAction(out IAction act, bool ignoreCastingCheck) } } + /// + /// The gcd for raising. + /// + /// the action. + /// protected virtual bool RaiseGCD(out IAction? act) { if (DataCenter.RightNowDutyRotation?.RaiseGCD(out act) ?? false) return true; act = null; return false; } + /// + /// The gcd for dispeling. + /// + /// the action. + /// protected virtual bool DispelGCD(out IAction? act) { if (EsunaPvE.CanUse(out act)) return true; diff --git a/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs b/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs index a3647b332..ea9f2ebb3 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_OtherInfo.cs @@ -110,7 +110,7 @@ partial class CustomRotation /// /// The player's target, or null if no valid target. (null clears the target) /// - protected static BattleChara CurrentTarget => Svc.Targets.Target is BattleChara b ? b : null; + protected static BattleChara? CurrentTarget => Svc.Targets.Target is BattleChara b ? b : null; /// /// The last attacked hostile target. diff --git a/RotationSolver.Basic/Rotations/Duties/BozjaRotation.cs b/RotationSolver.Basic/Rotations/Duties/BozjaRotation.cs index 0b6952b58..43a9fe8d5 100644 --- a/RotationSolver.Basic/Rotations/Duties/BozjaRotation.cs +++ b/RotationSolver.Basic/Rotations/Duties/BozjaRotation.cs @@ -1,5 +1,8 @@ namespace RotationSolver.Basic.Rotations.Duties; +/// +/// The bozja action. +/// [DutyTerritory] //TODO: the bozja territory ids! public abstract class BozjaRotation : DutyRotation { diff --git a/RotationSolver.Basic/Rotations/Duties/DutyRotation.cs b/RotationSolver.Basic/Rotations/Duties/DutyRotation.cs index 9a1e8aad1..84efc739b 100644 --- a/RotationSolver.Basic/Rotations/Duties/DutyRotation.cs +++ b/RotationSolver.Basic/Rotations/Duties/DutyRotation.cs @@ -1,4 +1,5 @@ namespace RotationSolver.Basic.Rotations.Duties; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member partial class DutyRotation { @@ -128,3 +129,4 @@ internal IAction[] AllActions } } } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member diff --git a/RotationSolver/Data/UiString.cs b/RotationSolver/Data/UiString.cs index 56d31eb99..f09d16187 100644 --- a/RotationSolver/Data/UiString.cs +++ b/RotationSolver/Data/UiString.cs @@ -123,6 +123,9 @@ internal enum UiString [Description("How many targets are needed to use this action.")] ConfigWindow_Actions_AoeCount, + [Description("Should this action check the stauts.")] + ConfigWindow_Actions_CheckStatus, + [Description("How many gcds are needed to add the status.")] ConfigWindow_Actions_GcdCount, diff --git a/RotationSolver/UI/ConditionDrawer.cs b/RotationSolver/UI/ConditionDrawer.cs index cfbfee8c7..22463934f 100644 --- a/RotationSolver/UI/ConditionDrawer.cs +++ b/RotationSolver/UI/ConditionDrawer.cs @@ -82,7 +82,7 @@ internal static void DrawCondition(bool? tag) private static IEnumerable GetAllMethods(this Type? type, Func> getFunc) { - if (type == null || getFunc == null) return Array.Empty(); + if (type == null || getFunc == null) return []; var methods = getFunc(type); return methods.Union(type.BaseType.GetAllMethods(getFunc)); diff --git a/RotationSolver/UI/RotationConfigWindow.cs b/RotationSolver/UI/RotationConfigWindow.cs index fdaeb9949..8d9762701 100644 --- a/RotationSolver/UI/RotationConfigWindow.cs +++ b/RotationSolver/UI/RotationConfigWindow.cs @@ -2,6 +2,7 @@ using Dalamud.Interface.Internal; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; +using Dalamud.Interface.Utility.Table; using Dalamud.Interface.Windowing; using Dalamud.Utility; using ECommons.DalamudServices; @@ -1405,105 +1406,76 @@ private static unsafe void DrawActions() ImGui.TableNextColumn(); - if (Service.Config.InDebug) - { - if (_activeAction is IBaseAction action) - { + DrawConfigsOfAction(); + DrawActionDebug(); - try - { -#if DEBUG - ImGui.Text("Is Real GCD: " + action.Info.IsRealGCD.ToString()); - ImGui.Text("Status: " + FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetActionStatus(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Action, action.AdjustedID).ToString()); - ImGui.Text("Cast Time: " + action.Info.CastTime.ToString()); - ImGui.Text("MP: " + action.Info.MPNeed.ToString()); -#endif - ImGui.Text("AttackType: " + action.Info.AttackType.ToString()); - ImGui.Text("Aspect: " + action.Info.Aspect.ToString()); - ImGui.Text("Has One:" + action.Cooldown.HasOneCharge.ToString()); - ImGui.Text("Recast One: " + action.Cooldown.RecastTimeOneChargeRaw.ToString()); - ImGui.Text("Recast Elapsed: " + action.Cooldown.RecastTimeElapsedRaw.ToString()); - - ImGui.Text($"Can Use: {action.CanUse(out _, skipClippingCheck: true)} "); - ImGui.Text("IgnoreCastCheck:" + action.CanUse(out _, skipClippingCheck: true, skipCastingCheck : true).ToString()); - if (action.Target != null) - { - ImGui.Text("Target Name: " + action.Target.Value.Target?.Name ?? string.Empty); - } - } - catch - { + ImGui.TextWrapped(UiString.ConfigWindow_Actions_ConditionDescription.Local()); + _sequencerList?.Draw(); + } - } - } - else if (_activeAction is IBaseItem item) - { - try - { - ImGui.Text("Status: " + FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetActionStatus(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID).ToString()); - ImGui.Text("Status HQ: " + FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetActionStatus(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID + 1000000).ToString()); - var remain = FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetRecastTime(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID) - FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetRecastTimeElapsed(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID); - ImGui.Text("remain: " + remain.ToString()); - ImGui.Text("CanUse: " + item.CanUse(out _, true).ToString()); + static void DrawConfigsOfAction() + { + if (_activeAction == null) return; - if (item is HpPotionItem healPotionItem) - { - ImGui.Text("MaxHP:" + healPotionItem.MaxHp.ToString()); - } - } - catch - { + var enable = _activeAction.IsEnabled; + if (ImGui.Checkbox($"{_activeAction.Name}##{_activeAction.Name} Enabled", ref enable)) + { + _activeAction.IsEnabled = enable; + } - } - } + const string key = "Action Enable Popup"; + var cmd = ToCommandStr(OtherCommandType.ToggleActions, _activeAction.ToString()!); + ImGuiHelper.DrawHotKeysPopup(key, cmd); + ImGuiHelper.ExecuteHotKeysPopup(key, cmd, string.Empty, false); + + enable = _activeAction.IsInCooldown; + if (ImGui.Checkbox($"{UiString.ConfigWindow_Actions_ShowOnCDWindow.Local()}##{_activeAction.Name}InCooldown", ref enable)) + { + _activeAction.IsInCooldown = enable; } - if (_activeAction != null) + if (_activeAction is IBaseAction a) { - var enable = _activeAction.IsEnabled; - if (ImGui.Checkbox($"{_activeAction.Name}##{_activeAction.Name} Enabled", ref enable)) + DrawConfigsOfBaseAction(a); + } + + ImGui.Separator(); + + static void DrawConfigsOfBaseAction(IBaseAction a) + { + var config = a.Config; + + if (Service.Config.MistakeRatio > 0 + && !a.Setting.IsFriendly + && a.Setting.TargetType != TargetType.Move) { - _activeAction.IsEnabled = enable; + var enable = config.IsInMistake; + if (ImGui.Checkbox($"{UiString.ConfigWindow_Actions_IsInMistake.Local()}##{a.Name}InMistake", ref enable)) + { + config.IsInMistake = enable; + } } - const string key = "Action Enable Popup"; - var cmd = ToCommandStr(OtherCommandType.ToggleActions, _activeAction.ToString()!); - ImGuiHelper.DrawHotKeysPopup(key, cmd); - ImGuiHelper.ExecuteHotKeysPopup(key, cmd, string.Empty, false); + ImGui.Separator(); - enable = _activeAction.IsInCooldown; - if (ImGui.Checkbox($"{UiString.ConfigWindow_Actions_ShowOnCDWindow.Local()}##{_activeAction.Name}InCooldown", ref enable)) + var ttk = config.TimeToKill; + ImGui.SetNextItemWidth(Scale * 150); + if (ImGui.DragFloat($"{UiString.ConfigWindow_Actions_TTK.Local()}##{a}", + ref ttk, 0.1f, 0, 120, $"{ttk:F2}{ConfigUnitType.Seconds.ToSymbol()}")) { - _activeAction.IsInCooldown = enable; + config.TimeToKill = ttk; } + ImguiTooltips.HoveredTooltip(ConfigUnitType.Seconds.Local()); - if (_activeAction is IBaseAction a) + if (a.Setting.StatusProvide != null || a.Setting.TargetStatusProvide != null) { - var config = a.Config; - - if (Service.Config.MistakeRatio > 0 - && !a.Setting.IsFriendly - && a.Setting.TargetType != TargetType.Move) - { - enable = config.IsInMistake; - if (ImGui.Checkbox($"{UiString.ConfigWindow_Actions_IsInMistake.Local()}##{a.Name}InMistake", ref enable)) - { - config.IsInMistake = enable; - } - } - - ImGui.Separator(); - - var ttk = config.TimeToKill; - ImGui.SetNextItemWidth(Scale * 150); - if (ImGui.DragFloat($"{UiString.ConfigWindow_Actions_TTK.Local()}##{a}", - ref ttk, 0.1f, 0, 120, $"{ttk:F2}{ConfigUnitType.Seconds.ToSymbol()}")) + var shouldStatus = config.ShouldCheckStatus; + if (ImGui.Checkbox($"{UiString.ConfigWindow_Actions_CheckStatus.Local()}##{a}", ref shouldStatus)) { - config.TimeToKill = ttk; + config.ShouldCheckStatus = shouldStatus; } - ImguiTooltips.HoveredTooltip(ConfigUnitType.Seconds.Local()); - if (a.Setting.StatusProvide != null || a.Setting.TargetStatusProvide != null) + if (shouldStatus) { var statusGcdCount = (int)config.StatusGcdCount; ImGui.SetNextItemWidth(Scale * 150); @@ -1513,33 +1485,84 @@ private static unsafe void DrawActions() config.StatusGcdCount = (byte)statusGcdCount; } } + } - if (!a.TargetInfo.IsSingleTarget) + if (!a.TargetInfo.IsSingleTarget) + { + var aoeCount = (int)config.AoeCount; + ImGui.SetNextItemWidth(Scale * 150); + if (ImGui.DragInt($"{UiString.ConfigWindow_Actions_AoeCount.Local()}##{a}", + ref aoeCount, 0.05f, 1, 10)) { - var aoeCount = (int)config.AoeCount; - ImGui.SetNextItemWidth(Scale * 150); - if (ImGui.DragInt($"{UiString.ConfigWindow_Actions_AoeCount.Local()}##{a}", - ref aoeCount, 0.05f, 1, 10)) - { - config.AoeCount = (byte)aoeCount; - } + config.AoeCount = (byte)aoeCount; } + } - var ratio = config.AutoHealRatio; - ImGui.SetNextItemWidth(Scale * 150); - if (ImGui.DragFloat($"{UiString.ConfigWindow_Actions_HealRatio.Local()}##{a}", - ref ratio, 0.002f, 0, 1, $"{ratio * 100:F1}{ConfigUnitType.Percent.ToSymbol()}")) + var ratio = config.AutoHealRatio; + ImGui.SetNextItemWidth(Scale * 150); + if (ImGui.DragFloat($"{UiString.ConfigWindow_Actions_HealRatio.Local()}##{a}", + ref ratio, 0.002f, 0, 1, $"{ratio * 100:F1}{ConfigUnitType.Percent.ToSymbol()}")) + { + config.AutoHealRatio = ratio; + } + ImguiTooltips.HoveredTooltip(ConfigUnitType.Percent.Local()); + + } + } + + static void DrawActionDebug() + { + if (!Service.Config.InDebug) return; + + if (_activeAction is IBaseAction action) + { + + try + { +#if DEBUG + ImGui.Text("Is Real GCD: " + action.Info.IsRealGCD.ToString()); + ImGui.Text("Status: " + FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetActionStatus(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Action, action.AdjustedID).ToString()); + ImGui.Text("Cast Time: " + action.Info.CastTime.ToString()); + ImGui.Text("MP: " + action.Info.MPNeed.ToString()); +#endif + ImGui.Text("AttackType: " + action.Info.AttackType.ToString()); + ImGui.Text("Aspect: " + action.Info.Aspect.ToString()); + ImGui.Text("Has One:" + action.Cooldown.HasOneCharge.ToString()); + ImGui.Text("Recast One: " + action.Cooldown.RecastTimeOneChargeRaw.ToString()); + ImGui.Text("Recast Elapsed: " + action.Cooldown.RecastTimeElapsedRaw.ToString()); + + ImGui.Text($"Can Use: {action.CanUse(out _, skipClippingCheck: true)} "); + ImGui.Text("IgnoreCastCheck:" + action.CanUse(out _, skipClippingCheck: true, skipCastingCheck: true).ToString()); + if (action.Target != null) { - config.AutoHealRatio = ratio; + ImGui.Text("Target Name: " + action.Target.Value.Target?.Name ?? string.Empty); } - ImguiTooltips.HoveredTooltip(ConfigUnitType.Percent.Local()); } + catch + { - ImGui.Separator(); + } } + else if (_activeAction is IBaseItem item) + { + try + { + ImGui.Text("Status: " + FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetActionStatus(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID).ToString()); + ImGui.Text("Status HQ: " + FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetActionStatus(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID + 1000000).ToString()); + var remain = FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetRecastTime(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID) - FFXIVClientStructs.FFXIV.Client.Game.ActionManager.Instance()->GetRecastTimeElapsed(FFXIVClientStructs.FFXIV.Client.Game.ActionType.Item, item.ID); + ImGui.Text("remain: " + remain.ToString()); + ImGui.Text("CanUse: " + item.CanUse(out _, true).ToString()); - ImGui.TextWrapped(UiString.ConfigWindow_Actions_ConditionDescription.Local()); - _sequencerList?.Draw(); + if (item is HpPotionItem healPotionItem) + { + ImGui.Text("MaxHP:" + healPotionItem.MaxHp.ToString()); + } + } + catch + { + + } + } } } diff --git a/RotationSolver/Updaters/SocialUpdater.cs b/RotationSolver/Updaters/SocialUpdater.cs index 06c4c5300..f780adba3 100644 --- a/RotationSolver/Updaters/SocialUpdater.cs +++ b/RotationSolver/Updaters/SocialUpdater.cs @@ -20,6 +20,9 @@ namespace RotationSolver.Updaters; internal class SocialUpdater { +#if DEBUG +#else + private static readonly List _macroToAuthor = [ "blush", @@ -30,6 +33,7 @@ internal class SocialUpdater "cheer", "stroke", ]; +#endif private static readonly HashSet saidAuthors = []; @@ -68,7 +72,7 @@ internal static void Enable() static async void DutyState_DutyCompleted(object? sender, ushort e) { - if (DataCenter.PartyMembers.Count() < 2) return; + if (DataCenter.PartyMembers.Length < 2) return; await Task.Delay(new Random().Next(4000, 6000)); @@ -91,6 +95,10 @@ static void ClientState_TerritoryChanged(ushort id) DataCenter.Territory = territory; +#if DEBUG + Svc.Log.Debug($"Move to {DataCenter.TerritoryName} ({id})"); +#endif + _dutyRotations ??= [..RotationUpdater.TryGetTypes(typeof(SocialUpdater).Assembly) .Where(t => t.IsAssignableTo(typeof(DutyRotation)) && !t.IsAbstract)];