From c2fc0c013f4f0215dd9bc45e64568df6795c4fb2 Mon Sep 17 00:00:00 2001 From: James Tanner Date: Sat, 7 Oct 2023 19:01:17 -0700 Subject: [PATCH] Handle a few more cases of spells failing during prepull --- sim/core/cast.go | 37 +++++++++++++++++-------------------- sim/core/energy.go | 7 +++---- sim/core/focus.go | 7 +++---- sim/core/mana.go | 7 +++---- sim/core/rage.go | 8 ++++---- sim/core/runic_power.go | 4 ++-- sim/core/spell.go | 4 ++-- 7 files changed, 34 insertions(+), 40 deletions(-) diff --git a/sim/core/cast.go b/sim/core/cast.go index 3283a57545..46a07e75e6 100644 --- a/sim/core/cast.go +++ b/sim/core/cast.go @@ -65,13 +65,19 @@ func (cast *Cast) EffectiveTime() time.Duration { type CastFunc func(*Simulation, *Unit) type CastSuccessFunc func(*Simulation, *Unit) bool -func (spell *Spell) castFailureHelper(sim *Simulation, message string, vals ...interface{}) bool { +func (spell *Spell) castFailureHelper(sim *Simulation, gracefulFailure bool, message string, vals ...interface{}) bool { reason := fmt.Sprintf(spell.ActionID.String()+" failed to cast: "+message, vals...) if sim.CurrentTime < 0 && spell.Unit.IsUsingAPL { spell.Unit.Rotation.ValidationWarning(reason) return false + } else if gracefulFailure { + if sim.Log != nil && !spell.Flags.Matches(SpellFlagNoLogs) { + spell.Unit.Log(sim, reason) + } + return false + } else { + panic(reason) } - panic(reason) } func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc { @@ -90,19 +96,13 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc { if spell.ExtraCastCondition != nil { if !spell.ExtraCastCondition(sim, target) { - if sim.Log != nil { - sim.Log("Failed cast because of extra condition") - } - return false + return spell.castFailureHelper(sim, true, "extra spell condition") } } if spell.Cost != nil { if !spell.Cost.MeetsRequirement(spell) { - if sim.Log != nil && !spell.Flags.Matches(SpellFlagNoLogs) { - spell.Cost.LogCostFailure(sim, spell) - } - return false + return spell.castFailureHelper(sim, true, spell.Cost.CostFailureReason(sim, spell)) } } @@ -119,7 +119,7 @@ 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, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime) + return spell.castFailureHelper(sim, false, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime) } spell.CD.Set(sim.CurrentTime + spell.CurCast.CastTime + spell.CD.Duration) } @@ -127,18 +127,18 @@ func (spell *Spell) makeCastFunc(config CastConfig) CastSuccessFunc { 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, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime) + return spell.castFailureHelper(sim, false, "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, "GCD on cooldown for %s, curTime = %s", spell.Unit.GCD.TimeToReady(sim), sim.CurrentTime) + return spell.castFailureHelper(sim, false, "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, "casting/channeling %v for %s, curTime = %s", hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime) + return spell.castFailureHelper(sim, false, "casting/channeling %v for %s, curTime = %s", hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime) } if effectiveTime := spell.CurCast.EffectiveTime(); effectiveTime != 0 { @@ -210,17 +210,14 @@ func (spell *Spell) makeCastFuncSimple() CastSuccessFunc { return func(sim *Simulation, target *Unit) bool { if spell.ExtraCastCondition != nil { if !spell.ExtraCastCondition(sim, target) { - if sim.Log != nil { - sim.Log("Failed cast because of extra condition") - } - return false + return spell.castFailureHelper(sim, true, "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, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime) + return spell.castFailureHelper(sim, false, "still on cooldown for %s, curTime = %s", spell.CD.TimeToReady(sim), sim.CurrentTime) } spell.CD.Set(sim.CurrentTime + spell.CD.Duration) @@ -229,7 +226,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, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime) + return spell.castFailureHelper(sim, false, "still on shared cooldown for %s, curTime = %s", spell.SharedCD.TimeToReady(sim), sim.CurrentTime) } spell.SharedCD.Set(sim.CurrentTime + spell.SharedCD.Duration) diff --git a/sim/core/energy.go b/sim/core/energy.go index bec4d39dcb..167e8269cb 100644 --- a/sim/core/energy.go +++ b/sim/core/energy.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "time" "github.com/wowsims/wotlk/sim/core/proto" @@ -202,10 +203,8 @@ func (ec *EnergyCost) MeetsRequirement(spell *Spell) bool { spell.CurCast.Cost = spell.ApplyCostModifiers(spell.CurCast.Cost) return spell.Unit.CurrentEnergy() >= spell.CurCast.Cost } -func (ec *EnergyCost) LogCostFailure(sim *Simulation, spell *Spell) { - spell.Unit.Log(sim, - "Failed casting %s, not enough energy. (Current Energy = %0.03f, Energy Cost = %0.03f)", - spell.ActionID, spell.Unit.CurrentEnergy(), spell.CurCast.Cost) +func (ec *EnergyCost) CostFailureReason(sim *Simulation, spell *Spell) string { + return fmt.Sprintf("not enough energy (Current Energy = %0.03f, Energy Cost = %0.03f)", spell.Unit.CurrentEnergy(), spell.CurCast.Cost) } func (ec *EnergyCost) SpendCost(sim *Simulation, spell *Spell) { if spell.CurCast.Cost > 0 { diff --git a/sim/core/focus.go b/sim/core/focus.go index fa75f650a3..2868da95b5 100644 --- a/sim/core/focus.go +++ b/sim/core/focus.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "time" "github.com/wowsims/wotlk/sim/core/proto" @@ -122,10 +123,8 @@ func (fc *FocusCost) MeetsRequirement(spell *Spell) bool { spell.CurCast.Cost = max(0, spell.CurCast.Cost*spell.Unit.PseudoStats.CostMultiplier) return spell.Unit.CurrentFocus() >= spell.CurCast.Cost } -func (fc *FocusCost) LogCostFailure(sim *Simulation, spell *Spell) { - spell.Unit.Log(sim, - "Failed casting %s, not enough focus. (Current Focus = %0.03f, Focus Cost = %0.03f)", - spell.ActionID, spell.Unit.CurrentFocus(), spell.CurCast.Cost) +func (fc *FocusCost) CostFailureReason(sim *Simulation, spell *Spell) string { + return fmt.Sprintf("not enough focus (Current Focus = %0.03f, Focus Cost = %0.03f)", spell.Unit.CurrentFocus(), spell.CurCast.Cost) } func (fc *FocusCost) SpendCost(sim *Simulation, spell *Spell) { spell.Unit.SpendFocus(sim, spell.CurCast.Cost, fc.ResourceMetrics) diff --git a/sim/core/mana.go b/sim/core/mana.go index 76069b3181..3c2134fcfb 100644 --- a/sim/core/mana.go +++ b/sim/core/mana.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "math" "time" @@ -322,10 +323,8 @@ func (mc *ManaCost) MeetsRequirement(spell *Spell) bool { spell.CurCast.Cost = spell.ApplyCostModifiers(spell.CurCast.Cost) return spell.Unit.CurrentMana() >= spell.CurCast.Cost } -func (mc *ManaCost) LogCostFailure(sim *Simulation, spell *Spell) { - spell.Unit.Log(sim, - "Failed casting %s, not enough mana. (Current Mana = %0.03f, Mana Cost = %0.03f)", - spell.ActionID, spell.Unit.CurrentMana(), spell.CurCast.Cost) +func (mc *ManaCost) CostFailureReason(sim *Simulation, spell *Spell) string { + return fmt.Sprintf("not enough mana (Current Mana = %0.03f, Mana Cost = %0.03f)", spell.Unit.CurrentMana(), spell.CurCast.Cost) } func (mc *ManaCost) SpendCost(sim *Simulation, spell *Spell) { if spell.CurCast.Cost > 0 { diff --git a/sim/core/rage.go b/sim/core/rage.go index aaf6883bc9..6125a18934 100644 --- a/sim/core/rage.go +++ b/sim/core/rage.go @@ -1,6 +1,8 @@ package core import ( + "fmt" + "github.com/wowsims/wotlk/sim/core/proto" ) @@ -223,10 +225,8 @@ func (rc *RageCost) MeetsRequirement(spell *Spell) bool { spell.CurCast.Cost = spell.ApplyCostModifiers(spell.CurCast.Cost) return spell.Unit.CurrentRage() >= spell.CurCast.Cost } -func (rc *RageCost) LogCostFailure(sim *Simulation, spell *Spell) { - spell.Unit.Log(sim, - "Failed casting %s, not enough rage. (Current Rage = %0.03f, Rage Cost = %0.03f)", - spell.ActionID, spell.Unit.CurrentRage(), spell.CurCast.Cost) +func (rc *RageCost) CostFailureReason(sim *Simulation, spell *Spell) string { + return fmt.Sprintf("not enough rage (Current Rage = %0.03f, Rage Cost = %0.03f)", spell.Unit.CurrentRage(), spell.CurCast.Cost) } func (rc *RageCost) SpendCost(sim *Simulation, spell *Spell) { if spell.CurCast.Cost > 0 { diff --git a/sim/core/runic_power.go b/sim/core/runic_power.go index ae658bc528..5b40bac5f6 100644 --- a/sim/core/runic_power.go +++ b/sim/core/runic_power.go @@ -844,8 +844,8 @@ func (rc *RuneCostImpl) MeetsRequirement(spell *Spell) bool { return true } -func (rc *RuneCostImpl) LogCostFailure(sim *Simulation, spell *Spell) { - spell.Unit.Log(sim, "Failed casting %s, not enough RP or runes.", spell.ActionID) +func (rc *RuneCostImpl) CostFailureReason(sim *Simulation, spell *Spell) string { + return "not enough RP or runes" } func (rc *RuneCostImpl) SpendCost(sim *Simulation, spell *Spell) { diff --git a/sim/core/spell.go b/sim/core/spell.go index b4c27b67d0..dc0408b849 100644 --- a/sim/core/spell.go +++ b/sim/core/spell.go @@ -591,8 +591,8 @@ type SpellCost interface { // requirements to cast the spell. MeetsRequirement(*Spell) bool - // Logs a message for when the cast fails due to lack of resources. - LogCostFailure(*Simulation, *Spell) + // Returns a message for when the cast fails due to lack of resources. + CostFailureReason(*Simulation, *Spell) string // Subtracts the resources used from a cast from the Unit. SpendCost(*Simulation, *Spell)