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 off GCD apl actions #1118

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
18 changes: 17 additions & 1 deletion proto/apl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ message APLListItem {
APLAction action = 3; // The action to be performed.
}

// NextIndex: 24
// NextIndex: 26
message APLAction {
APLValue condition = 1; // If set, action will only execute if value is true or != 0.

Expand All @@ -56,7 +56,9 @@ message APLAction {
// Timing
APLActionWait wait = 4;
APLActionWaitUntil wait_until = 14;
APLActionRelativeSchedule relative_schedule = 24;
APLActionSchedule schedule = 15;
APLActionPeriodicSchedule periodic_schedule = 25;

// Sequences
APLActionSequence sequence = 2;
Expand Down Expand Up @@ -219,13 +221,27 @@ message APLActionWaitUntil {
APLValue condition = 1;
}

message APLActionRelativeSchedule {
// relative time compared to current time, e.g. '1s'
string schedule = 1;

APLAction inner_action = 2;
}

message APLActionSchedule {
// Comma-separated list of times, e.g. '0s, 30s, 60s'
string schedule = 1;

APLAction inner_action = 2;
}

message APLActionPeriodicSchedule {
// Comma-separated list of starttime and period e.g. '1s, 3s' for every 3 seconds starting at 1 seconds
string schedule = 1;

APLAction inner_action = 2;
}

message APLActionSequence {
string name = 1;

Expand Down
16 changes: 16 additions & 0 deletions sim/core/apl_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"fmt"
"time"

"github.com/wowsims/sod/sim/core/proto"
)
Expand All @@ -26,6 +27,10 @@ func (action *APLAction) Execute(sim *Simulation) {
action.impl.Execute(sim)
}

func (action *APLAction) ExecuteOffGCD(sim *Simulation, offGCDTime time.Duration) {
action.impl.ExecuteOffGCD(sim, offGCDTime)
}

// Returns this Action, along with all inner Actions.
func (action *APLAction) GetAllActions() []*APLAction {
actions := action.impl.GetInnerActions()
Expand Down Expand Up @@ -90,9 +95,15 @@ type APLActionImpl interface {
// Whether this action is available to be used right now.
IsReady(*Simulation) bool

// Whether this action is available Even during GCD
IsOffGCDAction() bool

// Performs the action.
Execute(*Simulation)

// Performs the action off GCD at the given time
ExecuteOffGCD(*Simulation, time.Duration)

// Called only while this action is controlling the rotation.
GetNextAction(sim *Simulation) *APLAction

Expand All @@ -109,6 +120,7 @@ func (impl defaultAPLActionImpl) GetAPLValues() []APLValue { return
func (impl defaultAPLActionImpl) Finalize(*APLRotation) {}
func (impl defaultAPLActionImpl) Reset(*Simulation) {}
func (impl defaultAPLActionImpl) GetNextAction(*Simulation) *APLAction { return nil }
func (impl defaultAPLActionImpl) IsOffGCDAction() bool { return false }

func (rot *APLRotation) newAPLAction(config *proto.APLAction) *APLAction {
if config == nil {
Expand Down Expand Up @@ -155,8 +167,12 @@ func (rot *APLRotation) newAPLActionImpl(config *proto.APLAction) APLActionImpl
return rot.newActionWait(config.GetWait())
case *proto.APLAction_WaitUntil:
return rot.newActionWaitUntil(config.GetWaitUntil())
case *proto.APLAction_RelativeSchedule:
return rot.newActionRelativeSchedule(config.GetRelativeSchedule())
case *proto.APLAction_Schedule:
return rot.newActionSchedule(config.GetSchedule())
case *proto.APLAction_PeriodicSchedule:
return rot.newActionPeriodicSchedule(config.GetPeriodicSchedule())

// Sequences
case *proto.APLAction_Sequence:
Expand Down
85 changes: 81 additions & 4 deletions sim/core/apl_actions_casting.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ package core

import (
"fmt"
"time"

"github.com/wowsims/sod/sim/core/proto"
)

type APLActionCastSpell struct {
defaultAPLActionImpl
spell *Spell
target UnitReference
spell *Spell
target UnitReference
offGCD bool
offGCDTime time.Duration
offGCDTimeExe time.Duration
}

func (rot *APLRotation) newActionCastSpell(config *proto.APLActionCastSpell) APLActionImpl {
Expand All @@ -26,12 +30,61 @@ func (rot *APLRotation) newActionCastSpell(config *proto.APLActionCastSpell) APL
target: target,
}
}

func (action *APLActionCastSpell) Reset(sim *Simulation) {
action.offGCD = false
action.offGCDTime = -1 * time.Minute
action.offGCDTimeExe = -1 * time.Minute
}

func (action *APLActionCastSpell) IsReady(sim *Simulation) bool {
return action.spell.CanCast(sim, action.target.Get()) && (!action.spell.Flags.Matches(SpellFlagMCD) || action.spell.Unit.GCD.IsReady(sim) || action.spell.DefaultCast.GCD == 0)
action.offGCD = false
ready := action.spell.CanCast(sim, action.target.Get()) && (!action.spell.Flags.Matches(SpellFlagMCD) || action.spell.Unit.GCD.IsReady(sim) || action.spell.DefaultCast.GCD == 0)

if !ready && (action.spell.DefaultCast.GCD == 0) && action.spell.CD.Timer != nil && (action.spell.CD.Timer.TimeToReady(sim) < 1500*time.Millisecond) && action.offGCDTimeExe != action.spell.CD.Timer.ReadyAt() {
//if sim.Log != nil {
// sim.Log("APLActionCastSpell IsReady offGCD")
//}
ready = true
action.offGCD = true
action.offGCDTime = action.spell.CD.Timer.ReadyAt()
}
return ready
}
func (action *APLActionCastSpell) IsOffGCDAction() bool {
return action.spell.DefaultCast.GCD == 0
}
func (action *APLActionCastSpell) Execute(sim *Simulation) {
action.spell.Cast(sim, action.target.Get())
if action.offGCD {
// Used when using APLActionCastSpell as an unnested action
action.offGCDTimeExe = action.offGCDTime
offGCDTimeExe := action.offGCDTimeExe
//if sim.Log != nil {
// sim.Log("APLActionCastSpell Execute Scheduling delayed off GCD action for %f", offGCDTimeExe)
//}
StartDelayedAction(sim, DelayedActionOptions{
DoAt: offGCDTimeExe,
OnAction: func(s *Simulation) {
if action.spell.CanCast(sim, action.target.Get()) {
action.spell.Cast(sim, action.target.Get())
}
},
})
} else {
action.spell.Cast(sim, action.target.Get())
}
}

func (action *APLActionCastSpell) ExecuteOffGCD(sim *Simulation, time time.Duration) {
//if sim.Log != nil {
// sim.Log("APLActionCastSpell ExecuteOffGCD Scheduling delayed off GCD action for %f", time)
//}
// Used when using APLActionCastSpell as a nested action (e.g. within a sequence)
action.offGCD = true
action.offGCDTime = time
action.Execute(sim) // Default to Execute unless impletented for this APL Action
}

func (action *APLActionCastSpell) String() string {
return fmt.Sprintf("Cast Spell(%s)", action.spell.ActionID)
}
Expand Down Expand Up @@ -82,6 +135,9 @@ func (action *APLActionChannelSpell) GetAPLValues() []APLValue {
func (action *APLActionChannelSpell) IsReady(sim *Simulation) bool {
return action.spell.CanCast(sim, action.target.Get())
}
func (action *APLActionChannelSpell) IsOffGCDAction() bool {
return false
}
func (action *APLActionChannelSpell) Execute(sim *Simulation) {
action.spell.Cast(sim, action.target.Get())

Expand All @@ -95,6 +151,9 @@ func (action *APLActionChannelSpell) Execute(sim *Simulation) {
action.spell.Unit.Rotation.allowChannelRecastOnInterrupt = action.allowRecast
}
}
func (action *APLActionChannelSpell) ExecuteOffGCD(sim *Simulation, time time.Duration) {
action.Execute(sim) // Default to Execute unless impletented for this APL Action
}
func (action *APLActionChannelSpell) String() string {
return fmt.Sprintf("Channel Spell(%s, interruptIf=%s)", action.spell.ActionID, action.interruptIf)
}
Expand Down Expand Up @@ -167,9 +226,15 @@ func (action *APLActionMultidot) IsReady(sim *Simulation) bool {
}
return false
}
func (action *APLActionMultidot) IsOffGCDAction() bool {
return false
}
func (action *APLActionMultidot) Execute(sim *Simulation) {
action.spell.Cast(sim, action.nextTarget)
}
func (action *APLActionMultidot) ExecuteOffGCD(sim *Simulation, time time.Duration) {
action.Execute(sim) // Default to Execute unless impletented for this APL Action
}
func (action *APLActionMultidot) String() string {
return fmt.Sprintf("Multidot(%s)", action.spell.ActionID)
}
Expand Down Expand Up @@ -228,9 +293,15 @@ func (action *APLActionMultishield) IsReady(sim *Simulation) bool {
}
return false
}
func (action *APLActionMultishield) IsOffGCDAction() bool {
return false
}
func (action *APLActionMultishield) Execute(sim *Simulation) {
action.spell.Cast(sim, action.nextTarget)
}
func (action *APLActionMultishield) ExecuteOffGCD(sim *Simulation, time time.Duration) {
action.Execute(sim) // Default to Execute unless impletented for this APL Action
}
func (action *APLActionMultishield) String() string {
return fmt.Sprintf("Multishield(%s)", action.spell.ActionID)
}
Expand Down Expand Up @@ -259,10 +330,16 @@ func (action *APLActionAutocastOtherCooldowns) IsReady(sim *Simulation) bool {
// true even for MCDs which do not require the GCD.
return action.nextReadyMCD != nil && action.character.GCD.IsReady(sim)
}
func (action *APLActionAutocastOtherCooldowns) IsOffGCDAction() bool {
return false
}
func (action *APLActionAutocastOtherCooldowns) Execute(sim *Simulation) {
action.nextReadyMCD.tryActivateHelper(sim, action.character)
action.character.UpdateMajorCooldowns()
}
func (action *APLActionAutocastOtherCooldowns) ExecuteOffGCD(sim *Simulation, time time.Duration) {
action.Execute(sim) // Default to Execute unless impletented for this APL Action
}
func (action *APLActionAutocastOtherCooldowns) String() string {
return "Autocast Other Cooldowns"
}
Loading