Skip to content

Commit

Permalink
Merge pull request #1916 from wowsims/balance-dot-settings
Browse files Browse the repository at this point in the history
Balance dot settings overhaul
  • Loading branch information
Gashiraa authored Nov 24, 2022
2 parents 2e2f2be + 644e100 commit 0f5048c
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 118 deletions.
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

0 comments on commit 0f5048c

Please sign in to comment.