From 887bb607ae1fd0b5e0bc4771cb9fb61b77a2e134 Mon Sep 17 00:00:00 2001 From: Wiktor Phillips Date: Tue, 24 Sep 2024 17:52:03 -0400 Subject: [PATCH 1/7] wip --- proto/paladin.proto | 8 ++-- sim/paladin/paladin.go | 56 +++++++++++++++++++------- sim/paladin/protection/protection.go | 16 ++------ sim/paladin/retribution/retribution.go | 18 ++++----- ui/protection_paladin/inputs.ts | 34 ++++++++++++++++ ui/retribution_paladin/inputs.ts | 22 +++++----- ui/retribution_paladin/sim.ts | 2 +- 7 files changed, 105 insertions(+), 51 deletions(-) diff --git a/proto/paladin.proto b/proto/paladin.proto index 1017a91d63..20454c3089 100644 --- a/proto/paladin.proto +++ b/proto/paladin.proto @@ -131,12 +131,14 @@ enum PaladinSeal { message PaladinOptions { PaladinSeal primarySeal = 1; PaladinAura aura = 2; + bool IsUsingAllAbilitiesStopAttack = 3; bool IsUsingDivineStormStopAttack = 4; bool IsUsingJudgementStopAttack = 5; bool IsUsingCrusaderStrikeStopAttack = 6; - - bool righteousFury = 8; - Blessings personalBlessing = 9; + bool IsUsingHammerOfTheRighteousStopAttack = 7; + bool IsUsingShieldOfRighteousnessStopAttack = 8; + bool righteousFury = 9; + Blessings personalBlessing = 10; } message RetributionPaladin { diff --git a/sim/paladin/paladin.go b/sim/paladin/paladin.go index 55a6c35e3e..22a3e29b81 100644 --- a/sim/paladin/paladin.go +++ b/sim/paladin/paladin.go @@ -17,12 +17,21 @@ const ( ) const ( - SpellCode_PaladinNone = iota - + SpellCode_PaladinNone int32 = 0 + // Judgements + SpellCode_PaladinJudgementOfCommand = 1 << iota + SpellCode_PaladinJudgementOfMartyrdom + SpellCode_PaladinJudgementOfRighteousness + SpellCode_PaladinJudgementOfTheCrusader + // Special attacks that enable autoattacks/trigger extra attacks + SpellCode_PaladinCrusaderStrike + SpellCode_PaladinDivineStorm + SpellCode_PaladinHammerOfTheRighteous + SpellCode_PaladinShieldOfRighteousness + // Other spells SpellCode_PaladinExorcism SpellCode_PaladinHolyShock SpellCode_PaladinHolyWrath - SpellCode_PaladinJudgementOfCommand SpellCode_PaladinConsecration SpellCode_PaladinAvengersShield SpellCode_PaladinHolyShield @@ -30,6 +39,11 @@ const ( SpellCode_PaladinLayOnHands ) +const ( + SpellCode_PaladinJudgements int32 = SpellCode_PaladinJudgementOfCommand | SpellCode_PaladinJudgementOfMartyrdom | SpellCode_PaladinJudgementOfRighteousness | SpellCode_PaladinJudgementOfTheCrusader + SpellCode_PaladinTriggersExtraAttack = SpellCode_PaladinJudgements | SpellCode_PaladinCrusaderStrike | SpellCode_PaladinDivineStorm | SpellCode_PaladinHammerOfTheRighteous | SpellCode_PaladinShieldOfRighteousness +) + type SealJudgeCode uint8 const ( @@ -86,6 +100,7 @@ type Paladin struct { enableMultiJudge bool lingerDuration time.Duration consumeSealsOnJudge bool + stopAttackMacroMask int32 } // Implemented by each Paladin spec. @@ -109,6 +124,8 @@ func (paladin *Paladin) AddPartyBuffs(_ *proto.PartyBuffs) { } func (paladin *Paladin) Initialize() { + paladin.stopAttackMacroMask = paladin.getStopAttackMacroMask() + paladin.registerStopAttackMacros() paladin.registerRighteousFury() // Judgement and Seals paladin.registerJudgement() @@ -149,7 +166,6 @@ func (paladin *Paladin) Initialize() { paladin.lingerDuration = time.Millisecond * 400 paladin.consumeSealsOnJudge = true - paladin.registerStopAttackMacros() } func (paladin *Paladin) Reset(_ *core.Simulation) { @@ -202,22 +218,34 @@ func (paladin *Paladin) ResetPrimarySeal(primarySeal proto.PaladinSeal) { } func (paladin *Paladin) registerStopAttackMacros() { + paladin.OnSpellRegistered(func(spell *core.Spell) { + if paladin.stopAttackMacroMask&spell.SpellCode != 0 { + spell.Flags |= core.SpellFlagBatchStopAttackMacro + } + }) +} - if paladin.divineStorm != nil && paladin.Options.IsUsingDivineStormStopAttack { - paladin.divineStorm.Flags |= core.SpellFlagBatchStopAttackMacro +func (paladin *Paladin) getStopAttackMacroMask() int32 { + options := paladin.Options + if options.IsUsingAllAbilitiesStopAttack { + return SpellCode_PaladinTriggersExtraAttack } - if paladin.crusaderStrike != nil && paladin.Options.IsUsingCrusaderStrikeStopAttack { - paladin.crusaderStrike.Flags |= core.SpellFlagBatchStopAttackMacro + bitMask := SpellCode_PaladinNone + + spellCodes := []int32{ + core.TernaryInt32(options.IsUsingJudgementStopAttack, SpellCode_PaladinJudgements, SpellCode_PaladinNone), + core.TernaryInt32(options.IsUsingCrusaderStrikeStopAttack, SpellCode_PaladinCrusaderStrike, SpellCode_PaladinNone), + core.TernaryInt32(options.IsUsingDivineStormStopAttack, SpellCode_PaladinDivineStorm, SpellCode_PaladinNone), + core.TernaryInt32(options.IsUsingHammerOfTheRighteousStopAttack, SpellCode_PaladinHammerOfTheRighteous, SpellCode_PaladinNone), + core.TernaryInt32(options.IsUsingShieldOfRighteousnessStopAttack, SpellCode_PaladinShieldOfRighteousness, SpellCode_PaladinNone), } - for _, spellsJoX := range paladin.allJudgeSpells { - for _, v := range spellsJoX { - if v != nil && paladin.Options.IsUsingJudgementStopAttack { - v.Flags |= core.SpellFlagBatchStopAttackMacro - } - } + for _, spellCode := range spellCodes { + bitMask |= spellCode } + + return bitMask } func (paladin *Paladin) ResetCurrentPaladinAura() { diff --git a/sim/paladin/protection/protection.go b/sim/paladin/protection/protection.go index be86edc986..003913393a 100644 --- a/sim/paladin/protection/protection.go +++ b/sim/paladin/protection/protection.go @@ -29,13 +29,8 @@ func NewProtectionPaladin(character *core.Character, options *proto.Player) *Pro pal := paladin.NewPaladin(character, options, protOptions) prot := &ProtectionPaladin{ - Paladin: pal, - primarySeal: protOptions.PrimarySeal, - righteousFury: protOptions.RighteousFury, - IsUsingDivineStormStopAttack: protOptions.IsUsingDivineStormStopAttack, - IsUsingJudgementStopAttack: protOptions.IsUsingJudgementStopAttack, - IsUsingCrusaderStrikeStopAttack: protOptions.IsUsingCrusaderStrikeStopAttack, - personalBlessing: protOptions.PersonalBlessing, + Paladin: pal, + primarySeal: protOptions.PrimarySeal, } prot.EnableAutoAttacks(prot, core.AutoAttackOptions{ @@ -49,12 +44,7 @@ func NewProtectionPaladin(character *core.Character, options *proto.Player) *Pro type ProtectionPaladin struct { *paladin.Paladin - primarySeal proto.PaladinSeal - righteousFury bool - IsUsingDivineStormStopAttack bool - IsUsingJudgementStopAttack bool - IsUsingCrusaderStrikeStopAttack bool - personalBlessing proto.Blessings + primarySeal proto.PaladinSeal } func (prot *ProtectionPaladin) GetPaladin() *paladin.Paladin { diff --git a/sim/paladin/retribution/retribution.go b/sim/paladin/retribution/retribution.go index f97bba5a7c..9a0ab1db37 100644 --- a/sim/paladin/retribution/retribution.go +++ b/sim/paladin/retribution/retribution.go @@ -29,11 +29,11 @@ func NewRetributionPaladin(character *core.Character, options *proto.Player) *Re pal := paladin.NewPaladin(character, options, retOptions) ret := &RetributionPaladin{ - Paladin: pal, - primarySeal: retOptions.PrimarySeal, - IsUsingDivineStormStopAttack: retOptions.IsUsingDivineStormStopAttack, - IsUsingJudgementStopAttack: retOptions.IsUsingJudgementStopAttack, - IsUsingCrusaderStrikeStopAttack: retOptions.IsUsingCrusaderStrikeStopAttack, + Paladin: pal, + primarySeal: retOptions.PrimarySeal, + //IsUsingDivineStormStopAttack: retOptions.IsUsingDivineStormStopAttack, + //IsUsingJudgementStopAttack: retOptions.IsUsingJudgementStopAttack, + //IsUsingCrusaderStrikeStopAttack: retOptions.IsUsingCrusaderStrikeStopAttack, } ret.EnableAutoAttacks(ret, core.AutoAttackOptions{ @@ -47,10 +47,10 @@ func NewRetributionPaladin(character *core.Character, options *proto.Player) *Re type RetributionPaladin struct { *paladin.Paladin - primarySeal proto.PaladinSeal - IsUsingDivineStormStopAttack bool - IsUsingJudgementStopAttack bool - IsUsingCrusaderStrikeStopAttack bool + primarySeal proto.PaladinSeal + //IsUsingDivineStormStopAttack bool + //IsUsingJudgementStopAttack bool + //IsUsingCrusaderStrikeStopAttack bool } func (ret *RetributionPaladin) GetPaladin() *paladin.Paladin { diff --git a/ui/protection_paladin/inputs.ts b/ui/protection_paladin/inputs.ts index 266ab88c20..e610721bff 100644 --- a/ui/protection_paladin/inputs.ts +++ b/ui/protection_paladin/inputs.ts @@ -46,6 +46,40 @@ export const RighteousFuryToggle = InputHelpers.makeSpecOptionsBooleanIconInput< changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), }); +export const StopAttackAbilitySelection = InputHelpers.makeMultiIconInput({ + values: [ + InputHelpers.makeSpecOptionsBooleanIconInput({ + fieldName: 'isUsingJudgementStopAttack', + actionId: () => ActionId.fromSpellId(20271), + }), + InputHelpers.makeSpecOptionsBooleanIconInput({ + fieldName: 'isUsingDivineStormStopAttack', + actionId: () => ActionId.fromSpellId(407778), + showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotChest, PaladinRune.RuneChestDivineStorm), + changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), + }), + InputHelpers.makeSpecOptionsBooleanIconInput({ + fieldName: 'isUsingCrusaderStrikeStopAttack', + actionId: () => ActionId.fromSpellId(407676), + showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotHands, PaladinRune.RuneHandsCrusaderStrike), + changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), + }), + InputHelpers.makeSpecOptionsBooleanIconInput({ + fieldName: 'isUsingHammerOfTheRighteousStopAttack', + actionId: () => ActionId.fromSpellId(407632), + showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotWrist, PaladinRune.RuneWristHammerOfTheRighteous), + changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), + }), + InputHelpers.makeSpecOptionsBooleanIconInput({ + fieldName: 'isUsingShieldOfRighteousnessStopAttack', + actionId: () => ActionId.fromSpellId(440658), + showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotBack, PaladinRune.RuneCloakShieldOfRighteousness), + changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), + }), + ], + label: 'Stop Attack Macro Abilities', +}); + // The below is used in the custom APL action "Cast Primary Seal". // Only shows SoC if it's talented. export const PrimarySealSelection = InputHelpers.makeSpecOptionsEnumIconInput({ diff --git a/ui/retribution_paladin/inputs.ts b/ui/retribution_paladin/inputs.ts index 1436b6b004..67cf15eacc 100644 --- a/ui/retribution_paladin/inputs.ts +++ b/ui/retribution_paladin/inputs.ts @@ -9,17 +9,17 @@ import { TypedEvent } from '../core/typed_event.js'; // These don't need to be in a separate file but it keeps things cleaner. export const AuraSelection = InputHelpers.makeSpecOptionsEnumIconInput({ - fieldName: 'aura', - values: [ - { value: PaladinAura.NoPaladinAura, tooltip: 'No Aura' }, - { actionId: () => ActionId.fromSpellId(20218), value: PaladinAura.SanctityAura }, - //{ actionId: () => ActionId.fromSpellId(10299), value: PaladinAura.DevotionAura }, - //{ actionId: () => ActionId.fromSpellId(10299), value: PaladinAura.RetributionAura }, - //{ actionId: () => ActionId.fromSpellId(19746), value: PaladinAura.ConcentrationAura }, - //{ actionId: () => ActionId.fromSpellId(19888), value: PaladinAura.FrostResistanceAura }, - //{ actionId: () => ActionId.fromSpellId(19892), value: PaladinAura.ShadowResistanceAura }, - //{ actionId: () => ActionId.fromSpellId(19891), value: PaladinAura.FireResistanceAura }, - ], + fieldName: 'aura', + values: [ + { value: PaladinAura.NoPaladinAura, tooltip: 'No Aura' }, + { actionId: () => ActionId.fromSpellId(20218), value: PaladinAura.SanctityAura }, + //{ actionId: () => ActionId.fromSpellId(10299), value: PaladinAura.DevotionAura }, + //{ actionId: () => ActionId.fromSpellId(10299), value: PaladinAura.RetributionAura }, + //{ actionId: () => ActionId.fromSpellId(19746), value: PaladinAura.ConcentrationAura }, + //{ actionId: () => ActionId.fromSpellId(19888), value: PaladinAura.FrostResistanceAura }, + //{ actionId: () => ActionId.fromSpellId(19892), value: PaladinAura.ShadowResistanceAura }, + //{ actionId: () => ActionId.fromSpellId(19891), value: PaladinAura.FireResistanceAura }, + ], }); // The below is used in the custom APL action "Cast Primary Seal". diff --git a/ui/retribution_paladin/sim.ts b/ui/retribution_paladin/sim.ts index 6b42d7f763..cda9afce6c 100644 --- a/ui/retribution_paladin/sim.ts +++ b/ui/retribution_paladin/sim.ts @@ -119,7 +119,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRetributionPaladin, { excludeBuffDebuffInputs: [], // Inputs to include in the 'Other' section on the settings tab. otherInputs: { - inputs: [OtherInputs.TankAssignment, OtherInputs.InFrontOfTarget, RetributionPaladinInputs.CrusaderStrikeStopAttack, RetributionPaladinInputs.JudgementStopAttack, RetributionPaladinInputs.DivineStormStopAttack], + inputs: [OtherInputs.TankAssignment, OtherInputs.InFrontOfTarget], //, RetributionPaladinInputs.CrusaderStrikeStopAttack, RetributionPaladinInputs.JudgementStopAttack, RetributionPaladinInputs.DivineStormStopAttack], }, encounterPicker: { // Whether to include 'Execute Duration (%)' in the 'Encounter' section of the settings tab. From 6d983a0b19c885f07173e8d7a2b2fdfdd23d8b6b Mon Sep 17 00:00:00 2001 From: Wiktor Phillips Date: Sat, 28 Sep 2024 17:07:43 -0400 Subject: [PATCH 2/7] wip --- ui/protection_paladin/sim.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/protection_paladin/sim.ts b/ui/protection_paladin/sim.ts index 7d445e5081..103b2d5bae 100644 --- a/ui/protection_paladin/sim.ts +++ b/ui/protection_paladin/sim.ts @@ -170,7 +170,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { ProtectionPaladinInputs.AuraSelection, ], // Buff and Debuff inputs to include/exclude, overriding the EP-based defaults. - includeBuffDebuffInputs: [BuffDebuffInputs.SpellScorchDebuff], + includeBuffDebuffInputs: [BuffDebuffInputs.SpellScorchDebuff, ProtectionPaladinInputs.StopAttackAbilitySelection], excludeBuffDebuffInputs: [], // Inputs to include in the 'Other' section on the settings tab. otherInputs: { From 175ce2be37105f12e0c9b06661793b674b031a89 Mon Sep 17 00:00:00 2001 From: Wiktor Phillips Date: Sat, 28 Sep 2024 20:34:02 -0400 Subject: [PATCH 3/7] setup manual attacks for prot --- proto/paladin.proto | 2 +- sim/paladin/crusader_strike.go | 1 + sim/paladin/divine_storm.go | 3 ++- sim/paladin/hammer_of_the_righteous.go | 1 + sim/paladin/item_sets_pve.go | 6 ++++- sim/paladin/paladin.go | 2 +- sim/paladin/runes.go | 6 ++++- sim/paladin/shield_of_righteousness.go | 4 ++- sim/paladin/som.go | 1 + sim/paladin/sor.go | 1 + sim/paladin/sotc.go | 1 + sim/paladin/talents.go | 6 ++++- ui/protection_paladin/inputs.ts | 36 +++----------------------- ui/protection_paladin/sim.ts | 3 ++- ui/retribution_paladin/sim.ts | 8 +++++- 15 files changed, 40 insertions(+), 41 deletions(-) diff --git a/proto/paladin.proto b/proto/paladin.proto index 20454c3089..601bb4048a 100644 --- a/proto/paladin.proto +++ b/proto/paladin.proto @@ -131,7 +131,7 @@ enum PaladinSeal { message PaladinOptions { PaladinSeal primarySeal = 1; PaladinAura aura = 2; - bool IsUsingAllAbilitiesStopAttack = 3; + bool IsManuallyTriggeringAutoAttacks = 3; bool IsUsingDivineStormStopAttack = 4; bool IsUsingJudgementStopAttack = 5; bool IsUsingCrusaderStrikeStopAttack = 6; diff --git a/sim/paladin/crusader_strike.go b/sim/paladin/crusader_strike.go index bd8628f2f8..4b7249f69d 100644 --- a/sim/paladin/crusader_strike.go +++ b/sim/paladin/crusader_strike.go @@ -20,6 +20,7 @@ func (paladin *Paladin) registerCrusaderStrike() { crusaderStrikeSpell := paladin.RegisterSpell(core.SpellConfig{ ActionID: manaMetrics.ActionID, + SpellCode: SpellCode_PaladinCrusaderStrike, SpellSchool: core.SpellSchoolHoly, DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, diff --git a/sim/paladin/divine_storm.go b/sim/paladin/divine_storm.go index c6463779bc..5793d7ddb1 100644 --- a/sim/paladin/divine_storm.go +++ b/sim/paladin/divine_storm.go @@ -23,6 +23,7 @@ func (paladin *Paladin) registerDivineStorm() { divineStormSpell := paladin.RegisterSpell(core.SpellConfig{ ActionID: healthMetrics.ActionID, + SpellCode: SpellCode_PaladinDivineStorm, SpellSchool: core.SpellSchoolPhysical, DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, @@ -59,6 +60,6 @@ func (paladin *Paladin) registerDivineStorm() { paladin.GainHealth(sim, totalDamageDealt*0.25, healthMetrics) }, }) - + paladin.divineStorm = divineStormSpell } diff --git a/sim/paladin/hammer_of_the_righteous.go b/sim/paladin/hammer_of_the_righteous.go index 0c99a5b024..68decd782e 100644 --- a/sim/paladin/hammer_of_the_righteous.go +++ b/sim/paladin/hammer_of_the_righteous.go @@ -19,6 +19,7 @@ func (paladin *Paladin) registerHammerOfTheRighteous() { paladin.GetOrRegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.PaladinRune_RuneWristHammerOfTheRighteous)}, + SpellCode: SpellCode_PaladinHammerOfTheRighteous, SpellSchool: core.SpellSchoolHoly, DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, diff --git a/sim/paladin/item_sets_pve.go b/sim/paladin/item_sets_pve.go index eb52fb298d..fb70d3d380 100644 --- a/sim/paladin/item_sets_pve.go +++ b/sim/paladin/item_sets_pve.go @@ -407,7 +407,11 @@ var ItemSetWilfullJudgement = core.NewItemSet(core.ItemSet{ procChance := 0.2 * float64(paladin.Talents.Reckoning) handler := func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - paladin.AutoAttacks.ExtraMHAttack(sim, 1, actionID, spell.ActionID) + if paladin.Options.IsManuallyTriggeringAutoAttacks { + paladin.AutoAttacks.StoreExtraMHAttack(sim, 1, actionID, spell.ActionID) + } else { + paladin.AutoAttacks.ExtraMHAttack(sim, 1, actionID, spell.ActionID) + } } core.MakeProcTriggerAura(&c.Unit, core.ProcTrigger{ diff --git a/sim/paladin/paladin.go b/sim/paladin/paladin.go index 72c3bcb301..026366e99e 100644 --- a/sim/paladin/paladin.go +++ b/sim/paladin/paladin.go @@ -227,7 +227,7 @@ func (paladin *Paladin) registerStopAttackMacros() { func (paladin *Paladin) getStopAttackMacroMask() int32 { options := paladin.Options - if options.IsUsingAllAbilitiesStopAttack { + if options.IsManuallyTriggeringAutoAttacks { return SpellCode_PaladinTriggersExtraAttack } diff --git a/sim/paladin/runes.go b/sim/paladin/runes.go index f45ec91322..5f80f36677 100644 --- a/sim/paladin/runes.go +++ b/sim/paladin/runes.go @@ -226,7 +226,11 @@ func (paladin *Paladin) registerAegis() { Outcome: core.OutcomeLanded, ProcChance: procChance, Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - paladin.AutoAttacks.ExtraMHAttack(sim, 1, procID, spell.ActionID) + if paladin.Options.IsManuallyTriggeringAutoAttacks { + paladin.AutoAttacks.StoreExtraMHAttack(sim, 1, procID, spell.ActionID) + } else { + paladin.AutoAttacks.ExtraMHAttack(sim, 1, procID, spell.ActionID) + } }, }) } diff --git a/sim/paladin/shield_of_righteousness.go b/sim/paladin/shield_of_righteousness.go index 800ea42cd7..854b6441f3 100644 --- a/sim/paladin/shield_of_righteousness.go +++ b/sim/paladin/shield_of_righteousness.go @@ -1,9 +1,10 @@ package paladin import ( + "time" + "github.com/wowsims/sod/sim/core" "github.com/wowsims/sod/sim/core/proto" - "time" ) func (paladin *Paladin) registerShieldOfRighteousness() { @@ -17,6 +18,7 @@ func (paladin *Paladin) registerShieldOfRighteousness() { paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: int32(proto.PaladinRune_RuneCloakShieldOfRighteousness)}, + SpellCode: SpellCode_PaladinShieldOfRighteousness, SpellSchool: core.SpellSchoolHoly, DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, diff --git a/sim/paladin/som.go b/sim/paladin/som.go index a5899fd941..b02dc4d500 100644 --- a/sim/paladin/som.go +++ b/sim/paladin/som.go @@ -18,6 +18,7 @@ func (paladin *Paladin) registerSealOfMartyrdom() { judgeSpell := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: 407803}, + SpellCode: SpellCode_PaladinJudgementOfMartyrdom, SpellSchool: core.SpellSchoolHoly, DefenseType: core.DefenseTypeMelee, ProcMask: core.ProcMaskMeleeMHSpecial, diff --git a/sim/paladin/sor.go b/sim/paladin/sor.go index 85796cfd3e..67057c86d4 100644 --- a/sim/paladin/sor.go +++ b/sim/paladin/sor.go @@ -72,6 +72,7 @@ func (paladin *Paladin) registerSealOfRighteousness() { judgeSpell := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: rank.judge.spellID}, + SpellCode: SpellCode_PaladinJudgementOfRighteousness, SpellSchool: core.SpellSchoolHoly, DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskSpellDamage, diff --git a/sim/paladin/sotc.go b/sim/paladin/sotc.go index e0cdbba860..b750c03fa0 100644 --- a/sim/paladin/sotc.go +++ b/sim/paladin/sotc.go @@ -51,6 +51,7 @@ func (paladin *Paladin) registerSealOfTheCrusader() { judgeSpell := paladin.RegisterSpell(core.SpellConfig{ ActionID: core.ActionID{SpellID: rank.judge.spellID}, + SpellCode: SpellCode_PaladinJudgementOfTheCrusader, SpellSchool: core.SpellSchoolHoly, DefenseType: core.DefenseTypeMagic, ProcMask: core.ProcMaskEmpty, diff --git a/sim/paladin/talents.go b/sim/paladin/talents.go index 4c2e889d45..85147282cd 100644 --- a/sim/paladin/talents.go +++ b/sim/paladin/talents.go @@ -109,7 +109,11 @@ func (paladin *Paladin) applyReckoning() { ProcMask: core.ProcMaskMeleeOrRanged, ProcChance: procChance, Handler: func(sim *core.Simulation, spell *core.Spell, result *core.SpellResult) { - paladin.AutoAttacks.ExtraMHAttack(sim, 1, procID, spell.ActionID) + if paladin.Options.IsManuallyTriggeringAutoAttacks { + paladin.AutoAttacks.StoreExtraMHAttack(sim, 1, procID, spell.ActionID) + } else { + paladin.AutoAttacks.ExtraMHAttack(sim, 1, procID, spell.ActionID) + } }, }) } diff --git a/ui/protection_paladin/inputs.ts b/ui/protection_paladin/inputs.ts index e610721bff..74262c62d4 100644 --- a/ui/protection_paladin/inputs.ts +++ b/ui/protection_paladin/inputs.ts @@ -46,38 +46,10 @@ export const RighteousFuryToggle = InputHelpers.makeSpecOptionsBooleanIconInput< changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), }); -export const StopAttackAbilitySelection = InputHelpers.makeMultiIconInput({ - values: [ - InputHelpers.makeSpecOptionsBooleanIconInput({ - fieldName: 'isUsingJudgementStopAttack', - actionId: () => ActionId.fromSpellId(20271), - }), - InputHelpers.makeSpecOptionsBooleanIconInput({ - fieldName: 'isUsingDivineStormStopAttack', - actionId: () => ActionId.fromSpellId(407778), - showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotChest, PaladinRune.RuneChestDivineStorm), - changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), - }), - InputHelpers.makeSpecOptionsBooleanIconInput({ - fieldName: 'isUsingCrusaderStrikeStopAttack', - actionId: () => ActionId.fromSpellId(407676), - showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotHands, PaladinRune.RuneHandsCrusaderStrike), - changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), - }), - InputHelpers.makeSpecOptionsBooleanIconInput({ - fieldName: 'isUsingHammerOfTheRighteousStopAttack', - actionId: () => ActionId.fromSpellId(407632), - showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotWrist, PaladinRune.RuneWristHammerOfTheRighteous), - changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), - }), - InputHelpers.makeSpecOptionsBooleanIconInput({ - fieldName: 'isUsingShieldOfRighteousnessStopAttack', - actionId: () => ActionId.fromSpellId(440658), - showWhen: (player: Player) => player.hasRune(ItemSlot.ItemSlotBack, PaladinRune.RuneCloakShieldOfRighteousness), - changeEmitter: (player: Player) => TypedEvent.onAny([player.gearChangeEmitter, player.specOptionsChangeEmitter]), - }), - ], - label: 'Stop Attack Macro Abilities', +export const ManualAutoAttacksToggle = InputHelpers.makeSpecOptionsBooleanInput({ + fieldName: 'isManuallyTriggeringAutoAttacks', + label: 'Manually Triggered Autoattacks', + labelTooltip: 'Allows saving of extra attacks', }); // The below is used in the custom APL action "Cast Primary Seal". diff --git a/ui/protection_paladin/sim.ts b/ui/protection_paladin/sim.ts index 103b2d5bae..02b09a105d 100644 --- a/ui/protection_paladin/sim.ts +++ b/ui/protection_paladin/sim.ts @@ -170,7 +170,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { ProtectionPaladinInputs.AuraSelection, ], // Buff and Debuff inputs to include/exclude, overriding the EP-based defaults. - includeBuffDebuffInputs: [BuffDebuffInputs.SpellScorchDebuff, ProtectionPaladinInputs.StopAttackAbilitySelection], + includeBuffDebuffInputs: [BuffDebuffInputs.SpellScorchDebuff], excludeBuffDebuffInputs: [], // Inputs to include in the 'Other' section on the settings tab. otherInputs: { @@ -183,6 +183,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { OtherInputs.HpPercentForDefensives, OtherInputs.InspirationUptime, OtherInputs.InFrontOfTarget, + ProtectionPaladinInputs.ManualAutoAttacksToggle, //OtherInputs.DistanceFromTarget, ], }, diff --git a/ui/retribution_paladin/sim.ts b/ui/retribution_paladin/sim.ts index cda9afce6c..23c712b925 100644 --- a/ui/retribution_paladin/sim.ts +++ b/ui/retribution_paladin/sim.ts @@ -119,7 +119,13 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecRetributionPaladin, { excludeBuffDebuffInputs: [], // Inputs to include in the 'Other' section on the settings tab. otherInputs: { - inputs: [OtherInputs.TankAssignment, OtherInputs.InFrontOfTarget], //, RetributionPaladinInputs.CrusaderStrikeStopAttack, RetributionPaladinInputs.JudgementStopAttack, RetributionPaladinInputs.DivineStormStopAttack], + inputs: [ + OtherInputs.TankAssignment, + OtherInputs.InFrontOfTarget, + RetributionPaladinInputs.CrusaderStrikeStopAttack, + RetributionPaladinInputs.JudgementStopAttack, + RetributionPaladinInputs.DivineStormStopAttack, + ], }, encounterPicker: { // Whether to include 'Execute Duration (%)' in the 'Encounter' section of the settings tab. From 68b634fdec784232ac91bfc7c0d3c4a52857e1f3 Mon Sep 17 00:00:00 2001 From: Wiktor Phillips Date: Mon, 30 Sep 2024 13:01:22 -0400 Subject: [PATCH 4/7] make manually triggered attacks an experimental feature --- ui/protection_paladin/inputs.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/protection_paladin/inputs.ts b/ui/protection_paladin/inputs.ts index 74262c62d4..ad34e60e1e 100644 --- a/ui/protection_paladin/inputs.ts +++ b/ui/protection_paladin/inputs.ts @@ -49,7 +49,11 @@ export const RighteousFuryToggle = InputHelpers.makeSpecOptionsBooleanIconInput< export const ManualAutoAttacksToggle = InputHelpers.makeSpecOptionsBooleanInput({ fieldName: 'isManuallyTriggeringAutoAttacks', label: 'Manually Triggered Autoattacks', - labelTooltip: 'Allows saving of extra attacks', + labelTooltip: `\ + Simulates combat where autoattacks are manually enabled only when the swing timer is ready and turned off again immediately after the melee swing occurs. + Enabling this feature also assumes that all rotational abilities that initiate autoattacks (e.g. Hammer of the Righteous) are cast with a stopattack/@target macro.`, + showWhen: player => player.sim.getShowExperimental(), + changeEmitter: player => TypedEvent.onAny([player.specOptionsChangeEmitter, player.sim.showExperimentalChangeEmitter]), }); // The below is used in the custom APL action "Cast Primary Seal". From 2665a72b0048cd0e9e52d1e92d29737bbe772940 Mon Sep 17 00:00:00 2001 From: Wiktor Phillips Date: Mon, 30 Sep 2024 15:35:42 -0400 Subject: [PATCH 5/7] add a simulator warning if using manual autoattacks --- ui/protection_paladin/sim.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ui/protection_paladin/sim.ts b/ui/protection_paladin/sim.ts index 02b09a105d..af8ce25ee8 100644 --- a/ui/protection_paladin/sim.ts +++ b/ui/protection_paladin/sim.ts @@ -33,6 +33,21 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { }, }; }, + (simUI: IndividualSimUI) => { + return { + updateOn: simUI.player.changeEmitter, + getContent: () => { + if (simUI.player.getSpecOptions().isManuallyTriggeringAutoAttacks == true) { + return `You have enabled Manually Triggered Autoattacks, an experimental feature. + This feature simulates perfect execution of storing extra attacks gained through Rekconing, + as well as Wildstrike/HoJ/etc. This is an advanced technique that will difficult to execute in practice, + and any DPS gains with this feature enabled should be treated as a best-case scenario that may not be realized in a real raid encounter.`; + } else { + return ''; + } + }, + }; + }, ], // All stats for which EP should be calculated. epStats: [ From a7a323df8575303de7f998e1e99f7361a7524a71 Mon Sep 17 00:00:00 2001 From: Wiktor Phillips Date: Mon, 30 Sep 2024 16:07:28 -0400 Subject: [PATCH 6/7] undo autoformat for clarity From e5507fe8a035b4f941e68bfe3d08e592a4d29614 Mon Sep 17 00:00:00 2001 From: Wiktor Phillips Date: Mon, 30 Sep 2024 16:22:46 -0400 Subject: [PATCH 7/7] more typo fixes/cleanup --- sim/paladin/retribution/retribution.go | 6 ------ ui/protection_paladin/sim.ts | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/sim/paladin/retribution/retribution.go b/sim/paladin/retribution/retribution.go index 9a0ab1db37..c74f5e0aec 100644 --- a/sim/paladin/retribution/retribution.go +++ b/sim/paladin/retribution/retribution.go @@ -31,9 +31,6 @@ func NewRetributionPaladin(character *core.Character, options *proto.Player) *Re ret := &RetributionPaladin{ Paladin: pal, primarySeal: retOptions.PrimarySeal, - //IsUsingDivineStormStopAttack: retOptions.IsUsingDivineStormStopAttack, - //IsUsingJudgementStopAttack: retOptions.IsUsingJudgementStopAttack, - //IsUsingCrusaderStrikeStopAttack: retOptions.IsUsingCrusaderStrikeStopAttack, } ret.EnableAutoAttacks(ret, core.AutoAttackOptions{ @@ -48,9 +45,6 @@ type RetributionPaladin struct { *paladin.Paladin primarySeal proto.PaladinSeal - //IsUsingDivineStormStopAttack bool - //IsUsingJudgementStopAttack bool - //IsUsingCrusaderStrikeStopAttack bool } func (ret *RetributionPaladin) GetPaladin() *paladin.Paladin { diff --git a/ui/protection_paladin/sim.ts b/ui/protection_paladin/sim.ts index af8ce25ee8..105ee68151 100644 --- a/ui/protection_paladin/sim.ts +++ b/ui/protection_paladin/sim.ts @@ -40,7 +40,7 @@ const SPEC_CONFIG = registerSpecConfig(Spec.SpecProtectionPaladin, { if (simUI.player.getSpecOptions().isManuallyTriggeringAutoAttacks == true) { return `You have enabled Manually Triggered Autoattacks, an experimental feature. This feature simulates perfect execution of storing extra attacks gained through Rekconing, - as well as Wildstrike/HoJ/etc. This is an advanced technique that will difficult to execute in practice, + as well as Wildstrike/HoJ/etc. This is an advanced technique that will be difficult to execute in practice, and any DPS gains with this feature enabled should be treated as a best-case scenario that may not be realized in a real raid encounter.`; } else { return '';