Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vigo/item-sets #3630

Merged
merged 6 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30,418 changes: 15,209 additions & 15,209 deletions assets/db_inputs/wago_db2_items.csv

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion assets/db_inputs/wowhead_gearplannerdb.txt

Large diffs are not rendered by default.

12 changes: 4 additions & 8 deletions sim/common/tbc/melee_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,9 @@ var ItemSetStormshroud = core.NewItemSet(core.ItemSet{
if !result.Landed() || !spell.ProcMask.Matches(core.ProcMaskMelee) {
return
}
chance := 0.05
if sim.RandomFloat("Stormshroud Armor 2pc") > chance {
return
if sim.RandomFloat("Stormshroud Armor 2pc") < 0.05 {
proc.Cast(sim, result.Target)
}
proc.Cast(sim, result.Target)
},
})
},
Expand Down Expand Up @@ -113,11 +111,9 @@ var ItemSetStormshroud = core.NewItemSet(core.ItemSet{
if !result.Landed() || !spell.ProcMask.Matches(core.ProcMaskMelee) {
return
}
chance := 0.02
if sim.RandomFloat("Stormshroud Armor 2pc") > chance {
return
if sim.RandomFloat("Stormshroud Armor 3pc") < 0.02 {
proc.Cast(sim, result.Target)
}
proc.Cast(sim, result.Target)
},
})

Expand Down
7 changes: 3 additions & 4 deletions sim/common/wotlk/nibelung.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,10 @@ func MakeNibelungTriggerAura(agent core.Agent, isHeroic bool) {
return
}

