Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Balance dot settings overhaul #1916

Merged
merged 1 commit into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions proto/druid.proto
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,29 @@ message BalanceDruid {
Manual = 2;
}
Type type = 1;
bool use_battle_res = 2;
bool use_is = 3;
bool use_mf = 4;

enum MfUsage {
NoMf = 0;
BeforeLunar = 1;
MaximizeMf = 2;
}
MfUsage mf_usage = 2;

enum IsUsage {
NoIs = 0;
BeforeSolar = 1;
MaximizeIs = 2;
}
IsUsage is_usage = 3;

bool use_battle_res = 4;
bool use_wrath = 5;
bool use_starfire = 6;
bool use_typhoon = 7;
bool use_hurricane = 8;
int32 mf_inside_eclipse_threshold = 9;
int32 is_inside_eclipse_threshold = 10;
bool use_smart_cooldowns = 11;
bool maximize_mf_uptime = 12;
bool maximize_is_uptime = 13;
bool maintain_faerie_fire = 14;
int32 player_latency = 15;
bool use_smart_cooldowns = 9;
bool maintain_faerie_fire = 10;
int32 player_latency = 11;
}

Rotation rotation = 1;
Expand Down
16 changes: 2 additions & 14 deletions sim/druid/balance/balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,30 +80,18 @@ func (moonkin *BalanceDruid) Reset(sim *core.Simulation) {
moonkin.RebirthTiming = moonkin.Env.BaseDuration.Seconds() * sim.RandomFloat("Rebirth Timing")

if moonkin.Rotation.Type == proto.BalanceDruid_Rotation_Adaptive {
moonkin.Rotation.MfUsage = proto.BalanceDruid_Rotation_NoMf
moonkin.Rotation.IsUsage = proto.BalanceDruid_Rotation_MaximizeIs
moonkin.Rotation.UseBattleRes = false
moonkin.Rotation.UseMf = false
moonkin.Rotation.UseIs = true
moonkin.Rotation.UseStarfire = true
moonkin.Rotation.UseWrath = true
moonkin.Rotation.UseTyphoon = false
moonkin.Rotation.UseHurricane = false
moonkin.Rotation.MfInsideEclipseThreshold = 15
moonkin.Rotation.IsInsideEclipseThreshold = 15
moonkin.Rotation.UseSmartCooldowns = true
moonkin.Rotation.MaximizeMfUptime = false
moonkin.Rotation.MaximizeIsUptime = true
moonkin.Rotation.MaintainFaerieFire = true
moonkin.Rotation.PlayerLatency = 200
}

if !moonkin.Rotation.UseMf {
moonkin.Rotation.MfInsideEclipseThreshold = 15
}

if !moonkin.Rotation.UseIs {
moonkin.Rotation.IsInsideEclipseThreshold = 15
}

if moonkin.Rotation.UseSmartCooldowns {
moonkin.potionUsed = false
consumes := moonkin.Consumes
Expand Down
10 changes: 1 addition & 9 deletions sim/druid/balance/presets.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,7 @@ var PlayerOptionsAdaptive = &proto.Player_BalanceDruid{
InnervateTarget: &proto.RaidTarget{TargetIndex: 0}, // self innervate
},
Rotation: &proto.BalanceDruid_Rotation{
Type: proto.BalanceDruid_Rotation_Adaptive,
UseIs: true,
UseStarfire: true,
UseWrath: true,
UseBattleRes: true,
IsInsideEclipseThreshold: 15.0,
UseSmartCooldowns: true,
MaximizeIsUptime: true,
PlayerLatency: 200,
Type: proto.BalanceDruid_Rotation_Adaptive,
},
},
}
Expand Down
67 changes: 37 additions & 30 deletions sim/druid/balance/rotation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package balance

import (
"github.com/wowsims/wotlk/sim/core/proto"
"time"

"github.com/wowsims/wotlk/sim/core"
Expand Down Expand Up @@ -30,19 +31,8 @@ func (moonkin *BalanceDruid) rotation(sim *core.Simulation) *core.Spell {
}
}

moonfireUptime := moonkin.MoonfireDot.RemainingDuration(sim)
insectSwarmUptime := moonkin.InsectSwarmDot.RemainingDuration(sim)
shouldRebirth := sim.GetRemainingDuration().Seconds() < moonkin.RebirthTiming

