Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
TheGroxEmpire committed Jan 13, 2023
2 parents a67dc51 + 76bf188 commit f2abeb6
Show file tree
Hide file tree
Showing 295 changed files with 22,467 additions and 17,622 deletions.
Binary file modified assets/database/db.bin
Binary file not shown.
2,254 changes: 2,253 additions & 1 deletion assets/database/db.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions proto/deathknight.proto
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ message Deathknight {
bool hold_erw_army = 22;

bool use_gargoyle = 23;

bool nerfed_gargoyle = 24;

Presence gargoyle_presence = 25;
}
Rotation rotation = 1;

Expand Down
62 changes: 17 additions & 45 deletions sim/core/cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (spell *Spell) ApplyCostModifiers(cost float64) float64 {
}

func (spell *Spell) wrapCastFuncInit(config CastConfig, onCastComplete CastSuccessFunc) CastSuccessFunc {
if config.DefaultCast == emptyCast {
if spell.DefaultCast == emptyCast {
return onCastComplete
}

Expand All @@ -113,49 +113,27 @@ func (spell *Spell) wrapCastFuncInit(config CastConfig, onCastComplete CastSucce
}

func (spell *Spell) wrapCastFuncResources(config CastConfig, onCastComplete CastFunc) CastSuccessFunc {
if spell.ResourceType == 0 || config.DefaultCast.Cost == 0 {
if spell.ResourceType == 0 || spell.DefaultCast.Cost == 0 {
return func(sim *Simulation, target *Unit) bool {
onCastComplete(sim, target)
return true
}
}

switch spell.ResourceType {
case stats.Mana:
if spell.Cost != nil {
return func(sim *Simulation, target *Unit) bool {
spell.CurCast.Cost = spell.ApplyCostModifiers(spell.CurCast.Cost)
if spell.Unit.CurrentMana() < spell.CurCast.Cost {
if !spell.Cost.MeetsRequirement(spell) {
if sim.Log != nil && !spell.Flags.Matches(SpellFlagNoLogs) {
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)
spell.Cost.LogCostFailure(sim, spell)
}
return false
}

// Mana is subtracted at the end of the cast.
onCastComplete(sim, target)
return true
}
case stats.Rage:
return func(sim *Simulation, target *Unit) bool {
spell.CurCast.Cost = spell.ApplyCostModifiers(spell.CurCast.Cost)
if spell.Unit.CurrentRage() < spell.CurCast.Cost {
return false
}
spell.Unit.SpendRage(sim, spell.CurCast.Cost, spell.ResourceMetrics)
onCastComplete(sim, target)
return true
}
case stats.Energy:
return func(sim *Simulation, target *Unit) bool {
spell.CurCast.Cost = spell.ApplyCostModifiers(spell.CurCast.Cost)
if spell.Unit.CurrentEnergy() < spell.CurCast.Cost {
return false
}
spell.Unit.SpendEnergy(sim, spell.CurCast.Cost, spell.ResourceMetrics)
onCastComplete(sim, target)
return true
}
}

switch spell.ResourceType {
case stats.RunicPower:
return func(sim *Simulation, target *Unit) bool {
// Rune spending is currently handled in DK codebase.
Expand Down Expand Up @@ -185,7 +163,7 @@ func (spell *Spell) wrapCastFuncResources(config CastConfig, onCastComplete Cast
}

func (spell *Spell) wrapCastFuncHaste(config CastConfig, onCastComplete CastFunc) CastFunc {
if config.IgnoreHaste || (config.DefaultCast.GCD == 0 && config.DefaultCast.CastTime == 0 && config.DefaultCast.ChannelTime == 0) {
if config.IgnoreHaste || (spell.DefaultCast.GCD == 0 && spell.DefaultCast.CastTime == 0 && spell.DefaultCast.ChannelTime == 0) {
return onCastComplete
}

Expand All @@ -199,11 +177,11 @@ func (spell *Spell) wrapCastFuncHaste(config CastConfig, onCastComplete CastFunc
}

func (spell *Spell) wrapCastFuncGCD(config CastConfig, onCastComplete CastFunc) CastFunc {
if config.DefaultCast == emptyCast { // spells that are not actually cast (e.g. auto attacks, procs)
if spell.DefaultCast == emptyCast { // spells that are not actually cast (e.g. auto attacks, procs)
return onCastComplete
}

if config.DefaultCast.GCD == 0 { // mostly cooldowns (e.g. nature's swiftness, presence of mind)
if spell.DefaultCast.GCD == 0 { // mostly cooldowns (e.g. nature's swiftness, presence of mind)
return func(sim *Simulation, target *Unit) {
if hc := spell.Unit.Hardcast; hc.Expires > sim.CurrentTime {
panic(fmt.Sprintf("Trying to cast %s but casting/channeling %v for %s, curTime = %s", spell.ActionID, hc.ActionID, hc.Expires-sim.CurrentTime, sim.CurrentTime))
Expand Down Expand Up @@ -276,8 +254,8 @@ func (spell *Spell) wrapCastFuncSharedCooldown(config CastConfig, onCastComplete

func (spell *Spell) makeCastFuncWait(config CastConfig, onCastComplete CastFunc) CastFunc {
if !spell.Flags.Matches(SpellFlagNoOnCastComplete) {
configOnCastComplete := config.OnCastComplete
oldOnCastComplete1 := onCastComplete
configOnCastComplete := config.OnCastComplete
onCastComplete = func(sim *Simulation, target *Unit) {
oldOnCastComplete1(sim, target)
if configOnCastComplete != nil {
Expand All @@ -287,18 +265,15 @@ func (spell *Spell) makeCastFuncWait(config CastConfig, onCastComplete CastFunc)
}
}

if spell.ResourceType == stats.Mana && config.DefaultCast.Cost != 0 {
if spell.Cost != nil {
oldOnCastComplete2 := onCastComplete
onCastComplete = func(sim *Simulation, target *Unit) {
if spell.CurCast.Cost > 0 {
spell.Unit.SpendMana(sim, spell.CurCast.Cost, spell.ResourceMetrics)
spell.Unit.PseudoStats.FiveSecondRuleRefreshTime = sim.CurrentTime + time.Second*5
}
spell.Cost.SpendCost(sim, spell)
oldOnCastComplete2(sim, target)
}
}

if config.DefaultCast.ChannelTime > 0 {
if spell.DefaultCast.ChannelTime > 0 {
return func(sim *Simulation, target *Unit) {
spell.Unit.Hardcast = Hardcast{Expires: sim.CurrentTime + spell.CurCast.ChannelTime, ActionID: spell.ActionID}
if sim.Log != nil && !spell.Flags.Matches(SpellFlagNoLogs) {
Expand All @@ -310,7 +285,7 @@ func (spell *Spell) makeCastFuncWait(config CastConfig, onCastComplete CastFunc)
}
}

if config.DefaultCast.CastTime == 0 {
if spell.DefaultCast.CastTime == 0 {
if spell.Flags.Matches(SpellFlagNoLogs) {
return onCastComplete
} else {
Expand All @@ -328,10 +303,7 @@ func (spell *Spell) makeCastFuncWait(config CastConfig, onCastComplete CastFunc)
oldOnCastComplete3 := onCastComplete
onCastComplete = func(sim *Simulation, target *Unit) {
if sim.Log != nil && !spell.Flags.Matches(SpellFlagNoLogs) {
// Hunter fake cast has no ID.
if !spell.ActionID.SameAction(ActionID{}) {
spell.Unit.Log(sim, "Completed cast %s", spell.ActionID)
}
spell.Unit.Log(sim, "Completed cast %s", spell.ActionID)
}
oldOnCastComplete3(sim, target)
}
Expand Down
2 changes: 1 addition & 1 deletion sim/core/debuffs.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ func ExposeArmorAura(target *Unit, hasGlyph bool) *Aura {
const armorReduction = 0.2
aura := target.GetOrRegisterAura(Aura{
Label: "ExposeArmor",
ActionID: ActionID{SpellID: 48669},
ActionID: ActionID{SpellID: 8647},
Duration: time.Second * TernaryDuration(hasGlyph, 42, 30),
})

Expand Down
48 changes: 48 additions & 0 deletions sim/core/energy.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"time"

"github.com/wowsims/wotlk/sim/core/proto"
"github.com/wowsims/wotlk/sim/core/stats"
)

// Time between energy ticks.
Expand Down Expand Up @@ -164,3 +165,50 @@ func (eb *energyBar) reset(sim *Simulation) {
eb.comboPoints = 0
eb.newTickAction(sim, true)
}

type EnergyCostOptions struct {
Cost float64

Refund float64
RefundMetrics *ResourceMetrics // Optional, will default to unit.EnergyRefundMetrics if not supplied.
}
type EnergyCost struct {
Refund float64
RefundMetrics *ResourceMetrics
ResourceMetrics *ResourceMetrics
}

func newEnergyCost(spell *Spell, options EnergyCostOptions) *EnergyCost {
spell.ResourceType = stats.Energy
spell.BaseCost = options.Cost
spell.DefaultCast.Cost = options.Cost
if options.Refund > 0 && options.RefundMetrics == nil {
options.RefundMetrics = spell.Unit.EnergyRefundMetrics
}

return &EnergyCost{
Refund: options.Refund,
RefundMetrics: options.RefundMetrics,
ResourceMetrics: spell.Unit.NewEnergyMetrics(spell.ActionID),
}
}

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) SpendCost(sim *Simulation, spell *Spell) {
if spell.CurCast.Cost > 0 {
spell.Unit.SpendEnergy(sim, spell.CurCast.Cost, ec.ResourceMetrics)
}
}
func (ec *EnergyCost) IssueRefund(sim *Simulation, spell *Spell) {
if ec.Refund > 0 {
spell.Unit.AddEnergy(sim, ec.Refund*spell.CurCast.Cost, ec.RefundMetrics)
}
}
37 changes: 37 additions & 0 deletions sim/core/mana.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,40 @@ func (mb *manaBar) reset() {

mb.currentMana = mb.unit.MaxMana()
}

type ManaCostOptions struct {
BaseCost float64
FlatCost float64 // Alternative to BaseCost for giving a flat value.
Multiplier float64 // It's OK to leave this at 0, will default to 1.
}
type ManaCost struct {
ResourceMetrics *ResourceMetrics
}

func newManaCost(spell *Spell, options ManaCostOptions) *ManaCost {
spell.ResourceType = stats.Mana
spell.BaseCost = TernaryFloat64(options.FlatCost > 0, options.FlatCost, options.BaseCost*spell.Unit.BaseMana)
spell.DefaultCast.Cost = spell.BaseCost * TernaryFloat64(options.Multiplier == 0, 1, options.Multiplier)

return &ManaCost{
ResourceMetrics: spell.Unit.NewManaMetrics(spell.ActionID),
}
}

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) SpendCost(sim *Simulation, spell *Spell) {
if spell.CurCast.Cost > 0 {
spell.Unit.SpendMana(sim, spell.CurCast.Cost, mc.ResourceMetrics)
spell.Unit.PseudoStats.FiveSecondRuleRefreshTime = sim.CurrentTime + time.Second*5
}
}
func (mc *ManaCost) IssueRefund(sim *Simulation, spell *Spell) {
}
29 changes: 19 additions & 10 deletions sim/core/pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ type Pet struct {
statInheritance PetStatInheritance

// No-op until finalized to prevent owner stats from affecting pet until we're ready.
currentStatInheritance PetStatInheritance
inheritedStats stats.Stats
currentStatInheritance PetStatInheritance
inheritedStats stats.Stats
guardianDynamicStatInheritance PetStatInheritance

// Whether this pet is currently active. Pets which are active throughout a whole
// encounter, like Hunter pets, are always enabled. Pets which are instead summoned,
Expand All @@ -52,7 +53,7 @@ type Pet struct {
timeoutAction *PendingAction
}

func NewPet(name string, owner *Character, baseStats stats.Stats, statInheritance PetStatInheritance, enabledOnStart bool, isGuardian bool) Pet {
func NewPet(name string, owner *Character, baseStats stats.Stats, statInheritance PetStatInheritance, guardianDynamicStatInheritance PetStatInheritance, enabledOnStart bool, isGuardian bool) Pet {
pet := Pet{
Character: Character{
Unit: Unit{
Expand All @@ -71,10 +72,11 @@ func NewPet(name string, owner *Character, baseStats stats.Stats, statInheritanc
PartyIndex: owner.PartyIndex,
baseStats: baseStats,
},
Owner: owner,
statInheritance: statInheritance,
enabledOnStart: enabledOnStart,
isGuardian: isGuardian,
Owner: owner,
statInheritance: statInheritance,
guardianDynamicStatInheritance: guardianDynamicStatInheritance,
enabledOnStart: enabledOnStart,
isGuardian: isGuardian,
}
pet.GCD = pet.NewTimer()
pet.currentStatInheritance = func(ownerStats stats.Stats) stats.Stats {
Expand All @@ -95,11 +97,18 @@ func (pet *Pet) OwnerAttackSpeedChanged(sim *Simulation) {}
// addedStats is the amount of stats added to the owner (will be negative if the
// owner lost stats).
func (pet *Pet) addOwnerStats(sim *Simulation, addedStats stats.Stats) {
// Temporary pets dont update stats after summon
if pet.isGuardian || !pet.enabled {
// Only gargoyle is a guardian that inherits haste dynamically
if (pet.guardianDynamicStatInheritance == nil && pet.isGuardian) || !pet.enabled {
return
}
inheritedChange := pet.currentStatInheritance(addedStats)

inheritedChange := stats.Stats{}
if pet.isGuardian {
inheritedChange = pet.guardianDynamicStatInheritance(addedStats)
} else {
inheritedChange = pet.currentStatInheritance(addedStats)
}

pet.inheritedStats = pet.inheritedStats.Add(inheritedChange)
pet.AddStatsDynamic(sim, inheritedChange)
}
Expand Down
60 changes: 57 additions & 3 deletions sim/core/rage.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"github.com/wowsims/wotlk/sim/core/proto"
"github.com/wowsims/wotlk/sim/core/stats"
)

const MaxRage = 100.0
Expand Down Expand Up @@ -80,10 +81,16 @@ func (unit *Unit) EnableRageBar(options RageBarOptions, onRageGain OnRageGain) {

generatedRage *= options.RageMultiplier

if spell.ResourceMetrics == nil {
spell.ResourceMetrics = spell.Unit.NewRageMetrics(spell.ActionID)
var metrics *ResourceMetrics
if spell.Cost != nil {
metrics = spell.Cost.(*RageCost).ResourceMetrics
} else {
if spell.ResourceMetrics == nil {
spell.ResourceMetrics = spell.Unit.NewRageMetrics(spell.ActionID)
}
metrics = spell.ResourceMetrics
}
unit.AddRage(sim, generatedRage, spell.ResourceMetrics)
unit.AddRage(sim, generatedRage, metrics)
},
OnSpellHitTaken: func(aura *Aura, sim *Simulation, spell *Spell, result *SpellResult) {
if unit.GetCurrentPowerBar() != RageBar {
Expand Down Expand Up @@ -187,3 +194,50 @@ func (rb *rageBar) doneIteration() {
rageGainSpell.ApplyAOEThreatIgnoreMultipliers(resourceMetrics.ActualGainForCurrentIteration() * ThreatPerRageGained)
}
}

type RageCostOptions struct {
Cost float64

Refund float64
RefundMetrics *ResourceMetrics // Optional, will default to unit.RageRefundMetrics if not supplied.
}
type RageCost struct {
Refund float64
RefundMetrics *ResourceMetrics
ResourceMetrics *ResourceMetrics
}

func newRageCost(spell *Spell, options RageCostOptions) *RageCost {
spell.ResourceType = stats.Rage
spell.BaseCost = options.Cost
spell.DefaultCast.Cost = options.Cost
if options.Refund > 0 && options.RefundMetrics == nil {
options.RefundMetrics = spell.Unit.RageRefundMetrics
}

return &RageCost{
Refund: options.Refund * options.Cost,
RefundMetrics: options.RefundMetrics,
ResourceMetrics: spell.Unit.NewRageMetrics(spell.ActionID),
}
}

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) SpendCost(sim *Simulation, spell *Spell) {
if spell.CurCast.Cost > 0 {
spell.Unit.SpendRage(sim, spell.CurCast.Cost, rc.ResourceMetrics)
}
}
func (rc *RageCost) IssueRefund(sim *Simulation, spell *Spell) {
if rc.Refund > 0 {
spell.Unit.AddRage(sim, rc.Refund, rc.RefundMetrics)
}
}
Loading

0 comments on commit f2abeb6

Please sign in to comment.