Skip to content

Commit

Permalink
Merge pull request #4 from wowsims/pet-target-changes
Browse files Browse the repository at this point in the history
Pull in pet/target unit updates from #4118
  • Loading branch information
rosenrusinov authored Jan 31, 2024
2 parents 19c880c + 4c46aba commit 083aab5
Show file tree
Hide file tree
Showing 29 changed files with 380 additions and 161 deletions.
8 changes: 7 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: 19
// NextIndex: 21
message APLAction {
APLValue condition = 1; // If set, action will only execute if value is true or != 0.

Expand Down Expand Up @@ -73,6 +73,9 @@ message APLAction {

// Class or Spec-specific actions
APLActionCatOptimalRotationAction cat_optimal_rotation_action = 19;

// Internal use only, not exposed in UI.
APLActionCustomRotation custom_rotation = 20;
}
}

Expand Down Expand Up @@ -254,6 +257,9 @@ message APLActionMove {
APLValue range_from_target = 1;
}

message APLActionCustomRotation {
}

///////////////////////////////////////////////////////////////////////////
// VALUES
///////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 1 addition & 5 deletions sim/_shaman/fire_elemental_pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (fireElemental *FireElemental) Reset(_ *core.Simulation) {

}

func (fireElemental *FireElemental) OnGCDReady(sim *core.Simulation) {
func (fireElemental *FireElemental) ExecuteCustomRotation(sim *core.Simulation) {
/*
TODO this is a little dirty, can probably clean this up, the rotation might go through some more overhauls,
the random AI is hard to emulate.
Expand Down Expand Up @@ -122,10 +122,6 @@ func (fireElemental *FireElemental) TryCast(sim *core.Simulation, target *core.U
return false
}

if !spell.IsReady(sim) {
return false
}

if !spell.Cast(sim, target) {
return false
}
Expand Down
3 changes: 1 addition & 2 deletions sim/_shaman/spirit_wolves.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ func (spiritWolf *SpiritWolf) Initialize() {
// Nothing
}

func (spiritWolf *SpiritWolf) OnGCDReady(_ *core.Simulation) {
spiritWolf.DoNothing()
func (spiritWolf *SpiritWolf) ExecuteCustomRotation(_ *core.Simulation) {
}

func (spiritWolf *SpiritWolf) Reset(sim *core.Simulation) {
Expand Down
4 changes: 4 additions & 0 deletions sim/core/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type Agent interface {
// Should return nil when the config doesn't match any custom behaviors.
NewAPLValue(rot *APLRotation, config *proto.APLValue) APLValue
NewAPLAction(rot *APLRotation, config *proto.APLAction) APLActionImpl

// Implements custom rotation behavior. Usually for pets and targets but can be used
// for players too.
ExecuteCustomRotation(sim *Simulation)
}

type ActionID struct {
Expand Down
13 changes: 13 additions & 0 deletions sim/core/apl.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ func (rot *APLRotation) doAndRecordWarnings(warningsList *[]string, isPrepull bo
rot.parsingPrepull = false
}

func (unit *Unit) newCustomRotation() *APLRotation {
return unit.newAPLRotation(&proto.APLRotation{
Type: proto.APLRotation_TypeAPL,
PriorityList: []*proto.APLListItem{
{
Action: &proto.APLAction{
Action: &proto.APLAction_CustomRotation{},
},
},
},
})
}

func (unit *Unit) newAPLRotation(config *proto.APLRotation) *APLRotation {
if config == nil {
return nil
Expand Down
4 changes: 3 additions & 1 deletion sim/core/apl_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (rot *APLRotation) newAPLActionImpl(config *proto.APLAction) APLActionImpl
return nil
}

customAction := rot.unit.Env.Raid.GetPlayerFromUnit(rot.unit).NewAPLAction(rot, config)
customAction := rot.unit.Env.GetAgentFromUnit(rot.unit).NewAPLAction(rot, config)
if customAction != nil {
return customAction
}
Expand Down Expand Up @@ -179,6 +179,8 @@ func (rot *APLRotation) newAPLActionImpl(config *proto.APLAction) APLActionImpl
return rot.newActionItemSwap(config.GetItemSwap())
case *proto.APLAction_Move:
return rot.newActionMove(config.GetMove())
case *proto.APLAction_CustomRotation:
return rot.newActionCustomRotation(config.GetCustomRotation())
default:
return nil
}
Expand Down
35 changes: 35 additions & 0 deletions sim/core/apl_actions_misc.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 Down Expand Up @@ -188,3 +189,37 @@ func (action *APLActionMove) Execute(sim *Simulation) {
func (action *APLActionMove) String() string {
return fmt.Sprintf("Move(%s)", action.moveRange)
}

type APLActionCustomRotation struct {
defaultAPLActionImpl
unit *Unit
agent Agent

lastExecutedAt time.Duration
}

func (rot *APLRotation) newActionCustomRotation(config *proto.APLActionCustomRotation) APLActionImpl {
agent := rot.unit.Env.GetAgentFromUnit(rot.unit)
if agent == nil {
panic("Agent not found for custom rotation")
}

return &APLActionCustomRotation{
unit: rot.unit,
agent: agent,
}
}
func (action *APLActionCustomRotation) Reset(sim *Simulation) {
action.lastExecutedAt = -1
}
func (action *APLActionCustomRotation) IsReady(sim *Simulation) bool {
// Prevent infinite loops by only allowing this action to be performed once at each timestamp.
return action.lastExecutedAt != sim.CurrentTime
}
func (action *APLActionCustomRotation) Execute(sim *Simulation) {
action.lastExecutedAt = sim.CurrentTime
action.agent.ExecuteCustomRotation(sim)
}
func (action *APLActionCustomRotation) String() string {
return "Custom Rotation()"
}
2 changes: 1 addition & 1 deletion sim/core/apl_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (rot *APLRotation) newAPLValue(config *proto.APLValue) APLValue {
return nil
}

customValue := rot.unit.Env.Raid.GetPlayerFromUnit(rot.unit).NewAPLValue(rot, config)
customValue := rot.unit.Env.GetAgentFromUnit(rot.unit).NewAPLValue(rot, config)
if customValue != nil {
return customValue
}
Expand Down
26 changes: 12 additions & 14 deletions sim/core/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,13 @@ func (cast *Cast) EffectiveTime() time.Duration {
type CastFunc func(*Simulation, *Unit)
type CastSuccessFunc func(*Simulation, *Unit) bool

func (spell *Spell) castFailureHelper(sim *Simulation, gracefulFailure bool, message string, vals ...any) bool {
func (spell *Spell) castFailureHelper(sim *Simulation, message string, vals ...any) bool {
if sim.CurrentTime < 0 && spell.Unit.Rotation != nil {
spell.Unit.Rotation.ValidationWarning(fmt.Sprintf(spell.ActionID.String()+" failed to cast: "+message, vals...))
} else if gracefulFailure {
} else {
if sim.Log != nil && !spell.Flags.Matches(SpellFlagNoLogs) {
spell.Unit.Log(sim, fmt.Sprintf(spell.ActionID.String()+" failed to cast: "+message, vals...))
}
} else {
panic(fmt.Sprintf(spell.ActionID.String()+" failed to cast: "+message, vals...))
}
return false
}
Expand Down Expand Up @@ -151,13 +149,13 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {

if spell.ExtraCastCondition != nil {
if !spell.ExtraCastCondition(sim, target) {
return spell.castFailureHelper(sim, true, "extra spell condition")
return spell.castFailureHelper(sim, "extra spell condition")
}
}

if spell.Cost != nil {
if !spell.Cost.MeetsRequirement(sim, spell) {
return spell.castFailureHelper(sim, true, spell.Cost.CostFailureReason(sim, spell))
return spell.castFailureHelper(sim, spell.Cost.CostFailureReason(sim, spell))
}
}

Expand All @@ -169,26 +167,26 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {
if config.CD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.CD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
}
spell.CD.Set(sim.CurrentTime + spell.CurCast.CastTime + spell.CD.Duration)
}

if config.SharedCD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.SharedCD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
}
spell.SharedCD.Set(sim.CurrentTime + spell.CurCast.CastTime + spell.SharedCD.Duration)
}

// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if spell.CurCast.GCD != 0 && !spell.Unit.GCD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "GCD on cooldown for %s, curTime = %s", spell.Unit.GCD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "GCD on cooldown for %s, curTime = %s", spell.Unit.GCD.TimeToReady(sim), sim.CurrentTime)
}

if hc := spell.Unit.Hardcast; hc.Expires > sim.CurrentTime {
return spell.castFailureHelper(sim, false, "casting/channeling %v for %s, curTime = %s", hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime)
return spell.castFailureHelper(sim, "casting/channeling %v for %s, curTime = %s", hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime)
}

if effectiveTime := spell.CurCast.EffectiveTime(); effectiveTime != 0 {
Expand All @@ -200,7 +198,7 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc {
}

if (spell.CurCast.CastTime > 0) && spell.Unit.Moving {
return spell.castFailureHelper(sim, false, "casting/channeling while moving not allowed!")
return spell.castFailureHelper(sim, "casting/channeling while moving not allowed!")
}

// TODO: Fix with removal of ChannelTime?
Expand Down Expand Up @@ -274,14 +272,14 @@ func (spell *Spell) makeCastFuncSimple() CastSuccessFunc {
return func(sim *Simulation, target *Unit) bool {
if spell.ExtraCastCondition != nil {
if !spell.ExtraCastCondition(sim, target) {
return spell.castFailureHelper(sim, true, "extra spell condition")
return spell.castFailureHelper(sim, "extra spell condition")
}
}

if spell.CD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.CD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime)
}

spell.CD.Set(sim.CurrentTime + spell.CD.Duration)
Expand All @@ -290,7 +288,7 @@ func (spell *Spell) makeCastFuncSimple() CastSuccessFunc {
if spell.SharedCD.Timer != nil {
// By panicking if spell is on CD, we force each sim to properly check for their own CDs.
if !spell.SharedCD.IsReady(sim) {
return spell.castFailureHelper(sim, false, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
return spell.castFailureHelper(sim, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime)
}

spell.SharedCD.Set(sim.CurrentTime + spell.SharedCD.Duration)
Expand Down
18 changes: 18 additions & 0 deletions sim/core/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ func (env *Environment) finalize(raidProto *proto.Raid, _ *proto.Encounter, raid

for _, target := range env.Encounter.Targets {
target.finalize()
if target.AI != nil {
target.Rotation = target.newCustomRotation()
}
}

for _, party := range env.Raid.Parties {
Expand All @@ -156,6 +159,7 @@ func (env *Environment) finalize(raidProto *proto.Raid, _ *proto.Encounter, raid
character.Finalize()
for _, pet := range character.Pets {
pet.Finalize()
pet.Rotation = pet.newCustomRotation()
}
}
}
Expand Down Expand Up @@ -264,6 +268,20 @@ func (env *Environment) NextTarget(target *Unit) *Target {
func (env *Environment) NextTargetUnit(target *Unit) *Unit {
return &env.NextTarget(target).Unit
}
func (env *Environment) GetAgentFromUnit(unit *Unit) Agent {
raidAgent := env.Raid.GetPlayerFromUnit(unit)
if raidAgent != nil {
return raidAgent
}

for _, target := range env.Encounter.Targets {
if unit == &target.Unit {
return target
}
}

return nil
}

func (env *Environment) GetUnit(ref *proto.UnitReference, contextUnit *Unit) *Unit {
if ref == nil {
Expand Down
1 change: 1 addition & 0 deletions sim/core/pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,4 @@ func (pet *Pet) AddRaidBuffs(_ *proto.RaidBuffs) {}
func (pet *Pet) AddPartyBuffs(_ *proto.PartyBuffs) {}
func (pet *Pet) ApplyTalents() {}
func (pet *Pet) ApplyRunes() {}
func (pet *Pet) OnGCDReady(_ *Simulation) {}
2 changes: 1 addition & 1 deletion sim/core/target_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
type TargetAI interface {
Initialize(*Target, *proto.Target)
Reset(*Simulation)
DoAction(*Simulation)
ExecuteCustomRotation(*Simulation)
}

func (target *Target) initialize(config *proto.Target) {
Expand Down
1 change: 1 addition & 0 deletions sim/core/target_dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ func (td *TargetDummy) ApplyTalents() {}
func (td *TargetDummy) ApplyRunes() {}
func (td *TargetDummy) Initialize() {}
func (td *TargetDummy) Reset(sim *Simulation) {}
func (td *TargetDummy) ExecuteCustomRotation(sim *Simulation) {}
4 changes: 4 additions & 0 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,3 +604,7 @@ func (unit *Unit) GetMetadata() *proto.UnitMetadata {

return metadata
}

func (unit *Unit) ExecuteCustomRotation(sim *Simulation) {
panic("Unimplemented ExecuteCustomRotation")
}
2 changes: 1 addition & 1 deletion sim/encounters/default_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (ai *DefaultAI) Reset(sim *core.Simulation) {

}

func (ai *DefaultAI) DoAction(sim *core.Simulation) {
func (ai *DefaultAI) ExecuteCustomRotation(sim *core.Simulation) {
for _, ability := range ai.Abilities {
if sim.CurrentTime < ability.InitialCD {
continue
Expand Down
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/kelthuzad25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ func (ai *KelThuzad25AI) Initialize(target *core.Target, config *proto.Target) {
func (ai *KelThuzad25AI) Reset(*core.Simulation) {
}

func (ai *KelThuzad25AI) DoAction(sim *core.Simulation) {
func (ai *KelThuzad25AI) ExecuteCustomRotation(sim *core.Simulation) {
}
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/loatheb25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ func (ai *Loatheb25AI) Initialize(target *core.Target, config *proto.Target) {
func (ai *Loatheb25AI) Reset(*core.Simulation) {
}

func (ai *Loatheb25AI) DoAction(sim *core.Simulation) {
func (ai *Loatheb25AI) ExecuteCustomRotation(sim *core.Simulation) {
}
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/patchwerk10_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (ai *Patchwerk10AI) registerFrenzySpell(target *core.Target) {
})
}

func (ai *Patchwerk10AI) DoAction(sim *core.Simulation) {
func (ai *Patchwerk10AI) ExecuteCustomRotation(sim *core.Simulation) {
if ai.Target.CurrentTarget == nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/patchwerk25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (ai *Patchwerk25AI) registerFrenzySpell(target *core.Target) {
})
}

func (ai *Patchwerk25AI) DoAction(sim *core.Simulation) {
func (ai *Patchwerk25AI) ExecuteCustomRotation(sim *core.Simulation) {
if ai.Target.CurrentTarget == nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion sim/encounters/naxxramas/thaddius25_ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ func (ai *Thaddius25AI) Initialize(target *core.Target, config *proto.Target) {
func (ai *Thaddius25AI) Reset(*core.Simulation) {
}

func (ai *Thaddius25AI) DoAction(sim *core.Simulation) {
func (ai *Thaddius25AI) ExecuteCustomRotation(sim *core.Simulation) {
}
3 changes: 2 additions & 1 deletion sim/hunter/pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (hp *HunterPet) Reset(_ *core.Simulation) {
hp.uptimePercent = min(1, max(0, hp.hunterOwner.Options.PetUptime))
}

func (hp *HunterPet) OnGCDReady(sim *core.Simulation) {
func (hp *HunterPet) ExecuteCustomRotation(sim *core.Simulation) {
percentRemaining := sim.GetRemainingDurationPercent()
if percentRemaining < 1.0-hp.uptimePercent { // once fight is % completed, disable pet.
hp.Disable(sim)
Expand All @@ -120,6 +120,7 @@ func (hp *HunterPet) OnGCDReady(sim *core.Simulation) {
}

target := hp.CurrentTarget

if hp.focusDump == nil {
hp.specialAbility.Cast(sim, target)
return
Expand Down
Loading

0 comments on commit 083aab5

Please sign in to comment.