// Player "brain" latency
playerLatency := time.Duration(rotation.PlayerLatency)
lunarICD := moonkin.LunarICD.Timer.TimeToReady(sim)
solarICD := moonkin.SolarICD.Timer.TimeToReady(sim)
fishingForLunar := lunarICD <= solarICD
fishingForSolar := solarICD < lunarICD
maximizeIsUptime := rotation.MaximizeIsUptime && rotation.UseIs
maximizeMfUptime := rotation.MaximizeMfUptime && rotation.UseMf

if rotation.UseBattleRes && shouldRebirth && moonkin.Rebirth.IsReady(sim) {
return moonkin.Rebirth
} else if moonkin.Talents.ForceOfNature && moonkin.ForceOfNature.IsReady(sim) {
Expand All @@ -59,6 +49,21 @@ func (moonkin *BalanceDruid) rotation(sim *core.Simulation) *core.Spell {
return moonkin.Hurricane
}

moonfireUptime := moonkin.MoonfireDot.RemainingDuration(sim)
insectSwarmUptime := moonkin.InsectSwarmDot.RemainingDuration(sim)
// Player "brain" latency
playerLatency := time.Duration(rotation.PlayerLatency)
lunarICD := moonkin.LunarICD.Timer.TimeToReady(sim)
solarICD := moonkin.SolarICD.Timer.TimeToReady(sim)
fishingForLunar := lunarICD <= solarICD
//fishingForSolar := solarICD < lunarICD
useMf := moonkin.Rotation.MfUsage != proto.BalanceDruid_Rotation_NoMf
useIs := moonkin.Rotation.IsUsage != proto.BalanceDruid_Rotation_NoIs
maximizeMfUptime := moonkin.Rotation.MfUsage == proto.BalanceDruid_Rotation_MaximizeMf
maximizeIsUptime := moonkin.Rotation.IsUsage == proto.BalanceDruid_Rotation_MaximizeIs
shouldRefreshMf := moonfireUptime <= 0 && useMf
shouldRefreshIs := insectSwarmUptime <= 0 && useIs

if moonkin.Talents.Eclipse > 0 {

lunarUptime := moonkin.LunarEclipseProcAura.ExpiresAt() - sim.CurrentTime
Expand All @@ -67,16 +72,16 @@ func (moonkin *BalanceDruid) rotation(sim *core.Simulation) *core.Spell {
solarIsActive := moonkin.SolarEclipseProcAura.IsActive()

// "Dispelling" eclipse effects before casting if needed
if float64(lunarUptime-moonkin.Starfire.CurCast.CastTime) <= 0 && rotation.UseMf {
if float64(lunarUptime-moonkin.Starfire.CurCast.CastTime) <= 0 && useMf {
lunarIsActive = false
}
if float64(solarUptime-moonkin.Wrath.CurCast.CastTime) <= 0 && rotation.UseIs {
if float64(solarUptime-moonkin.Wrath.CurCast.CastTime) <= 0 && useIs {
solarIsActive = false
}

if lunarIsActive {
lunarIsActive = lunarUptime < (moonkin.LunarEclipseProcAura.Duration - playerLatency)
fishingForSolar = false
//fishingForSolar = false
}
if solarIsActive {
solarIsActive = solarUptime < (moonkin.SolarEclipseProcAura.Duration - playerLatency)
Expand All @@ -85,41 +90,43 @@ func (moonkin *BalanceDruid) rotation(sim *core.Simulation) *core.Spell {

// Eclipse
if solarIsActive || lunarIsActive {
if maximizeIsUptime && insectSwarmUptime <= 0 {
if maximizeIsUptime && shouldRefreshIs {
return moonkin.InsectSwarm
}
if maximizeMfUptime && moonfireUptime <= 0 {
if maximizeMfUptime && shouldRefreshMf {
return moonkin.Moonfire
}
if lunarIsActive {
if (moonfireUptime > 0 || float64(rotation.MfInsideEclipseThreshold) >= lunarUptime.Seconds()) && rotation.UseStarfire {
if (rotation.UseSmartCooldowns && lunarUptime > 14*time.Second) || sim.GetRemainingDuration() < 15*time.Second {
moonkin.castMajorCooldown(moonkin.hyperSpeedMCD, sim, target)
moonkin.castMajorCooldown(moonkin.potionSpeedMCD, sim, target)
}
return moonkin.Starfire
} else if rotation.UseMf {
return moonkin.Moonfire
if (rotation.UseSmartCooldowns && lunarUptime > 14*time.Second) || sim.GetRemainingDuration() < 15*time.Second {
moonkin.castMajorCooldown(moonkin.hyperSpeedMCD, sim, target)
moonkin.castMajorCooldown(moonkin.potionSpeedMCD, sim, target)
}
return moonkin.Starfire
} else if solarIsActive {
if insectSwarmUptime > 0 || float64(rotation.IsInsideEclipseThreshold) >= solarUptime.Seconds() && rotation.UseWrath {
if rotation.UseWrath {
if (rotation.UseSmartCooldowns && solarUptime > 14*time.Second) || sim.GetRemainingDuration() < 15*time.Second {
moonkin.castMajorCooldown(moonkin.potionWildMagicMCD, sim, target)
}
return moonkin.Wrath
} else if rotation.UseIs {
return moonkin.InsectSwarm
}
}
}
if moonkin.Rotation.MfUsage == proto.BalanceDruid_Rotation_BeforeLunar && lunarICD < 2*time.Second && shouldRefreshMf {
return moonkin.Moonfire
}
if moonkin.Rotation.IsUsage == proto.BalanceDruid_Rotation_BeforeSolar && solarICD < 2*time.Second && shouldRefreshIs {
return moonkin.InsectSwarm
}
} else {
fishingForLunar, fishingForSolar = true, true // If Eclipse isn't talented we're not fishing
// If Eclipse isn't talented we're not fishing
fishingForLunar = true
//fishingForSolar = true
}

// Non-Eclipse
if rotation.UseMf && moonfireUptime <= 0 && (fishingForLunar || maximizeMfUptime) {
if maximizeMfUptime && shouldRefreshMf {
return moonkin.Moonfire
} else if rotation.UseIs && insectSwarmUptime <= 0 && (fishingForSolar || maximizeIsUptime) {
} else if maximizeIsUptime && shouldRefreshIs {
return moonkin.InsectSwarm
} else if fishingForLunar && rotation.UseWrath {
return moonkin.Wrath
Expand Down
1 change: 0 additions & 1 deletion sim/druid/druid.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ func (druid *Druid) Initialize() {
druid.HasSetBonus(ItemSetLasherweaveRegalia, 4),
druid.HasSetBonus(ItemSetGladiatorsWildhide, 2),
druid.HasSetBonus(ItemSetGladiatorsWildhide, 4),

druid.HasSetBonus(ItemSetNightsongBattlegear, 2),
druid.HasSetBonus(ItemSetNightsongBattlegear, 4),
}
Expand Down
71 changes: 32 additions & 39 deletions ui/balance_druid/inputs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { BalanceDruid_Options as DruidOptions, BalanceDruid_Rotation_Type as RotationType } from '../core/proto/druid.js';
import { RaidTarget } from '../core/proto/common.js';
import { Spec } from '../core/proto/common.js';
import { NO_TARGET } from '../core/proto_utils/utils.js';
Expand All @@ -8,6 +7,14 @@ import { EventID, TypedEvent } from '../core/typed_event.js';

import * as InputHelpers from '../core/components/input_helpers.js';

import {
BalanceDruid_Options as DruidOptions,
BalanceDruid_Rotation_Type as RotationType,
BalanceDruid_Rotation_MfUsage as MfUsage,
BalanceDruid_Rotation_IsUsage as IsUsage,
} from '../core/proto/druid.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.

Expand Down Expand Up @@ -45,21 +52,31 @@ export const BalanceDruidRotationConfig = {
],
}),
InputHelpers.makeRotationBooleanInput<Spec.SpecBalanceDruid>({
fieldName: 'useBattleRes',
label: 'Use Battle Res',
labelTooltip: 'Cast Battle Res on an ally sometime during the encounter.',
fieldName: 'useSmartCooldowns',
label: 'Smart Cooldowns usage',
labelTooltip: 'The rotation will use cooldowns during eclipses, avoiding Haste CDs in solar and Crit CDs in lunar',
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationBooleanInput<Spec.SpecBalanceDruid>({
fieldName: 'useMf',
label: 'Use Moonfire',
labelTooltip: 'Should the rotation use Moonfire.',
InputHelpers.makeRotationEnumInput<Spec.SpecBalanceDruid, MfUsage>({
fieldName: 'mfUsage',
label: 'Moonfire Usage',
labelTooltip: 'Defines how Moonfire will be used in the rotation.',
values: [
{ name: 'Unused', value: MfUsage.NoMf },
{ name: 'Before lunar', value: MfUsage.BeforeLunar },
{ name: 'Maximize', value: MfUsage.MaximizeMf },
],
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationBooleanInput<Spec.SpecBalanceDruid>({
fieldName: 'useIs',
label: 'Use Insect Swarm',
labelTooltip: 'Should the rotation use Insect Swarm.',
InputHelpers.makeRotationEnumInput<Spec.SpecBalanceDruid, IsUsage>({
fieldName: 'isUsage',
label: 'Insect Swarm Usage',
labelTooltip: 'Defines how Insect Swarm will be used in the rotation.',
values: [
{ name: 'Unused', value: IsUsage.NoIs },
{ name: 'Before solar', value: IsUsage.BeforeSolar },
{ name: 'Maximize', value: IsUsage.MaximizeIs },
],
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationBooleanInput<Spec.SpecBalanceDruid>({
Expand All @@ -86,34 +103,10 @@ export const BalanceDruidRotationConfig = {
labelTooltip: 'Should the rotation use Hurricane.',
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationNumberInput<Spec.SpecBalanceDruid>({
fieldName: 'mfInsideEclipseThreshold',
label: 'Moonfire inside eclipse max timing',
labelTooltip: 'Max eclipse uptime at which Moonfire can be applied/refreshed. 15 = never refresh, 0= always refresh.',
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationNumberInput<Spec.SpecBalanceDruid>({
fieldName: 'isInsideEclipseThreshold',
label: 'Insect Swarm inside eclipse max timing',
labelTooltip: 'Max eclipse uptime at which Insect Swarm can be applied/refreshed. 15 = never refresh, 0= always refresh.',
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationBooleanInput<Spec.SpecBalanceDruid>({
fieldName: 'useSmartCooldowns',
label: 'Smart Cooldowns usage',
labelTooltip: 'The rotation will use cooldowns during eclipses, avoiding Haste CDs in solar and Crit CDs in lunar',
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationBooleanInput<Spec.SpecBalanceDruid>({
fieldName: 'maximizeMfUptime',
label: 'Maximize Moonfire uptime',
labelTooltip: 'Rotation will try to keep Moonfire up without clipping',
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationBooleanInput<Spec.SpecBalanceDruid>({
fieldName: 'maximizeIsUptime',
label: 'Maximize Insect Swarm uptime',
labelTooltip: 'Rotation will try to keep Insect Swarm up without clipping',
fieldName: 'useBattleRes',
label: 'Use Battle Res',
labelTooltip: 'Cast Battle Res on an ally sometime during the encounter.',
showWhen: (player: Player<Spec.SpecBalanceDruid>) => player.getRotation().type == RotationType.Manual,
}),
InputHelpers.makeRotationNumberInput<Spec.SpecBalanceDruid>({
Expand Down
34 changes: 19 additions & 15 deletions ui/balance_druid/presets.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import {
Consumes,
Debuffs, Glyphs,
Debuffs,
EquipmentSpec,
Flask,
Food,
Glyphs,
IndividualBuffs,
PartyBuffs,
Potions,
RaidBuffs,
RaidTarget,
TristateEffect
} from '../core/proto/common.js';
import { Flask } from '../core/proto/common.js';
import { Food } from '../core/proto/common.js';
import { EquipmentSpec } from '../core/proto/common.js';
import { Potions } from '../core/proto/common.js';
import { SavedTalents } from '../core/proto/ui.js';
import {SavedTalents} from '../core/proto/ui.js';

import {
BalanceDruid_Rotation as BalanceDruidRotation,
BalanceDruid_Options as BalanceDruidOptions,
BalanceDruid_Rotation_Type as RotationType, DruidMajorGlyph, DruidMinorGlyph,
BalanceDruid_Rotation as BalanceDruidRotation,
BalanceDruid_Rotation_IsUsage,
BalanceDruid_Rotation_MfUsage,
BalanceDruid_Rotation_Type as RotationType,
DruidMajorGlyph,
DruidMinorGlyph,
} from '../core/proto/druid.js';

import * as Tooltips from '../core/constants/tooltips.js';
import { NO_TARGET } from "../core/proto_utils/utils";
import {NO_TARGET} from "../core/proto_utils/utils";

// Preset options for this spec.
// Eventually we will import these values for the raid sim too, so its good to
Expand All @@ -45,13 +50,12 @@ export const StandardTalents = {

export const DefaultRotation = BalanceDruidRotation.create({
type: RotationType.Adaptive,
useSmartCooldowns : true,
mfUsage : BalanceDruid_Rotation_MfUsage.NoMf,
isUsage : BalanceDruid_Rotation_IsUsage.MaximizeIs,
useStarfire: true,
useWrath: true,
useBattleRes: false,
useIs: true,
useMf: false,
isInsideEclipseThreshold: 15,
mfInsideEclipseThreshold: 0,
useSmartCooldowns : true,
maximizeIsUptime : true,
playerLatency : 200,
});

Expand Down