Skip to content

Commit

Permalink
Merge pull request #3682 from vigo2/vigo/pet-stuff
Browse files Browse the repository at this point in the history
Vigo/pet stuff
  • Loading branch information
vigo2 authored Sep 16, 2023
2 parents e465c5a + 8a4d713 commit a03e60d
Show file tree
Hide file tree
Showing 22 changed files with 503 additions and 546 deletions.
16 changes: 4 additions & 12 deletions sim/common/wotlk/nibelung.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,9 @@ type ValkyrPet struct {

func newValkyr(character *core.Character) *ValkyrPet {
return &ValkyrPet{
Pet: core.NewPet(
"Valkyr",
character,
valkyrStats,
func(ownerStats stats.Stats) stats.Stats {
return stats.Stats{}
},
nil,
false,
true,
),
Pet: core.NewPet("Valkyr", character, valkyrStats, func(ownerStats stats.Stats) stats.Stats {
return stats.Stats{}
}, false, true),
}
}

Expand Down Expand Up @@ -77,7 +69,7 @@ func (valkyr *ValkyrPet) registerSmite(isHeroic bool) {

func (valkyr *ValkyrPet) Initialize() {}

func (valkyr *ValkyrPet) Reset(sim *core.Simulation) {}
func (valkyr *ValkyrPet) Reset(_ *core.Simulation) {}

func (valkyr *ValkyrPet) OnGCDReady(sim *core.Simulation) {
target := valkyr.CurrentTarget
Expand Down
3 changes: 2 additions & 1 deletion sim/core/aura.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"fmt"
"golang.org/x/exp/constraints"
"math"
"strconv"
"time"
Expand Down Expand Up @@ -749,7 +750,7 @@ func (aura *Aura) Deactivate(sim *Simulation) {
}

// Constant-time removal from slice by swapping with the last element before removing.
func removeBySwappingToBack(arr []*Aura, removeIdx int32) []*Aura {
func removeBySwappingToBack[T any, U constraints.Integer](arr []T, removeIdx U) []T {
arr[removeIdx] = arr[len(arr)-1]
return arr[:len(arr)-1]
}
Expand Down
12 changes: 0 additions & 12 deletions sim/core/character.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,26 +347,14 @@ func (character *Character) AddPet(pet PetAgent) {

func (character *Character) MultiplyMeleeSpeed(sim *Simulation, amount float64) {
character.Unit.MultiplyMeleeSpeed(sim, amount)

for _, petAgent := range character.PetAgents {
petAgent.OwnerAttackSpeedChanged(sim)
}
}

func (character *Character) MultiplyRangedSpeed(sim *Simulation, amount float64) {
character.Unit.MultiplyRangedSpeed(sim, amount)

for _, petAgent := range character.PetAgents {
petAgent.OwnerAttackSpeedChanged(sim)
}
}

func (character *Character) MultiplyAttackSpeed(sim *Simulation, amount float64) {
character.Unit.MultiplyAttackSpeed(sim, amount)

for _, petAgent := range character.PetAgents {
petAgent.OwnerAttackSpeedChanged(sim)
}
}

func (character *Character) GetBaseStats() stats.Stats {
Expand Down
121 changes: 67 additions & 54 deletions sim/core/pet.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package core

import (
"fmt"
"time"

"github.com/wowsims/wotlk/sim/core/proto"
"github.com/wowsims/wotlk/sim/core/stats"
"golang.org/x/exp/slices"
"time"
)

// Extension of Agent interface, for Pets.
Expand All @@ -14,12 +14,13 @@ type PetAgent interface {

// The Pet controlled by this PetAgent.
GetPet() *Pet
OwnerAttackSpeedChanged(sim *Simulation)
}

type OnPetEnable func(sim *Simulation)
type OnPetDisable func(sim *Simulation)

type PetStatInheritance func(ownerStats stats.Stats) stats.Stats
type PetMeleeSpeedInheritance func(amount float64)

// Pet is an extension of Character, for any entity created by a player that can
// take actions on its own.
Expand All @@ -35,12 +36,12 @@ type Pet struct {
OnPetDisable OnPetDisable

// Calculates inherited stats based on owner stats or stat changes.
statInheritance PetStatInheritance
statInheritance PetStatInheritance
dynamicStatInheritance PetStatInheritance
inheritedStats stats.Stats

// No-op until finalized to prevent owner stats from affecting pet until we're ready.
currentStatInheritance PetStatInheritance
inheritedStats stats.Stats
guardianDynamicStatInheritance PetStatInheritance
// DK pets also inherit their owner's MeleeSpeed. This replace OwnerAttackSpeedChanged.
dynamicMeleeSpeedInheritance PetMeleeSpeedInheritance

isReset bool

Expand All @@ -49,7 +50,7 @@ type Pet struct {
timeoutAction *PendingAction
}

func NewPet(name string, owner *Character, baseStats stats.Stats, statInheritance PetStatInheritance, guardianDynamicStatInheritance PetStatInheritance, enabledOnStart bool, isGuardian bool) Pet {
func NewPet(name string, owner *Character, baseStats stats.Stats, statInheritance PetStatInheritance, enabledOnStart bool, isGuardian bool) Pet {
pet := Pet{
Character: Character{
Unit: Unit{
Expand All @@ -68,16 +69,12 @@ func NewPet(name string, owner *Character, baseStats stats.Stats, statInheritanc
PartyIndex: owner.PartyIndex,
baseStats: baseStats,
},
Owner: owner,
statInheritance: statInheritance,
guardianDynamicStatInheritance: guardianDynamicStatInheritance,
enabledOnStart: enabledOnStart,
isGuardian: isGuardian,
Owner: owner,
statInheritance: statInheritance,
enabledOnStart: enabledOnStart,
isGuardian: isGuardian,
}
pet.GCD = pet.NewTimer()
pet.currentStatInheritance = func(ownerStats stats.Stats) stats.Stats {
return stats.Stats{}
}

pet.AddStats(baseStats)
pet.addUniversalStatDependencies()
Expand All @@ -86,38 +83,22 @@ func NewPet(name string, owner *Character, baseStats stats.Stats, statInheritanc
return pet
}

// Add a default base if pets don't need this
func (pet *Pet) OwnerAttackSpeedChanged(_ *Simulation) {}

// Updates the stats for this pet in response to a stat change on the owner.
// 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) {
// Only gargoyle is a guardian that inherits haste dynamically
if (pet.guardianDynamicStatInheritance == nil && pet.isGuardian) || !pet.enabled {
return
}

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

pet.inheritedStats = pet.inheritedStats.Add(inheritedChange)
pet.inheritedStats.AddInplace(&inheritedChange)
pet.AddStatsDynamic(sim, inheritedChange)
}

func (pet *Pet) Finalize() {
pet.Character.Finalize()
}

func (pet *Pet) reset(sim *Simulation, agent PetAgent) {
if pet.isReset {
return
}
pet.isReset = true

pet.Character.reset(sim, agent)

pet.CancelGCDTimer(sim)
Expand All @@ -131,6 +112,7 @@ func (pet *Pet) reset(sim *Simulation, agent PetAgent) {
func (pet *Pet) advance(sim *Simulation) {
pet.Character.advance(sim)
}

func (pet *Pet) doneIteration(sim *Simulation) {
pet.Character.doneIteration(sim)
pet.isReset = false
Expand All @@ -157,7 +139,11 @@ func (pet *Pet) Enable(sim *Simulation, petAgent PetAgent) {

pet.inheritedStats = pet.statInheritance(pet.Owner.GetStats())
pet.AddStatsDynamic(sim, pet.inheritedStats)
pet.currentStatInheritance = pet.statInheritance

if !pet.isGuardian {
pet.Owner.DynamicStatsPets = append(pet.Owner.DynamicStatsPets, pet)
pet.dynamicStatInheritance = pet.statInheritance
}

//reset current mana after applying stats
pet.manaBar.reset()
Expand Down Expand Up @@ -186,6 +172,36 @@ func (pet *Pet) Enable(sim *Simulation, petAgent PetAgent) {
pet.Log(sim, "Pet summoned")
}
}

// Helper for enabling a pet that will expire after a certain duration.
func (pet *Pet) EnableWithTimeout(sim *Simulation, petAgent PetAgent, petDuration time.Duration) {
pet.Enable(sim, petAgent)

pet.timeoutAction = &PendingAction{
NextActionAt: sim.CurrentTime + petDuration,
OnAction: func(sim *Simulation) {
pet.Disable(sim)
},
}
sim.AddPendingAction(pet.timeoutAction)
}

// Enables and possibly updates how the pet inherits its owner's stats. DK use only.
func (pet *Pet) EnableDynamicStats(inheritance PetStatInheritance) {
if !slices.Contains(pet.Owner.DynamicStatsPets, pet) {
pet.Owner.DynamicStatsPets = append(pet.Owner.DynamicStatsPets, pet)
}
pet.dynamicStatInheritance = inheritance
}

// Enables and possibly updates how the pet inherits its owner's melee speed. DK use only.
func (pet *Pet) EnableDynamicMeleeSpeed(inheritance PetMeleeSpeedInheritance) {
if !slices.Contains(pet.Owner.DynamicMeleeSpeedPets, pet) {
pet.Owner.DynamicMeleeSpeedPets = append(pet.Owner.DynamicMeleeSpeedPets, pet)
}
pet.dynamicMeleeSpeedInheritance = inheritance
}

func (pet *Pet) Disable(sim *Simulation) {
if !pet.enabled {
if sim.Log != nil {
Expand All @@ -198,9 +214,20 @@ func (pet *Pet) Disable(sim *Simulation) {
if pet.isGuardian || pet.timeoutAction != nil {
pet.AddStatsDynamic(sim, pet.inheritedStats.Multiply(-1))
pet.inheritedStats = stats.Stats{}
pet.currentStatInheritance = func(ownerStats stats.Stats) stats.Stats {
return stats.Stats{}
}

if pet.dynamicStatInheritance != nil {
if idx := slices.Index(pet.Owner.DynamicStatsPets, pet); idx != -1 {
pet.Owner.DynamicStatsPets = removeBySwappingToBack(pet.Owner.DynamicStatsPets, idx)
}
pet.dynamicStatInheritance = nil
}

if pet.dynamicMeleeSpeedInheritance != nil {
if idx := slices.Index(pet.Owner.DynamicMeleeSpeedPets, pet); idx != -1 {
pet.Owner.DynamicMeleeSpeedPets = removeBySwappingToBack(pet.Owner.DynamicMeleeSpeedPets, idx)
}
pet.dynamicMeleeSpeedInheritance = nil
}

pet.CancelGCDTimer(sim)
Expand All @@ -209,8 +236,7 @@ func (pet *Pet) Disable(sim *Simulation) {
pet.enabled = false
pet.DoNothing() // mark it is as doing nothing now.

// If a pet is immediately re-summoned it might try to use GCD, so we need to
// clear it.
// If a pet is immediately re-summoned it might try to use GCD, so we need to clear it.
pet.Hardcast = Hardcast{}

if pet.timeoutAction != nil {
Expand All @@ -231,19 +257,6 @@ func (pet *Pet) Disable(sim *Simulation) {
}
}

// Helper for enabling a pet that will expire after a certain duration.
func (pet *Pet) EnableWithTimeout(sim *Simulation, petAgent PetAgent, petDuration time.Duration) {
pet.Enable(sim, petAgent)

pet.timeoutAction = &PendingAction{
NextActionAt: sim.CurrentTime + petDuration,
OnAction: func(sim *Simulation) {
pet.Disable(sim)
},
}
sim.AddPendingAction(pet.timeoutAction)
}

// Default implementations for some Agent functions which most Pets don't need.
func (pet *Pet) GetCharacter() *Character {
return &pet.Character
Expand Down
5 changes: 2 additions & 3 deletions sim/core/spell_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,8 @@ func (spell *Spell) attackerDamageMultiplierInternal(attackTable *AttackTable) f
return 1
}

ps := spell.Unit.PseudoStats
return ps.DamageDealtMultiplier *
ps.SchoolDamageDealtMultiplier[spell.SchoolIndex] *
return spell.Unit.PseudoStats.DamageDealtMultiplier *
spell.Unit.PseudoStats.SchoolDamageDealtMultiplier[spell.SchoolIndex] *
attackTable.DamageDealtMultiplier
}

Expand Down
21 changes: 15 additions & 6 deletions sim/core/stats/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,13 @@ func (stats Stats) Add(other Stats) Stats {
return newStats
}

// Adds another to Stats to this, in-place.
func (stats *Stats) AddInplace(other *Stats) {
for k := range stats {
stats[k] += other[k]
}
}

// Subtracts another Stats from this one, returning the new Stats.
func (stats Stats) Subtract(other Stats) Stats {
var newStats Stats
Expand Down Expand Up @@ -247,11 +254,12 @@ func (stats Stats) String() string {
sb.WriteString("\n{\n")

for statIdx, statValue := range stats {
name := Stat(statIdx).StatName()
if name == "none" || statValue == 0 {
if statValue == 0 {
continue
}
_, _ = fmt.Fprintf(&sb, "\t%s: %0.3f,\n", name, statValue)
if name := Stat(statIdx).StatName(); name != "none" {
_, _ = fmt.Fprintf(&sb, "\t%s: %0.3f,\n", name, statValue)
}
}

sb.WriteString("\n}")
Expand All @@ -264,11 +272,12 @@ func (stats Stats) FlatString() string {
sb.WriteString("{")

for statIdx, statValue := range stats {
name := Stat(statIdx).StatName()
if name == "none" || statValue == 0 {
if statValue == 0 {
continue
}
_, _ = fmt.Fprintf(&sb, "\"%s\": %0.3f,", name, statValue)
if name := Stat(statIdx).StatName(); name != "none" {
_, _ = fmt.Fprintf(&sb, "\"%s\": %0.3f,", name, statValue)
}
}

sb.WriteString("}")
Expand Down
Loading

0 comments on commit a03e60d

Please sign in to comment.