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

Implement autocast CD action for APL, hunter APL rotation DPS now mat… #3256

Merged
merged 1 commit into from
Jul 6, 2023
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
4 changes: 4 additions & 0 deletions proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ message APLAction {
APLActionStrictSequence strict_sequence = 6;

APLActionCastSpell cast_spell = 3;
APLActionAutocastOtherCooldowns autocast_other_cooldowns = 7;
APLActionWait wait = 4;
}
}
Expand Down Expand Up @@ -87,6 +88,9 @@ message APLActionCastSpell {
ActionID spell_id = 1;
}

message APLActionAutocastOtherCooldowns {
}

message APLActionWait {
APLValue duration = 1;
}
Expand Down
11 changes: 10 additions & 1 deletion sim/core/apl.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ func (unit *Unit) newAPLRotation(config *proto.APLRotation) *APLRotation {

for _, action := range rotation.allAPLActions() {
action.impl.Finalize()

// Remove MCDs that are referenced by APL actions.
character := unit.Env.Raid.GetPlayerFromUnit(unit).GetCharacter()
if castSpellAction, ok := action.impl.(*APLActionCastSpell); ok {
character.removeInitialMajorCooldown(castSpellAction.spell.ActionID)
}
}

return rotation
Expand All @@ -63,8 +69,11 @@ func (rot *APLRotation) reset(sim *Simulation) {
func (apl *APLRotation) DoNextAction(sim *Simulation) {
if apl.strictSequence == nil {
for _, action := range apl.priorityList {
if action.IsAvailable(sim) {
if action.IsReady(sim) {
action.Execute(sim)
if apl.unit.GCD.IsReady(sim) {
apl.unit.WaitUntil(sim, sim.CurrentTime)
}
return
}
}
Expand Down
8 changes: 5 additions & 3 deletions sim/core/apl_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ type APLAction struct {
impl APLActionImpl
}

func (action *APLAction) IsAvailable(sim *Simulation) bool {
return (action.condition == nil || action.condition.GetBool(sim)) && action.impl.IsAvailable(sim)
func (action *APLAction) IsReady(sim *Simulation) bool {
return (action.condition == nil || action.condition.GetBool(sim)) && action.impl.IsReady(sim)
}

func (action *APLAction) Execute(sim *Simulation) {
Expand All @@ -35,7 +35,7 @@ type APLActionImpl interface {
Reset(*Simulation)

// Whether this action is available to be used right now.
IsAvailable(*Simulation) bool
IsReady(*Simulation) bool

// Performs the action.
Execute(*Simulation)
Expand Down Expand Up @@ -66,6 +66,8 @@ func (unit *Unit) newAPLActionImpl(config *proto.APLAction) APLActionImpl {
return unit.newActionStrictSequence(config.GetStrictSequence())
case *proto.APLAction_CastSpell:
return unit.newActionCastSpell(config.GetCastSpell())
case *proto.APLAction_AutocastOtherCooldowns:
return unit.newActionAutocastOtherCooldowns(config.GetAutocastOtherCooldowns())
case *proto.APLAction_Wait:
return unit.newActionWait(config.GetWait())
default:
Expand Down
29 changes: 27 additions & 2 deletions sim/core/apl_actions_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,38 @@ func (unit *Unit) newActionCastSpell(config *proto.APLActionCastSpell) APLAction
func (action *APLActionCastSpell) GetInnerActions() []*APLAction { return nil }
func (action *APLActionCastSpell) Finalize() {}
func (action *APLActionCastSpell) Reset(*Simulation) {}
func (action *APLActionCastSpell) IsAvailable(sim *Simulation) bool {
func (action *APLActionCastSpell) IsReady(sim *Simulation) bool {
return action.spell.CanCast(sim, action.spell.Unit.CurrentTarget)
}
func (action *APLActionCastSpell) Execute(sim *Simulation) {
action.spell.Cast(sim, action.spell.Unit.CurrentTarget)
}

type APLActionAutocastOtherCooldowns struct {
character *Character

nextReadyMCD *MajorCooldown
}

func (unit *Unit) newActionAutocastOtherCooldowns(config *proto.APLActionAutocastOtherCooldowns) APLActionImpl {
return &APLActionAutocastOtherCooldowns{
character: unit.Env.Raid.GetPlayerFromUnit(unit).GetCharacter(),
}
}
func (action *APLActionAutocastOtherCooldowns) GetInnerActions() []*APLAction { return nil }
func (action *APLActionAutocastOtherCooldowns) Finalize() {}
func (action *APLActionAutocastOtherCooldowns) Reset(*Simulation) {
action.nextReadyMCD = nil
}
func (action *APLActionAutocastOtherCooldowns) IsReady(sim *Simulation) bool {
action.nextReadyMCD = action.character.getFirstReadyMCD(sim)
return action.nextReadyMCD != nil
}
func (action *APLActionAutocastOtherCooldowns) Execute(sim *Simulation) {
action.nextReadyMCD.tryActivateHelper(sim, action.character)
action.character.UpdateMajorCooldowns()
}

type APLActionWait struct {
unit *Unit
duration APLValue
Expand All @@ -42,7 +67,7 @@ func (unit *Unit) newActionWait(config *proto.APLActionWait) APLActionImpl {
func (action *APLActionWait) GetInnerActions() []*APLAction { return nil }
func (action *APLActionWait) Finalize() {}
func (action *APLActionWait) Reset(*Simulation) {}
func (action *APLActionWait) IsAvailable(sim *Simulation) bool {
func (action *APLActionWait) IsReady(sim *Simulation) bool {
return action.duration != nil
}
func (action *APLActionWait) Execute(sim *Simulation) {
Expand Down
12 changes: 6 additions & 6 deletions sim/core/apl_actions_sequences.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ func (action *APLActionSequence) Finalize() {}
func (action *APLActionSequence) Reset(*Simulation) {
action.curIdx = 0
}
func (action *APLActionSequence) IsAvailable(sim *Simulation) bool {
return action.curIdx < len(action.actions) && action.actions[action.curIdx].IsAvailable(sim)
func (action *APLActionSequence) IsReady(sim *Simulation) bool {
return action.curIdx < len(action.actions) && action.actions[action.curIdx].IsReady(sim)
}
func (action *APLActionSequence) Execute(sim *Simulation) {
action.actions[action.curIdx].Execute(sim)
Expand Down Expand Up @@ -65,7 +65,7 @@ func (action *APLActionResetSequence) Finalize() {
validationWarning("No sequence with name: %s", action.name)
}
func (action *APLActionResetSequence) Reset(*Simulation) {}
func (action *APLActionResetSequence) IsAvailable(sim *Simulation) bool {
func (action *APLActionResetSequence) IsReady(sim *Simulation) bool {
return true
}
func (action *APLActionResetSequence) Execute(sim *Simulation) {
Expand Down Expand Up @@ -96,17 +96,17 @@ func (action *APLActionStrictSequence) Finalize() {}
func (action *APLActionStrictSequence) Reset(*Simulation) {
action.curIdx = 0
}
func (action *APLActionStrictSequence) IsAvailable(sim *Simulation) bool {
func (action *APLActionStrictSequence) IsReady(sim *Simulation) bool {
for _, subaction := range action.actions {
if !subaction.IsAvailable(sim) {
if !subaction.IsReady(sim) {
return false
}
}
return true
}
func (action *APLActionStrictSequence) Execute(sim *Simulation) {
action.unit.Rotation.strictSequence = action
if !action.actions[action.curIdx].IsAvailable(sim) {
if !action.actions[action.curIdx].IsReady(sim) {
action.curIdx = 0
action.unit.Rotation.strictSequence = nil
return
Expand Down
42 changes: 36 additions & 6 deletions sim/core/major_cooldown.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ func (mcd *MajorCooldown) tryActivateInternal(sim *Simulation, character *Charac
return mcd.tryActivateHelper(sim, character)
}

// Activates this MCD, if all the conditions pass.
// Returns whether the MCD was activated.
func (mcd *MajorCooldown) tryActivateHelper(sim *Simulation, character *Character) bool {
func (mcd *MajorCooldown) shouldActivateHelper(sim *Simulation, character *Character) bool {
if mcd.Type.Matches(CooldownTypeSurvival) && character.cooldownConfigs.HpPercentForDefensives != 0 {
if character.CurrentHealthPercent() > character.cooldownConfigs.HpPercentForDefensives {
return false
Expand All @@ -136,12 +134,17 @@ func (mcd *MajorCooldown) tryActivateHelper(sim *Simulation, character *Characte
return false
}

var shouldActivate bool
if mcd.numUsages < len(mcd.timings) {
shouldActivate = sim.CurrentTime >= mcd.timings[mcd.numUsages]
return sim.CurrentTime >= mcd.timings[mcd.numUsages]
} else {
shouldActivate = mcd.ShouldActivate(sim, character)
return mcd.ShouldActivate(sim, character)
}
}

// Activates this MCD, if all the conditions pass.
// Returns whether the MCD was activated.
func (mcd *MajorCooldown) tryActivateHelper(sim *Simulation, character *Character) bool {
shouldActivate := mcd.shouldActivateHelper(sim, character)

if shouldActivate {
if mcd.Spell.Flags.Matches(SpellFlagHelpful) {
Expand Down Expand Up @@ -397,6 +400,16 @@ func (mcdm *majorCooldownManager) GetInitialMajorCooldown(actionID ActionID) Maj
return MajorCooldown{}
}

func (mcdm *majorCooldownManager) removeInitialMajorCooldown(actionID ActionID) {
for i, mcd := range mcdm.initialMajorCooldowns {
if mcd.Spell.SameAction(actionID) {
mcdm.initialMajorCooldowns = append(mcdm.initialMajorCooldowns[:i], mcdm.initialMajorCooldowns[i+1:]...)
mcdm.majorCooldowns = mcdm.majorCooldowns[:len(mcdm.majorCooldowns)-1]
return
}
}
}

func (mcdm *majorCooldownManager) GetMajorCooldown(actionID ActionID) *MajorCooldown {
for _, mcd := range mcdm.majorCooldowns {
if mcd.Spell.SameAction(actionID) {
Expand Down Expand Up @@ -427,6 +440,23 @@ func (mcdm *majorCooldownManager) GetMajorCooldownIDs() []*proto.ActionID {
return ids
}

func (mcdm *majorCooldownManager) getFirstReadyMCD(sim *Simulation) *MajorCooldown {
if sim.CurrentTime < mcdm.minReady {
return nil
}

for _, mcd := range mcdm.majorCooldowns {
if !mcd.IsReady(sim) {
return nil
}
if mcd.shouldActivateHelper(sim, mcdm.character) {
return mcd
}
}

return nil
}

func (mcdm *majorCooldownManager) TryUseCooldowns(sim *Simulation) {
if sim.CurrentTime < mcdm.minReady {
return
Expand Down
3 changes: 2 additions & 1 deletion sim/hunter/rotation.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package hunter

import (
"time"

"github.com/wowsims/wotlk/sim/common"
"github.com/wowsims/wotlk/sim/core"
"github.com/wowsims/wotlk/sim/core/proto"
"time"
)

func (hunter *Hunter) OnAutoAttack(sim *core.Simulation, spell *core.Spell) {
Expand Down
15 changes: 15 additions & 0 deletions ui/core/components/individual_sim_ui/apl_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
APLActionSequence,
APLActionResetSequence,
APLActionStrictSequence,
APLActionAutocastOtherCooldowns,
APLActionWait,
APLValue,
} from '../../proto/apl.js';
Expand Down Expand Up @@ -260,8 +261,22 @@ export const actionTypeFactories: Record<NonNullable<APLActionType>, ActionTypeC
actionListFieldConfig('actions'),
],
}),
['autocastOtherCooldowns']: inputBuilder({
label: 'Autocast Other Cooldowns',
submenu: ['Misc'],
shortDescription: 'Auto-casts cooldowns as soon as they are ready.',
fullDescription: `
<ul>
<li>Does not auto-cast cooldowns which are already controlled by other actions in the priority list.</li>
<li>Cooldowns are usually cast immediately upon becoming ready, but there are some basic smart checks in place, e.g. don't use Mana CDs when near full mana.</li>
</ul>
`,
newValue: APLActionAutocastOtherCooldowns.create,
fields: [],
}),
['wait']: inputBuilder({
label: 'Wait',
submenu: ['Misc'],
shortDescription: 'Pauses the GCD for a specified amount of time.',
newValue: APLActionWait.create,
fields: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class APLRotationPicker extends Component {
inlineMenuBar: true,
});

modPlayer.rotationChangeEmitter.on(() => console.log('APL: ' + APLRotation.toJsonString(modPlayer.aplRotation)))
//modPlayer.rotationChangeEmitter.on(() => console.log('APL: ' + APLRotation.toJsonString(modPlayer.aplRotation)))
}
}

Expand Down
1 change: 0 additions & 1 deletion ui/core/components/individual_sim_ui/rotation_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export class RotationTab extends SimTab {

constructor(parentElem: HTMLElement, simUI: IndividualSimUI<Spec>) {
super(parentElem, simUI, {identifier: 'rotation-tab', title: 'Rotation'});
this.rootElem.classList.add('experimental');
this.simUI = simUI;

this.leftPanel = document.createElement('div');
Expand Down
6 changes: 5 additions & 1 deletion ui/hunter/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,17 @@ export const ROTATION_PRESET_DEFAULT = {
rotation: APLRotation.fromJsonString(`{
"enabled": true,
"priorityList": [
{"action": {"autocastOtherCooldowns": {}}},
{"action": {
"condition": {"not": {"val": {"dotIsActive": {"spellId": { "spellId": 49001 }}}}},
"castSpell": {"spellId": { "spellId": 49001 }}
}},
{"action": {"castSpell": {"spellId": { "spellId": 61006 }}}},
{"action": {"castSpell": {"spellId": { "spellId": 63672 }}}},
{"action": {"castSpell": {"spellId": { "spellId": 60053 }}}},
{"action": {
"condition": {"not": {"val": {"dotIsActive": {"spellId": { "spellId": 60053 }}}}},
"castSpell": {"spellId": { "spellId": 60053 }}
}},
{"action": {"castSpell": {"spellId": { "spellId": 49050 }}}},
{"action": {
"condition": {"not": {"val": {"dotIsActive": {"spellId": { "spellId": 60053 }}}}},
Expand Down