diff --git a/RotationSolver.Basic/Configuration/Configs.cs b/RotationSolver.Basic/Configuration/Configs.cs index 395d4e029..c227f0e5c 100644 --- a/RotationSolver.Basic/Configuration/Configs.cs +++ b/RotationSolver.Basic/Configuration/Configs.cs @@ -357,6 +357,11 @@ public enum PluginConfigBool : byte [Default(false)] TargetAllForFriendly, [Default(false)] ShowCooldownWindow, + [Default(true)] UseLostActions, + [Default(false)] UseLostFlareStarOnMobs, + [Default(true)] UseLostAssassinationOnMobs, + [Default(true)] LostReflectAutoRefresh, + [Default(true)] RecordCastingArea, [Default(true)] AutoOffAfterCombat, @@ -443,6 +448,7 @@ public enum PluginConfigFloat : byte [Default(24f, 0f, 90f), Unit(ConfigUnitType.Degree)] MoveTargetAngle, [Default(90f, 10f, 1800f), Unit(ConfigUnitType.Seconds)] BossTimeToKill, [Default(10f, 0f, 60f), Unit(ConfigUnitType.Seconds)] DyingTimeToKill, + [Default(15f, 0f, 1800f), Unit(ConfigUnitType.Seconds)] LostAssassinationTimeToKill, [Default(16f, 9.6f, 96f), Unit(ConfigUnitType.Pixels)] CooldownFontSize, diff --git a/RotationSolver.Basic/Configuration/OtherConfiguration.cs b/RotationSolver.Basic/Configuration/OtherConfiguration.cs index baa9773a6..dac050568 100644 --- a/RotationSolver.Basic/Configuration/OtherConfiguration.cs +++ b/RotationSolver.Basic/Configuration/OtherConfiguration.cs @@ -48,6 +48,9 @@ public class OtherConfiguration { (uint) ActionID.SteelCyclone, 2}, { (uint) ActionID.VariantSpiritDart, 1 }, { (uint) ActionID.VariantSpiritDart2, 1 }, + { (uint) ActionID.LostRampage, 1 }, + { (uint) ActionID.LostBurst, 1 }, + { (uint) ActionID.LostFlarestar, 1 } }; public static Dictionary ActionTTK = new() @@ -259,4 +262,4 @@ private static void InitOne(ref T value, string name, bool download = true) } } #pragma warning restore CA2211 -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member \ No newline at end of file +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member diff --git a/RotationSolver.Basic/Data/ActionID.cs b/RotationSolver.Basic/Data/ActionID.cs index 8dd72c2b2..48c2b80a4 100644 --- a/RotationSolver.Basic/Data/ActionID.cs +++ b/RotationSolver.Basic/Data/ActionID.cs @@ -5208,6 +5208,21 @@ public enum ActionID : uint /// LostBurst = 23909, + /// + /// + /// + LostProtect = 20719, + + /// + /// + /// + LostShell = 20710, + + /// + /// + /// + LostReflect = 20711, + /// /// /// @@ -5216,12 +5231,17 @@ public enum ActionID : uint /// /// /// - LostProtect = 20719, + LostFontOfPower = 20717, /// /// /// - LostShell = 20710, + BannerOfHonoredSacrifice = 20721, + + /// + /// + /// + LostAssassination = 23914, /// /// diff --git a/RotationSolver.Basic/Data/StatusID.cs b/RotationSolver.Basic/Data/StatusID.cs index 4386416f0..5ee5a6dd6 100644 --- a/RotationSolver.Basic/Data/StatusID.cs +++ b/RotationSolver.Basic/Data/StatusID.cs @@ -1341,23 +1341,43 @@ public enum StatusID : ushort /// /// /// - LostSpellforge = 2338, + SpiritOfTheBeast = 2324, /// /// /// - MagicalAversion = 2370, + BannerOfHonoredSacrifice = 2327, + + /// + /// + /// + LostReflect = 2337, + + /// + /// + /// + LostSpellforge = 2338, /// /// /// LostSteelsting = 2339, + /// + /// + /// + LostFontOfPower = 2346, + /// /// /// PhysicalAversion = 2369, + /// + /// + /// + MagicalAversion = 2370, + /// /// /// diff --git a/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs b/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs index 30be1ad1e..25e9710d5 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_Ability.cs @@ -431,6 +431,7 @@ protected virtual bool AttackAbility(out IAction act) if (VariantSpiritDart2.CanUse(out act, CanUseOption.MustUse)) return true; if (VariantRampart.CanUse(out act)) return true; if (VariantRampart2.CanUse(out act)) return true; + if (LostAssassination.CanUse(out act)) return true; return false; } } diff --git a/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs b/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs index 423026044..1e37a5d35 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_Actions.cs @@ -1,5 +1,6 @@ using ECommons.ExcelServices; using RotationSolver.Basic.Traits; +using RotationSolver.Basic.Configuration; namespace RotationSolver.Basic.Rotations; @@ -98,7 +99,7 @@ public override bool CanUse(out IAction act, CanUseOption option = CanUseOption. public static IBaseAction SecondWind { get; } = new RoleAction(ActionID.SecondWind, new JobRole[] { JobRole.RangedPhysical, JobRole.Melee }, ActionOption.Heal) { - ActionCheck = (b, m) => Player?.GetHealthRatio() < Service.Config.GetValue(DataCenter.Job, Configuration.JobConfigFloat.HealthSingleAbility) && InCombat, + ActionCheck = (b, m) => Player?.GetHealthRatio() < Service.Config.GetValue(DataCenter.Job, JobConfigFloat.HealthSingleAbility) && InCombat, }; /// @@ -392,8 +393,8 @@ public override bool CanUse(out IAction act, CanUseOption option = CanUseOption. public static IBaseAction LostSpellforge { get; } = new BaseAction(ActionID.LostSpellforge, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostSpellforge }, - ActionCheck = (b, m) => LostSpellforge.Target?.HasStatus(false, StatusID.MagicalAversion) ?? false, + TargetStatus = new StatusID[] { StatusID.LostSpellforge }, + // TargetStatusIsGlobal = true, ChoiceTarget = (targets, mustUse) => targets.FirstOrDefault(t => (Job)t.ClassJob.Id switch { Job.WAR @@ -421,8 +422,8 @@ or Job.RDM public static IBaseAction LostSteelsting { get; } = new BaseAction(ActionID.LostSteelsting, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostSteelsting }, - ActionCheck = (b, m) => LostSteelsting.Target?.HasStatus(false, StatusID.PhysicalAversion) ?? false, + TargetStatus = new StatusID[] { StatusID.LostSteelsting }, + // TargetStatusIsGlobal = true, ChoiceTarget = (targets, mustUse) => targets.FirstOrDefault(t => (Job)t.ClassJob.Id switch { Job.WHM @@ -446,21 +447,53 @@ or Job.RDM /// /// /// - public static IBaseAction LostRampage { get; } = new BaseAction(ActionID.LostRampage, - ActionOption.DutyAction | ActionOption.Friendly) - { - StatusProvide = new StatusID[] { StatusID.LostRampage }, - ActionCheck = (b, m) => LostRampage.Target?.HasStatus(false, StatusID.PhysicalAversion) ?? false, + public static IBaseAction LostRampage { get; } = new RoleAction( + ActionID.LostRampage, + new JobRole[] { JobRole.Melee, JobRole.Tank, JobRole.RangedPhysical }, + ActionOption.DutyAction | ActionOption.Eot + ) { + TargetStatus = new StatusID[] { StatusID.LostRampage }, + // TargetStatusIsGlobal = true, + FilterForHostiles = (targets) => targets.Where(tar => + ObjectHelper.CanInterrupt(tar) || + (tar.IsBossFromIcon() && tar.HasStatus(false, StatusID.PhysicalAversion))) }; /// /// /// - public static IBaseAction LostBurst { get; } = new BaseAction(ActionID.LostBurst, - ActionOption.DutyAction | ActionOption.Friendly) - { - StatusProvide = new StatusID[] { StatusID.LostBurst }, - ActionCheck = (b, m) => LostBurst.Target?.HasStatus(false, StatusID.MagicalAversion) ?? false, + public static IBaseAction LostBurst { get; } = new RoleAction( + ActionID.LostBurst, + new JobRole[] { JobRole.Healer, JobRole.RangedMagical }, + ActionOption.DutyAction | ActionOption.Eot + ) { + TargetStatus = new StatusID[] { StatusID.LostBurst }, + // TargetStatusIsGlobal = true, + FilterForHostiles = (targets) => targets.Where(tar => + ObjectHelper.CanInterrupt(tar) || + (tar.IsBossFromIcon() && tar.HasStatus(false, StatusID.MagicalAversion))), + }; + + /// + /// + /// + public static IBaseAction LostAssassination { get; } = new RoleAction( + ActionID.LostAssassination, + new JobRole[] { JobRole.Melee, JobRole.Tank, JobRole.RangedPhysical }, + ActionOption.DutyAction + ) { + ActionCheck = (tar, mustUse) => { + if (tar.IsBossFromIcon()) { + // use for Lost Font of Power on bosses + return Player.HasStatus(true, StatusID.SpiritOfTheBeast) && !tar.IsDying(); + } else if (Service.Config.GetValue(PluginConfigBool.UseLostAssassinationOnMobs)) { + // use to instakill tanky mobs + var ttk = Service.Config.GetValue(PluginConfigFloat.LostAssassinationTimeToKill); + return tar.FindEnemyPositional() == EnemyPositional.Rear && tar.GetTimeToKill(true) >= ttk; + } + + return false; + } }; /// @@ -469,7 +502,8 @@ or Job.RDM public static IBaseAction LostBravery { get; } = new BaseAction(ActionID.LostBravery, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostBravery }, + TargetStatus = new StatusID[] { StatusID.LostBravery }, + // TargetStatusIsGlobal = true, }; /// @@ -478,7 +512,8 @@ or Job.RDM public static IBaseAction LostProtect { get; } = new BaseAction(ActionID.LostProtect, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostProtect, StatusID.LostProtect2 }, + TargetStatus = new StatusID[] { StatusID.LostProtect, StatusID.LostProtect2 }, + // TargetStatusIsGlobal = true, }; /// @@ -487,7 +522,8 @@ or Job.RDM public static IBaseAction LostShell { get; } = new BaseAction(ActionID.LostShell, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostShell, StatusID.LostShell2 }, + TargetStatus = new StatusID[] { StatusID.LostShell, StatusID.LostShell2 }, + // TargetStatusIsGlobal = true, }; /// @@ -496,7 +532,8 @@ or Job.RDM public static IBaseAction LostProtect2 { get; } = new BaseAction(ActionID.LostProtect2, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostProtect2 }, + TargetStatus = new StatusID[] { StatusID.LostProtect2 }, + // TargetStatusIsGlobal = true, }; /// @@ -505,7 +542,8 @@ or Job.RDM public static IBaseAction LostShell2 { get; } = new BaseAction(ActionID.LostShell2, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostShell2 }, + TargetStatus = new StatusID[] { StatusID.LostShell2 }, + // TargetStatusIsGlobal = true, }; /// @@ -514,7 +552,8 @@ or Job.RDM public static IBaseAction LostBubble { get; } = new BaseAction(ActionID.LostBubble, ActionOption.DutyAction | ActionOption.Friendly) { - StatusProvide = new StatusID[] { StatusID.LostBubble }, + TargetStatus = new StatusID[] { StatusID.LostBubble }, + // TargetStatusIsGlobal = true, }; /// @@ -524,7 +563,8 @@ or Job.RDM ActionOption.DutyAction | ActionOption.Defense) { ChoiceTarget = TargetFilter.FindAttackedTarget, - StatusProvide = new StatusID[] { StatusID.LostStoneskin }, + TargetStatus = new StatusID[] { StatusID.LostStoneskin }, + // TargetStatusIsGlobal = true, }; /// @@ -540,9 +580,20 @@ or Job.RDM /// /// public static IBaseAction LostFlarestar { get; } = new BaseAction(ActionID.LostFlarestar, - ActionOption.DutyAction) + ActionOption.DutyAction | ActionOption.Dot) { - StatusProvide = new StatusID[] { StatusID.LostFlarestar }, + FilterForHostiles = (tars) => tars.Where(t => t.IsBossFromIcon() || Service.Config.GetValue(PluginConfigBool.UseLostFlareStarOnMobs)), + TargetStatus = new StatusID[] { StatusID.LostFlarestar }, + // TargetStatusIsGlobal = true, + }; + + /// + /// + /// + public static IBaseAction LostReflect { get; } = new BaseAction(ActionID.LostReflect, ActionOption.DutyAction | ActionOption.Friendly) { + ChoiceTarget = (tars, mustUse) => tars.FirstOrDefault(b => + b.HasStatus(true, StatusID.LostReflect) && + b.WillStatusEndGCD(1, 0, true, StatusID.LostReflect)) }; /// @@ -551,7 +602,21 @@ or Job.RDM public static IBaseAction LostSeraphStrike { get; } = new BaseAction(ActionID.LostSeraphStrike, ActionOption.DutyAction) { - StatusProvide = new StatusID[] { StatusID.LostSeraphStrike }, + TargetStatus = new StatusID[] { StatusID.LostSeraphStrike }, + }; + + /// + /// + /// + public static IBaseAction LostFontOfPower { get; } = new BaseAction(ActionID.LostFontOfPower, ActionOption.DutyAction) { + StatusProvide = new StatusID[] { StatusID.LostFontOfPower }, + }; + + /// + /// + /// + public static IBaseAction BannerOfHonoredSacrifice { get; } = new BaseAction(ActionID.BannerOfHonoredSacrifice, ActionOption.DutyAction) { + StatusProvide = new StatusID[] { StatusID.BannerOfHonoredSacrifice }, }; #endregion diff --git a/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs b/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs index 4cc89eab3..1b615adf9 100644 --- a/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs +++ b/RotationSolver.Basic/Rotations/CustomRotation_GCD.cs @@ -183,22 +183,16 @@ private static bool EsunaAction(out IAction act, CanUseOption option = CanUseOpt protected virtual bool EmergencyGCD(out IAction act) { #region Bozja - if (LostSpellforge.CanUse(out act)) return true; - if (LostSteelsting.CanUse(out act)) return true; + if (LostFlarestar.CanUse(out act)) return true; if (LostRampage.CanUse(out act)) return true; if (LostBurst.CanUse(out act)) return true; - + if (Service.Config.GetValue(PluginConfigBool.LostReflectAutoRefresh) && LostReflect.CanUse(out act)) return true; if (LostBravery.CanUse(out act)) return true; if (LostBubble.CanUse(out act)) return true; if (LostShell2.CanUse(out act)) return true; if (LostShell.CanUse(out act)) return true; if (LostProtect2.CanUse(out act)) return true; if (LostProtect.CanUse(out act)) return true; - - //Add your own logic here. - //if (LostFlarestar.CanUse(out act)) return true; - //if (LostSeraphStrike.CanUse(out act)) return true; - #endregion #region PvP diff --git a/RotationSolver/Localization/ConfigTranslation.cs b/RotationSolver/Localization/ConfigTranslation.cs index 64f18fec2..910f08fbf 100644 --- a/RotationSolver/Localization/ConfigTranslation.cs +++ b/RotationSolver/Localization/ConfigTranslation.cs @@ -118,6 +118,10 @@ internal static class ConfigTranslation PluginConfigBool.HealWhenNothingTodo => LocalizationManager.RightLang.ConfigWindow_Param_HealWhenNothingTodo, PluginConfigBool.UseResourcesAction => LocalizationManager.RightLang.ConfigWindow_Auto_UseResourcesAction, PluginConfigBool.OnlyHealSelfWhenNoHealer => LocalizationManager.RightLang.ConfigWindow_Auto_OnlyHealSelfWhenNoHealer, + PluginConfigBool.UseLostActions => LocalizationManager.RightLang.ConfigWindow_Auto_UseLostActions, + PluginConfigBool.UseLostFlareStarOnMobs => LocalizationManager.RightLang.ConfigWindow_Auto_UseLostFlareStarOnMobs, + PluginConfigBool.UseLostAssassinationOnMobs => LocalizationManager.RightLang.ConfigWindow_Auto_UseLostAssassinationOnMobs, + PluginConfigBool.LostReflectAutoRefresh => LocalizationManager.RightLang.ConfigWindow_Auto_LostReflectAutoRefresh, // target PluginConfigBool.AddEnemyListToHostile => LocalizationManager.RightLang.ConfigWindow_Param_AddEnemyListToHostile, @@ -204,6 +208,7 @@ internal static class ConfigTranslation PluginConfigFloat.AutoHealTimeToKill => LocalizationManager.RightLang.ConfigWindow_Auto_AutoHealTimeToKill, PluginConfigFloat.ProvokeDelayMin => LocalizationManager.RightLang.ConfigWindow_Auto_ProvokeDelay, PluginConfigFloat.HealthForGuard => LocalizationManager.RightLang.ConfigWindow_Param_HealthForGuard, + PluginConfigFloat.LostAssassinationTimeToKill => LocalizationManager.RightLang.ConfigWindow_Auto_LostAssassinationTimeToKill, // target PluginConfigFloat.BossTimeToKill => LocalizationManager.RightLang.ConfigWindow_Param_BossTimeToKill, PluginConfigFloat.DyingTimeToKill => LocalizationManager.RightLang.ConfigWindow_Param_DyingTimeToKill, diff --git a/RotationSolver/Localization/Strings.cs b/RotationSolver/Localization/Strings.cs index 15b7436ef..5adb05034 100644 --- a/RotationSolver/Localization/Strings.cs +++ b/RotationSolver/Localization/Strings.cs @@ -792,6 +792,11 @@ internal class Strings public string ConfigWindow_Auto_UseResourcesAction { get; set; } = "Use actions that use resources"; public string ConfigWindow_Auto_OnlyHealSelfWhenNoHealer { get; set; } = "Only Heal self When Not a healer"; + public string ConfigWindow_Auto_UseLostActions { get; set; } = "Use Lost Actions (Bozja)"; + public string ConfigWindow_Auto_UseLostFlareStarOnMobs { get; set; } = "Use Lost Flare Star on non-boss targets"; + public string ConfigWindow_Auto_UseLostAssassinationOnMobs { get; set; } = "Use Lost Assassination to kill non-boss targets"; + public string ConfigWindow_Auto_LostReflectAutoRefresh { get; set; } = "Automatically refresh Lost Reflect before it expires"; + public string ConfigWindow_Auto_LostAssassinationTimeToKill { get; set; } = "Expected TTK required to use Lost Assassination on target"; public string ConfigWindow_Auto_HealthForAutoDefense { get; set; } = "HP Ratio about defense single of Tanks"; public string ConfigWindow_Basic_SayHelloToUsers { get; set; } = "Say hello to the users of Rotation Solver."; @@ -838,4 +843,4 @@ internal class Strings public string ConfigWindow_Condition_DutyName { get; set; } = "Duty Name"; public string ConfigWindow_Condition_TargetWarning { get; set; } = "You'd better not use it. Because this target isn't the action's target. Try to pick it from action."; -} \ No newline at end of file +} diff --git a/RotationSolver/UI/RotationConfigWindow_Config.cs b/RotationSolver/UI/RotationConfigWindow_Config.cs index 6484d00d0..ed2369c2d 100644 --- a/RotationSolver/UI/RotationConfigWindow_Config.cs +++ b/RotationSolver/UI/RotationConfigWindow_Config.cs @@ -834,6 +834,13 @@ private static void DrawAutoActionCondition() new CheckBoxSearchPlugin(PluginConfigBool.AutoSpeedOutOfCombat), }), + + new CheckBoxSearchPlugin(PluginConfigBool.UseLostActions, new ISearchable[] { + new CheckBoxSearchPlugin(PluginConfigBool.UseLostFlareStarOnMobs), + new CheckBoxSearchPlugin(PluginConfigBool.UseLostAssassinationOnMobs, + new DragFloatSearchPlugin(PluginConfigFloat.LostAssassinationTimeToKill, 0.5f)), + new CheckBoxSearchPlugin(PluginConfigBool.LostReflectAutoRefresh) + }), }; #endregion