for _, pet := range character.PetAgents {
valkyr, ok := pet.(*ValkyrPet)
if ok && !valkyr.IsEnabled() {
for _, petAgent := range character.PetAgents {
if valkyr, ok := petAgent.(*ValkyrPet); ok && !valkyr.IsEnabled() {
valkyr.registerSmite(isHeroic)
valkyr.EnableWithTimeout(sim, pet, valkyrAura.Duration)
valkyr.EnableWithTimeout(sim, petAgent, valkyrAura.Duration)
break
}
}
Expand Down
13 changes: 7 additions & 6 deletions sim/core/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,26 @@ import (

var WITH_DB = false

var ItemsByID = map[int32]Item{}
var GemsByID = map[int32]Gem{}
var EnchantsByEffectID = map[int32]Enchant{}
var ItemsByID map[int32]Item
var GemsByID map[int32]Gem
var EnchantsByEffectID map[int32]Enchant

func addToDatabase(newDB *proto.SimDatabase) {
ItemsByID = make(map[int32]Item, len(newDB.Items))
for _, v := range newDB.Items {
if _, ok := ItemsByID[v.Id]; !ok {
item := ItemFromProto(v)
ItemsByID[v.Id] = item
AddItemToSets(item)
ItemsByID[v.Id] = ItemFromProto(v)
}
}

EnchantsByEffectID = make(map[int32]Enchant, len(newDB.Enchants))
for _, v := range newDB.Enchants {
if _, ok := EnchantsByEffectID[v.EffectId]; !ok {
EnchantsByEffectID[v.EffectId] = EnchantFromProto(v)
}
}

GemsByID = make(map[int32]Gem, len(newDB.Gems))
for _, v := range newDB.Gems {
if _, ok := GemsByID[v.Id]; !ok {
GemsByID[v.Id] = GemFromProto(v)
Expand Down
12 changes: 4 additions & 8 deletions sim/core/item_effects.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/slices"
"strconv"
"time"

Expand All @@ -15,15 +16,15 @@ import (
// but there are occasionally class-specific item effects.
type ApplyEffect func(Agent)

// Function for applying permenent effects to an agent's weapon
// Function for applying permanent effects to an agent's weapon
type ApplyWeaponEffect func(Agent, proto.ItemSlot)

var itemEffects = map[int32]ApplyEffect{}
var weaponEffects = map[int32]ApplyWeaponEffect{}
var enchantEffects = map[int32]ApplyEffect{}

// IDs of item effects which should be used for tests.
var itemEffectsForTest = []int32{}
var itemEffectsForTest []int32

// This value can be set before adding item effects, to control whether they are included in tests.
var AddEffectsToTest = true
Expand All @@ -33,12 +34,7 @@ func HasItemEffect(id int32) bool {
return ok
}
func HasItemEffectForTest(id int32) bool {
for _, itemID := range itemEffectsForTest {
if id == itemID {
return true
}
}
return false
return slices.Contains(itemEffectsForTest, id)
}

func HasWeaponEffect(id int32) bool {
Expand Down
134 changes: 52 additions & 82 deletions sim/core/item_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,65 +9,44 @@ type ItemSet struct {
Name string
AlternativeName string

// IDs of items that are part of this set. map[key]struct{} is roughly a set in go.
Items map[int32]struct{}

// Maps set piece requirement to an ApplyEffect function that will be called
// before the Sim starts.
//
// The function should apply any benefits provided by the set bonus.
Bonuses map[int32]ApplyEffect
}

func (set ItemSet) ItemIDs() []int32 {
ids := make([]int32, 0, len(set.Items))
for id := range set.Items {
ids = append(ids, id)
func (set ItemSet) Items() []Item {
var items []Item
for _, item := range ItemsByID {
if item.SetName == "" {
continue
}
if item.SetName == set.Name || item.SetName == set.AlternativeName {
items = append(items, item)
}
}
// Sort so the order of IDs is always consistent, for tests.
slices.Sort(ids)
return ids
}

func (set ItemSet) ItemIsInSet(itemID int32) bool {
_, ok := set.Items[itemID]
return ok
slices.SortFunc(items, func(a, b Item) bool {
return a.ID < b.ID
})
return items
}

var sets []*ItemSet

func GetAllItemSets() []*ItemSet {
// Defensive copy to prevent modifications.
tmp := make([]*ItemSet, len(sets))
copy(tmp, sets)
return tmp
}

// cache for mapping item to set for fast resetting of sim.
var itemSetLookup = map[int32]*ItemSet{}

// Registers a new ItemSet with item IDs populated.
func NewItemSet(setStruct ItemSet) *ItemSet {
set := &ItemSet{}
*set = setStruct

if len(set.Items) > 0 {
panic(set.Name + " (" + set.AlternativeName + ") supplied item IDs, set items are detected automatically!")
}

set.Items = make(map[int32]struct{})
func NewItemSet(set ItemSet) *ItemSet {
foundName := false
foundAlternativeName := false
foundAlternativeName := set.AlternativeName == ""
for _, item := range ItemsByID {
if item.SetName == set.Name || (len(set.AlternativeName) > 0 && item.SetName == set.AlternativeName) {
//fmt.Printf("Adding item %s-%d to set %s\n", item.Name, item.ID, item.SetName)
set.Items[item.ID] = struct{}{}

if item.SetName == set.Name {
foundName = true
} else {
foundAlternativeName = true
}
if item.SetName == "" {
continue
}
foundName = foundName || item.SetName == set.Name
foundAlternativeName = foundAlternativeName || item.SetName == set.AlternativeName
if foundName && foundAlternativeName {
break
}
}

Expand All @@ -80,38 +59,25 @@ func NewItemSet(setStruct ItemSet) *ItemSet {
}
}

sets = append(sets, set)
for itemID := range set.Items {
itemSetLookup[itemID] = set
}
return set
}

func AddItemToSets(item Item) {
if item.SetName == "" {
return
}

for _, set := range sets {
if set.Name == item.SetName || set.AlternativeName == item.SetName {
set.Items[item.ID] = struct{}{}
itemSetLookup[item.ID] = set
}
}
sets = append(sets, &set)
return &set
}

func (character *Character) HasSetBonus(itemSet *ItemSet, numItems int32) bool {
func (character *Character) HasSetBonus(set *ItemSet, numItems int32) bool {
if character.Env != nil && character.Env.IsFinalized() {
panic("HasSetBonus is very slow and should never be called after finalization. Try caching the value during construction instead!")
}

if _, ok := itemSet.Bonuses[numItems]; !ok {
panic(fmt.Sprintf("Item set %s does not have a bonus with %d pieces.", itemSet.Name, numItems))
if _, ok := set.Bonuses[numItems]; !ok {
panic(fmt.Sprintf("Item set %s does not have a bonus with %d pieces.", set.Name, numItems))
}

var count int32
for _, item := range character.Equipment {
if itemSet.ItemIsInSet(item.ID) {
if item.SetName == "" {
continue
}
if item.SetName == set.Name || item.SetName == set.AlternativeName {
count++
if count >= numItems {
return true
Expand All @@ -135,19 +101,24 @@ type ActiveSetBonus struct {

// Returns a list describing all active set bonuses.
func (character *Character) GetActiveSetBonuses() []ActiveSetBonus {
activeBonuses := []ActiveSetBonus{}
setItemCount := map[string]int32{}

for _, i := range character.Equipment {
set := itemSetLookup[i.ID]
if set != nil {
setItemCount[set.Name]++
if setBonusFunc, ok := set.Bonuses[setItemCount[set.Name]]; ok {
activeBonuses = append(activeBonuses, ActiveSetBonus{
Name: set.Name,
NumPieces: setItemCount[set.Name],
BonusEffect: setBonusFunc,
})
var activeBonuses []ActiveSetBonus

setItemCount := make(map[*ItemSet]int32)
for _, item := range character.Equipment {
if item.SetName == "" {
continue
}
for _, set := range sets {
if set.Name == item.SetName || set.AlternativeName == item.SetName {
setItemCount[set]++
if bonusEffect, ok := set.Bonuses[setItemCount[set]]; ok {
activeBonuses = append(activeBonuses, ActiveSetBonus{
Name: set.Name,
NumPieces: setItemCount[set],
BonusEffect: bonusEffect,
})
}
break
}
}
}
Expand All @@ -167,11 +138,10 @@ func (character *Character) applyItemSetBonusEffects(agent Agent) {
// Returns the names of all active set bonuses.
func (character *Character) GetActiveSetBonusNames() []string {
activeSetBonuses := character.GetActiveSetBonuses()
names := []string{}

for _, activeSetBonus := range activeSetBonuses {
names = append(names, fmt.Sprintf("%s (%dpc)", activeSetBonus.Name, activeSetBonus.NumPieces))
names := make([]string, len(activeSetBonuses))
for i, activeSetBonus := range activeSetBonuses {
names[i] = fmt.Sprintf("%s (%dpc)", activeSetBonus.Name, activeSetBonus.NumPieces)
}

return names
}
Loading
Loading