diff --git a/proto/shaman.proto b/proto/shaman.proto index a1cab5b385..43dd006743 100644 --- a/proto/shaman.proto +++ b/proto/shaman.proto @@ -233,7 +233,7 @@ message ElementalShaman { Manual = 2; } RotationType type = 1; - bool in_thunderstorm_range = 2; + bool in_thunderstorm_range = 2 [deprecated = true]; // These options are used for the manual rotation. bool use_fire_nova = 4; @@ -245,12 +245,26 @@ message ElementalShaman { bool always_crit_lvb = 7; bool use_thunderstorm = 8; double lvb_fs_wait_ms = 12; + + enum BloodlustUse { + UnsetBloodlust = 0; + UseBloodlust = 1; + NoBloodlust = 2; + } + BloodlustUse bloodlust = 13; } message Options { ShamanShield shield = 1; - bool bloodlust = 2; + bool bloodlust = 2 [deprecated = true]; ShamanTotems totems = 3; + + enum ThunderstormRange { + UnsetTSRange = 0; + TSInRange = 1; + TSOutofRange = 2; + } + ThunderstormRange thunderstormRange = 4; } Rotation rotation = 1; @@ -311,11 +325,18 @@ message EnhancementShaman { double delay_gcd_weave = 13; ItemSwap item_swap = 14; bool enable_item_swap = 15; + + enum BloodlustUse { + UnsetBloodlust = 0; + UseBloodlust = 1; + NoBloodlust = 2; + } + BloodlustUse bloodlust = 16; } message Options { ShamanShield shield = 1; - bool bloodlust = 2; + bool bloodlust = 2 [deprecated = true]; ShamanSyncType sync_type = 3; ShamanImbue imbue_mh = 4; ShamanImbue imbue_oh = 5; @@ -340,11 +361,18 @@ message RestorationShaman { bool use_earth_shield = 2; ShamanHealSpell primary_heal = 3; bool use_riptide = 4; + + enum BloodlustUse { + UnsetBloodlust = 0; + UseBloodlust = 1; + NoBloodlust = 2; + } + BloodlustUse bloodlust = 5; } message Options { ShamanShield shield = 1; - bool bloodlust = 2; + bool bloodlust = 2 [deprecated = true]; ShamanImbue imbue_mh = 4; int32 earth_shield_p_p_m = 5; ShamanTotems totems = 6; diff --git a/sim/shaman/elemental/elemental.go b/sim/shaman/elemental/elemental.go index 1c2c9467a8..3e734f02d6 100644 --- a/sim/shaman/elemental/elemental.go +++ b/sim/shaman/elemental/elemental.go @@ -32,6 +32,10 @@ func NewElementalShaman(character *core.Character, options *proto.Player) *Eleme Shield: eleShamOptions.Options.Shield, } + if eleShamOptions.Rotation.Bloodlust != proto.ElementalShaman_Rotation_UnsetBloodlust { + selfBuffs.Bloodlust = eleShamOptions.Rotation.Bloodlust == proto.ElementalShaman_Rotation_UseBloodlust + } + totems := &proto.ShamanTotems{} if eleShamOptions.Options.Totems != nil { totems = eleShamOptions.Options.Totems @@ -49,8 +53,12 @@ func NewElementalShaman(character *core.Character, options *proto.Player) *Eleme rotation = NewAdaptiveRotation(eleShamOptions.Rotation) } + inRange := eleShamOptions.Rotation.InThunderstormRange + if eleShamOptions.Options.ThunderstormRange != proto.ElementalShaman_Options_UnsetTSRange { + inRange = eleShamOptions.Options.ThunderstormRange == proto.ElementalShaman_Options_TSInRange + } ele := &ElementalShaman{ - Shaman: shaman.NewShaman(character, options.TalentsString, totems, selfBuffs, eleShamOptions.Rotation.InThunderstormRange), + Shaman: shaman.NewShaman(character, options.TalentsString, totems, selfBuffs, inRange), rotation: rotation, has4pT6: character.HasSetBonus(shaman.ItemSetSkyshatterRegalia, 4), } diff --git a/sim/shaman/enhancement/enhancement.go b/sim/shaman/enhancement/enhancement.go index 352ed1846e..6d443c6301 100644 --- a/sim/shaman/enhancement/enhancement.go +++ b/sim/shaman/enhancement/enhancement.go @@ -36,6 +36,11 @@ func NewEnhancementShaman(character *core.Character, options *proto.Player) *Enh ImbueOH: enhOptions.Options.ImbueOh, } + // Override with new rotation option bloodlust. + if enhOptions.Rotation.Bloodlust != proto.EnhancementShaman_Rotation_UnsetBloodlust { + selfBuffs.Bloodlust = enhOptions.Rotation.Bloodlust == proto.EnhancementShaman_Rotation_UseBloodlust + } + totems := &proto.ShamanTotems{} if enhOptions.Options.Totems != nil { totems = enhOptions.Options.Totems diff --git a/sim/shaman/restoration/restoration.go b/sim/shaman/restoration/restoration.go index 4918aeb645..880f4c0d29 100644 --- a/sim/shaman/restoration/restoration.go +++ b/sim/shaman/restoration/restoration.go @@ -33,6 +33,10 @@ func NewRestorationShaman(character *core.Character, options *proto.Player) *Res Shield: restoShamOptions.Options.Shield, } + if restoShamOptions.Rotation.Bloodlust != proto.RestorationShaman_Rotation_UnsetBloodlust { + selfBuffs.Bloodlust = restoShamOptions.Rotation.Bloodlust == proto.RestorationShaman_Rotation_UseBloodlust + } + totems := &proto.ShamanTotems{} if restoShamOptions.Options.Totems != nil { totems = restoShamOptions.Options.Totems diff --git a/ui/core/player.ts b/ui/core/player.ts index e2fd163f7e..827f93b058 100644 --- a/ui/core/player.ts +++ b/ui/core/player.ts @@ -89,6 +89,7 @@ import { Party, MAX_PARTY_SIZE } from './party.js'; import { Raid } from './raid.js'; import { Sim } from './sim.js'; import { stringComparator, sum } from './utils.js'; +import { ElementalShaman_Options, ElementalShaman_Options_ThunderstormRange, ElementalShaman_Rotation, ElementalShaman_Rotation_BloodlustUse, EnhancementShaman_Rotation, EnhancementShaman_Rotation_BloodlustUse, RestorationShaman_Rotation, RestorationShaman_Rotation_BloodlustUse } from './proto/shaman.js'; export interface AuraStats { data: AuraStatsProto, @@ -1364,6 +1365,36 @@ export class Player { rot.totems = undefined; this.setRotation(eventID, rot as SpecRotation); } + const opt = this.getSpecOptions() as SpecOptions; + + // Update Bloodlust to be part of rotation instead of options to support APL casting bloodlust. + if (opt.bloodlust) { + opt.bloodlust = false; + + var tRot = this.getRotation(); + if (this.spec == Spec.SpecElementalShaman) { + (tRot as ElementalShaman_Rotation).bloodlust = ElementalShaman_Rotation_BloodlustUse.UseBloodlust; + } else if (this.spec == Spec.SpecEnhancementShaman) { + (tRot as EnhancementShaman_Rotation).bloodlust = EnhancementShaman_Rotation_BloodlustUse.UseBloodlust; + } else if (this.spec == Spec.SpecRestorationShaman) { + (tRot as RestorationShaman_Rotation).bloodlust = RestorationShaman_Rotation_BloodlustUse.UseBloodlust; + } + + this.setRotation(eventID, tRot as SpecRotation); + this.setSpecOptions(eventID, opt as SpecOptions); + } + + // Update Ele TS range option. + if (this.spec == Spec.SpecElementalShaman) { + var eleOpt = this.getSpecOptions() as ElementalShaman_Options; + var eleRot = this.getRotation() as ElementalShaman_Rotation; + if (eleRot.inThunderstormRange) { + eleOpt.thunderstormRange = ElementalShaman_Options_ThunderstormRange.TSInRange; + eleRot.inThunderstormRange = false; + this.setRotation(eventID, eleRot as SpecRotation); + this.setSpecOptions(eventID, eleOpt as SpecOptions); + } + } } }); } diff --git a/ui/elemental_shaman/index.ts b/ui/elemental_shaman/index.ts index 4af2959e9a..86535f75c2 100644 --- a/ui/elemental_shaman/index.ts +++ b/ui/elemental_shaman/index.ts @@ -8,5 +8,4 @@ import { ElementalShamanSimUI } from './sim.js'; const sim = new Sim(); const player = new Player(Spec.SpecElementalShaman, sim); sim.raid.setPlayer(TypedEvent.nextEventID(), 0, player); - const simUI = new ElementalShamanSimUI(document.body, player); diff --git a/ui/elemental_shaman/inputs.ts b/ui/elemental_shaman/inputs.ts index 492c740ccf..d3963843fd 100644 --- a/ui/elemental_shaman/inputs.ts +++ b/ui/elemental_shaman/inputs.ts @@ -1,5 +1,5 @@ import { IconPickerConfig } from '../core/components/icon_picker.js'; -import { ElementalShaman_Rotation_RotationType as RotationType, ShamanShield } from '../core/proto/shaman.js'; +import { ElementalShaman_Options_ThunderstormRange, ElementalShaman_Rotation_BloodlustUse, ElementalShaman_Rotation_RotationType as RotationType, ShamanShield, ShamanTotems } from '../core/proto/shaman.js'; import { ElementalShaman_Options as ShamanOptions } from '../core/proto/shaman.js'; import { AirTotem } from '../core/proto/shaman.js'; import { Spec } from '../core/proto/common.js'; @@ -7,14 +7,28 @@ import { ActionId } from '../core/proto_utils/action_id.js'; import { Player } from '../core/player.js'; import * as InputHelpers from '../core/components/input_helpers.js'; +import { EventID, TypedEvent } from 'ui/core/typed_event.js'; // Configuration for spec-specific UI elements on the settings tab. // These don't need to be in a separate file but it keeps things cleaner. -export const Bloodlust = InputHelpers.makeSpecOptionsBooleanIconInput({ - fieldName: 'bloodlust', - id: ActionId.fromSpellId(2825), +export const InThunderstormRange = InputHelpers.makeSpecOptionsBooleanInput({ + fieldName: 'thunderstormRange', + // id: ActionId.fromSpellId(59159), + label: "Thunderstorm In Range", + labelTooltip: "When set to true, thunderstorm casts will cause damage.", + getValue: (player: Player) => player.getSpecOptions().thunderstormRange == ElementalShaman_Options_ThunderstormRange.TSInRange, + setValue: (eventID: EventID, player: Player, newValue: boolean) => { + const newOptions = player.getSpecOptions(); + if (newValue) { + newOptions.thunderstormRange = ElementalShaman_Options_ThunderstormRange.TSInRange; + } else { + newOptions.thunderstormRange = ElementalShaman_Options_ThunderstormRange.TSOutofRange; + } + player.setSpecOptions(eventID, newOptions); + }, }); + export const ShamanShieldInput = InputHelpers.makeSpecOptionsEnumIconInput({ fieldName: 'shield', values: [ @@ -41,10 +55,19 @@ export const ElementalShamanRotationConfig = { ], }), InputHelpers.makeRotationBooleanInput({ - fieldName: 'inThunderstormRange', - label: 'In Thunderstorm Range', - labelTooltip: 'Thunderstorm will hit all targets when cast. Ignores knockback.', - showWhen: (player: Player) => player.getTalents().thunderstorm, + fieldName: 'bloodlust', + label: 'Use Bloodlust', + labelTooltip: 'Player will cast bloodlust', + getValue: (player: Player) => player.getRotation().bloodlust == ElementalShaman_Rotation_BloodlustUse.UseBloodlust, + setValue: (eventID: EventID, player: Player, newValue: boolean) => { + const newRotation = player.getRotation(); + if (newValue) { + newRotation.bloodlust = ElementalShaman_Rotation_BloodlustUse.UseBloodlust; + } else { + newRotation.bloodlust = ElementalShaman_Rotation_BloodlustUse.NoBloodlust; + } + player.setRotation(eventID, newRotation); + }, }), InputHelpers.makeRotationNumberInput({ fieldName: 'lvbFsWaitMs', diff --git a/ui/elemental_shaman/sim.ts b/ui/elemental_shaman/sim.ts index 70b2dc23e4..bb93ec8154 100644 --- a/ui/elemental_shaman/sim.ts +++ b/ui/elemental_shaman/sim.ts @@ -15,13 +15,12 @@ import { Stats } from '../core/proto_utils/stats.js'; import { IndividualSimUI } from '../core/individual_sim_ui.js'; import { EventID, TypedEvent } from '../core/typed_event.js'; import { TotemsSection } from '../core/components/totem_inputs.js'; - import * as IconInputs from '../core/components/icon_inputs.js'; import * as OtherInputs from '../core/components/other_inputs.js'; import * as Mechanics from '../core/constants/mechanics.js'; - import * as ShamanInputs from './inputs.js'; import * as Presets from './presets.js'; +import { ElementalShaman_Options_ThunderstormRange, ElementalShaman_Rotation_BloodlustUse} from '../core/proto/shaman.js'; export class ElementalShamanSimUI extends IndividualSimUI { constructor(parentElem: HTMLElement, player: Player) { @@ -129,7 +128,6 @@ export class ElementalShamanSimUI extends IndividualSimUI({ - fieldName: 'bloodlust', - id: ActionId.fromSpellId(2825), -}); export const ShamanShieldInput = InputHelpers.makeSpecOptionsEnumIconInput({ fieldName: 'shield', values: [ @@ -279,6 +278,21 @@ export const EnhancementShamanRotationConfig = { label: 'Mana % to use Shamanistic Rage', enableWhen: (player: Player) => player.getTalents().shamanisticRage, }), + InputHelpers.makeRotationBooleanInput({ + fieldName: 'bloodlust', + label: 'Use Bloodlust', + labelTooltip: 'Player will cast bloodlust', + getValue: (player: Player) => player.getRotation().bloodlust == EnhancementShaman_Rotation_BloodlustUse.UseBloodlust, + setValue: (eventID: EventID, player: Player, newValue: boolean) => { + const newRotation = player.getRotation(); + if (newValue) { + newRotation.bloodlust = EnhancementShaman_Rotation_BloodlustUse.UseBloodlust; + } else { + newRotation.bloodlust = EnhancementShaman_Rotation_BloodlustUse.NoBloodlust; + } + player.setRotation(eventID, newRotation); + }, + }), ], }; diff --git a/ui/enhancement_shaman/sim.ts b/ui/enhancement_shaman/sim.ts index 6cec38a22d..01630bb42f 100644 --- a/ui/enhancement_shaman/sim.ts +++ b/ui/enhancement_shaman/sim.ts @@ -116,7 +116,6 @@ export class EnhancementShamanSimUI extends IndividualSimUI({ - fieldName: 'bloodlust', - id: ActionId.fromSpellId(2825), -}); export const ShamanShieldInput = InputHelpers.makeSpecOptionsEnumIconInput({ fieldName: 'shield', values: [ @@ -84,6 +81,21 @@ export const RestorationShamanRotationConfig = { UseRiptide, UseEarthShield, TriggerEarthShield, + InputHelpers.makeRotationBooleanInput({ + fieldName: 'bloodlust', + label: 'Use Bloodlust', + labelTooltip: 'Player will cast bloodlust', + getValue: (player: Player) => player.getRotation().bloodlust == RestorationShaman_Rotation_BloodlustUse.UseBloodlust, + setValue: (eventID: EventID, player: Player, newValue: boolean) => { + const newRotation = player.getRotation(); + if (newValue) { + newRotation.bloodlust = RestorationShaman_Rotation_BloodlustUse.UseBloodlust; + } else { + newRotation.bloodlust = RestorationShaman_Rotation_BloodlustUse.NoBloodlust; + } + player.setRotation(eventID, newRotation); + }, + }), ], }; diff --git a/ui/restoration_shaman/sim.ts b/ui/restoration_shaman/sim.ts index 90fe198a75..74fabba7d4 100644 --- a/ui/restoration_shaman/sim.ts +++ b/ui/restoration_shaman/sim.ts @@ -109,7 +109,6 @@ export class RestorationShamanSimUI extends IndividualSimUI