Skip to content

Commit

Permalink
Optimise item set logic
Browse files Browse the repository at this point in the history
  • Loading branch information
1337LutZ committed Jan 9, 2025
1 parent cf7b51d commit bd710cf
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 111 deletions.
2 changes: 1 addition & 1 deletion sim/common/shared/shared_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func factory_StatBonusEffect(config ProcStatBonusEffect, extraSpell func(agent c
if isEnchant {
dpm = character.AutoAttacks.NewDynamicProcManagerForEnchant(effectID, config.PPM, 0)
} else {
dpm = character.AutoAttacks.NewPPMManagerForWeaponEffect(effectID, config.PPM)
dpm = character.AutoAttacks.NewDynamicProcManagerForWeaponEffect(effectID, config.PPM, 0)
}
}

Expand Down
7 changes: 4 additions & 3 deletions sim/common/tbc/enchant_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func init() {
} else {
label += "OH"
}
dpm := character.AutoAttacks.NewPPMManagerForWeaponEffect(3273, 2.15)
dpm := character.AutoAttacks.NewDynamicProcManagerForWeaponEffect(3273, 2.15, 0)

aura := character.GetOrRegisterAura(core.Aura{
Label: label,
Expand All @@ -191,7 +191,7 @@ func init() {
return
}

if spell.ProcMask.Matches(core.ProcMaskMelee) {
if spell.ProcMask.Matches(core.Ternary(isMH, core.ProcMaskMeleeMH, core.ProcMaskMeleeOH)) {
if dpm.Proc(sim, spell.ProcMask, "Deathfrost") {
procSpell.Cast(sim, result.Target)
}
Expand All @@ -204,7 +204,8 @@ func init() {
},
})

character.ItemSwap.RegisterEnchantProc(3273, aura, core.MeleeWeaponSlots())
meleeWeaponSlots := core.MeleeWeaponSlots()
character.ItemSwap.RegisterEnchantProc(3273, aura, core.Ternary(isMH, meleeWeaponSlots[:1], meleeWeaponSlots[1:]))
}

core.NewEnchantEffect(3273, func(agent core.Agent) {
Expand Down
6 changes: 3 additions & 3 deletions sim/common/tbc/melee_items.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func init() {
core.NewItemEffect(19019, func(agent core.Agent) {
character := agent.GetCharacter()

dpm := character.AutoAttacks.NewPPMManagerForWeaponEffect(19019, 6.0)
dpm := character.AutoAttacks.NewDynamicProcManagerForWeaponEffect(19019, 6.0, 0)

procActionID := core.ActionID{SpellID: 21992}

Expand Down Expand Up @@ -173,7 +173,7 @@ func init() {
core.NewItemEffect(29996, func(agent core.Agent) {
character := agent.GetCharacter()

dpm := character.AutoAttacks.NewPPMManagerForWeaponEffect(29996, 1.0)
dpm := character.AutoAttacks.NewDynamicProcManagerForWeaponEffect(29996, 1.0, 0)

actionID := core.ActionID{ItemID: 29996}

Expand Down Expand Up @@ -351,7 +351,7 @@ func init() {
core.NewItemEffect(12590, func(agent core.Agent) {
character := agent.GetCharacter()

dpm := character.AutoAttacks.NewPPMManagerForWeaponEffect(12590, 1.0)
dpm := character.AutoAttacks.NewDynamicProcManagerForWeaponEffect(12590, 1.0, 0)

effectAura := character.NewTemporaryStatsAura("Felstriker Proc", core.ActionID{SpellID: 16551}, stats.Stats{stats.PhysicalCritPercent: 100}, time.Second*3)

Expand Down
2 changes: 1 addition & 1 deletion sim/common/wotlk/other_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,7 @@ func init() {
core.NewItemEffect(itemID, func(agent core.Agent) {
character := agent.GetCharacter()

dpm := character.AutoAttacks.NewPPMManagerForWeaponEffect(itemID, 2.0)
dpm := character.AutoAttacks.NewDynamicProcManagerForWeaponEffect(itemID, 2.0, 0)

procActionID := core.ActionID{ItemID: itemID}

Expand Down
52 changes: 12 additions & 40 deletions sim/core/attack.go
Original file line number Diff line number Diff line change
Expand Up @@ -840,55 +840,27 @@ func (aa *AutoAttacks) NewPPMManager(ppm float64, procMask ProcMask) *DynamicPro
return &dpm
}

// PPMManager for dynamic ProcMasks on weapon enchants
// Dynamic Proc Manager for dynamic ProcMasks on weapon enchants
func (aa *AutoAttacks) NewDynamicProcManagerForEnchant(effectID int32, ppm float64, fixedProcChance float64) *DynamicProcManager {
getProcMask := func() ProcMask {
return aa.character.getDefaultProcMaskForWeaponEnchant(effectID)
}

dpm := aa.newDynamicProcManager(ppm, fixedProcChance, getProcMask())

if aa.character != nil {
aa.character.RegisterItemSwapCallback(AllWeaponSlots(), func(sim *Simulation, slot proto.ItemSlot) {
procMask := aa.character.getDefaultProcMaskForWeaponEnchant(effectID)
dpm = aa.character.AutoAttacks.newDynamicProcManager(ppm, fixedProcChance, procMask)
})
}

return &dpm
}

// PPMManager for dynamic ProcMasks on weapon effects
func (aa *AutoAttacks) NewPPMManagerForWeaponEffect(itemID int32, ppm float64) *DynamicProcManager {
getProcMask := func() ProcMask {
return aa.character.getDefaultProcMaskForWeaponEffect(itemID)
}

dpm := aa.newDynamicProcManager(ppm, 0, getProcMask())

if aa.character != nil {
if aa.character != nil {
aa.character.RegisterItemSwapCallback(AllWeaponSlots(), func(sim *Simulation, slot proto.ItemSlot) {
dpm = aa.character.AutoAttacks.newDynamicProcManager(ppm, 0, getProcMask())
})
}
}

return &dpm
return aa.newDynamicProcManagerWithDynamicProcMask(ppm, fixedProcChance, func() ProcMask {
return aa.character.getCurrentProcMaskForWeaponEnchant(effectID)
})
}

// PPMManager for dynamic ProcMasks on weapon effects
// Dynamic Proc Manager for dynamic ProcMasks on weapon effects
func (aa *AutoAttacks) NewDynamicProcManagerForWeaponEffect(itemID int32, ppm float64, fixedProcChance float64) *DynamicProcManager {
getProcMask := func() ProcMask {
return aa.character.getDefaultProcMaskForWeaponEffect(itemID)
}
return aa.newDynamicProcManagerWithDynamicProcMask(ppm, fixedProcChance, func() ProcMask {
return aa.character.getCurrentProcMaskForWeaponEffect(itemID)
})
}

dpm := aa.newDynamicProcManager(ppm, fixedProcChance, getProcMask())
func (aa *AutoAttacks) newDynamicProcManagerWithDynamicProcMask(ppm float64, fixedProcChance float64, procMaskFn func() ProcMask) *DynamicProcManager {
dpm := aa.newDynamicProcManager(ppm, fixedProcChance, procMaskFn())

if aa.character != nil {
if aa.character != nil {
aa.character.RegisterItemSwapCallback(AllWeaponSlots(), func(sim *Simulation, slot proto.ItemSlot) {
dpm = aa.character.AutoAttacks.newDynamicProcManager(ppm, fixedProcChance, getProcMask())
dpm = aa.character.AutoAttacks.newDynamicProcManager(ppm, fixedProcChance, procMaskFn())
})
}
}
Expand Down
38 changes: 16 additions & 22 deletions sim/core/character.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,58 +599,52 @@ func (character *Character) HasRangedWeapon() bool {
}

func (character *Character) GetDynamicProcMaskForWeaponEnchant(effectID int32) *ProcMask {
getProcMask := func() ProcMask {
return character.getDefaultProcMaskForWeaponEnchant(effectID)
}
return character.getDynamicProcMaskPointer(func() ProcMask {
return character.getCurrentProcMaskForWeaponEnchant(effectID)
})
}

procMask := getProcMask()
func (character *Character) getDynamicProcMaskPointer(procMaskFn func() ProcMask) *ProcMask {
procMask := procMaskFn()

character.RegisterItemSwapCallback(AllWeaponSlots(), func(sim *Simulation, slot proto.ItemSlot) {
procMask = getProcMask()
procMask = procMaskFn()
})

return &procMask
}

func (character *Character) getDefaultProcMaskForWeaponEnchant(effectID int32) ProcMask {
return character.getDefaultProcMaskFor(func(weapon *Item) bool {
func (character *Character) getCurrentProcMaskForWeaponEnchant(effectID int32) ProcMask {
return character.getCurrentProcMaskFor(func(weapon *Item) bool {
return weapon.Enchant.EffectID == effectID
})
}

func (character *Character) GetDynamicProcMaskForWeaponEffect(itemID int32) *ProcMask {
getProcMask := func() ProcMask {
return character.getDefaultProcMaskForWeaponEffect(itemID)
}

procMask := getProcMask()

character.RegisterItemSwapCallback(AllWeaponSlots(), func(sim *Simulation, slot proto.ItemSlot) {
procMask = getProcMask()
return character.getDynamicProcMaskPointer(func() ProcMask {
return character.getCurrentProcMaskForWeaponEffect(itemID)
})

return &procMask
}

func (character *Character) getDefaultProcMaskForWeaponEffect(itemID int32) ProcMask {
return character.getDefaultProcMaskFor(func(weapon *Item) bool {
func (character *Character) getCurrentProcMaskForWeaponEffect(itemID int32) ProcMask {
return character.getCurrentProcMaskFor(func(weapon *Item) bool {
return weapon.ID == itemID
})
}

func (character *Character) GetProcMaskForTypes(weaponTypes ...proto.WeaponType) ProcMask {
return character.getDefaultProcMaskFor(func(weapon *Item) bool {
return character.getCurrentProcMaskFor(func(weapon *Item) bool {
return weapon != nil && slices.Contains(weaponTypes, weapon.WeaponType)
})
}

func (character *Character) GetProcMaskForTypesAndHand(twohand bool, weaponTypes ...proto.WeaponType) ProcMask {
return character.getDefaultProcMaskFor(func(weapon *Item) bool {
return character.getCurrentProcMaskFor(func(weapon *Item) bool {
return weapon != nil && (weapon.HandType == proto.HandType_HandTypeTwoHand) == twohand && slices.Contains(weaponTypes, weapon.WeaponType)
})
}

func (character *Character) getDefaultProcMaskFor(pred func(item *Item) bool) ProcMask {
func (character *Character) getCurrentProcMaskFor(pred func(item *Item) bool) ProcMask {
mask := ProcMaskUnknown

if character == nil {
Expand Down
89 changes: 50 additions & 39 deletions sim/core/item_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,45 +101,21 @@ func (character *Character) HasSetBonus(set *ItemSet, numItems int32) bool {
panic(fmt.Sprintf("Item set %s does not have a bonus with %d pieces.", set.Name, numItems))
}

activeSetBonus := character.HasActiveSetBonus(set.Name, numItems)
if activeSetBonus {
return activeSetBonus
if character.hasActiveSetBonus(set.Name, numItems) {
return true
}

if character.ItemSwap.IsEnabled() {
unequippedSetBonuses := character.GetSetBonuses(character.ItemSwap.unEquippedItems)
for _, unequippedSetBonus := range unequippedSetBonuses {
if unequippedSetBonus.Name == set.Name && unequippedSetBonus.NumPieces >= numItems {
return true
}
}
return character.hasUnequippedSetBonus(set.Name, numItems)
}

return false
}

type SetBonus struct {
// Name of the set.
Name string

// Number of pieces required for this bonus.
NumPieces int32

// Function for applying the effects of this set bonus.
BonusEffect ApplySetBonus

// Optional field to override the DefaultItemSetSlots
// For Example: The set contains of 2 weapons
Slots []proto.ItemSlot
}

// Returns a list describing all active set bonuses.
func (character *Character) GetActiveSetBonuses() []SetBonus {
return character.GetSetBonuses(character.Equipment)
}
type SetBonusCollection []SetBonus

func (character *Character) GetSetBonuses(equipment Equipment) []SetBonus {
var activeBonuses []SetBonus
func (equipment Equipment) getSetBonuses() SetBonusCollection {
var activeBonuses SetBonusCollection

setItemCount := make(map[*ItemSet]int32)
for _, item := range equipment {
Expand Down Expand Up @@ -184,19 +160,51 @@ func (character *Character) GetSetBonuses(equipment Equipment) []SetBonus {
return activeBonuses
}

// Checks whether the character has an equipped set bonus
func (character *Character) HasActiveSetBonus(setName string, count int32) bool {
activeSetBonuses := character.GetActiveSetBonuses()

for _, activeSetBonus := range activeSetBonuses {
if activeSetBonus.Name == setName && activeSetBonus.NumPieces >= count {
func (collection SetBonusCollection) ContainsBonus(setName string, count int32) bool {
for _, bonus := range collection {
if (bonus.Name == setName) && (bonus.NumPieces >= count) {
return true
}
}

return false
}

// Returns a list describing all active set bonuses.
func (character *Character) GetActiveSetBonuses() SetBonusCollection {
return character.Equipment.getSetBonuses()
}

func (character *Character) getUnequippedSetBonuses() SetBonusCollection {
return character.ItemSwap.unEquippedItems.getSetBonuses()
}

func (character *Character) hasUnequippedSetBonus(setName string, count int32) bool {
unequippedSetBonuses := character.getUnequippedSetBonuses()
return unequippedSetBonuses.ContainsBonus(setName, count)
}

type SetBonus struct {
// Name of the set.
Name string

// Number of pieces required for this bonus.
NumPieces int32

// Function for applying the effects of this set bonus.
BonusEffect ApplySetBonus

// Optional field to override the DefaultItemSetSlots
// For Example: The set contains of 2 weapons
Slots []proto.ItemSlot
}

// Checks whether the character has an equipped set bonus
func (character *Character) hasActiveSetBonus(setName string, count int32) bool {
activeSetBonuses := character.GetActiveSetBonuses()
return activeSetBonuses.ContainsBonus(setName, count)
}

// Apply effects from item set bonuses.
func (character *Character) applyItemSetBonusEffects(agent Agent) {
activeSetBonuses := character.GetActiveSetBonuses()
Expand All @@ -207,11 +215,14 @@ func (character *Character) applyItemSetBonusEffects(agent Agent) {
}

if character.ItemSwap.IsEnabled() {
unequippedSetBonuses := FilterSlice(character.GetSetBonuses(character.ItemSwap.unEquippedItems), func(unequippedBonus SetBonus) bool {
return !character.HasActiveSetBonus(unequippedBonus.Name, unequippedBonus.NumPieces)
unequippedSetBonuses := FilterSlice(character.ItemSwap.unEquippedItems.getSetBonuses(), func(unequippedBonus SetBonus) bool {
return !character.hasActiveSetBonus(unequippedBonus.Name, unequippedBonus.NumPieces)
})

for _, unequippedSetBonus := range unequippedSetBonuses {
if activeSetBonuses.ContainsBonus(unequippedSetBonus.Name, unequippedSetBonus.NumPieces) {
continue
}
setBonusAura := character.makeSetBonusStatusAura(unequippedSetBonus.Name, unequippedSetBonus.NumPieces, unequippedSetBonus.Slots, false)
unequippedSetBonus.BonusEffect(agent, setBonusAura)
}
Expand All @@ -231,7 +242,7 @@ func (character *Character) makeSetBonusStatusAura(setName string, numPieces int

if character.ItemSwap.IsEnabled() {
character.RegisterItemSwapCallback(slots, func(sim *Simulation, _ proto.ItemSlot) {
if character.HasActiveSetBonus(setName, numPieces) {
if character.hasActiveSetBonus(setName, numPieces) {
statusAura.Activate(sim)
} else {
statusAura.Deactivate(sim)
Expand Down
2 changes: 0 additions & 2 deletions sim/core/item_swaps.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package core

import (
"fmt"
"time"

"github.com/wowsims/cata/sim/core/proto"
Expand Down Expand Up @@ -131,7 +130,6 @@ func (swap *ItemSwap) registerProcInternal(config ItemSwapProcConfig) {

if isItemProc {
isItemSlotMatch = swap.HasEquippedItem(config.ItemID, config.Slots)
fmt.Println("RegisterProc", sim.CurrentTime, config.ItemID, slot)
} else if isEnchantEffectProc {
isItemSlotMatch = swap.HasEquippedEnchant(config.EnchantId, config.Slots)
}
Expand Down

0 comments on commit bd710cf

Please sign in to comment.