1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-16 09:25:57 -05:00
OpenDiablo2/d2core/d2stats/diablo2stats/statlist.go
lord 9e61079e93
Stats refactor (#617)
* add interface for stats, d2 is an implementation

* fix incorrect comment, remove ennecessary int

* simplified description functions, remove duplicates

* moved default stringer functions

* fixed incorrect stat combine method

* change `Create` to `New` in method names

* d2stats + diablo2stats refactored again

- simplified `NewStat` provider function
- added initializer for stat values that sets the stringer functions, value types, and combination types for values when created
- removed redundant description functions
- added stat value combination types `sum` and `static`

`static` stat values which are not altered when stats are combined. this makes sense for stats like proc-on-hit or +skills to class

example:
	Stat A: `10% reanimate as: skeleton mage`
	Stat B: `8% reanimate as: skeleton archer`
	Stat C: `6% reanimate as: skeleton archer`

	A and B can not be combined
	B and C can be combined to `14% reanimate as: skeleton archer`
2020-07-23 22:12:48 -04:00

121 lines
2.8 KiB
Go

package diablo2stats
import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2stats"
)
// static check that diablo2Stat implements Stat
var _ d2stats.StatList = &Diablo2StatList{}
// Diablo2StatList is a diablo 2 implementation of a stat list
type Diablo2StatList struct {
stats []d2stats.Stat
}
// Index returns a stat given with the given index
func (sl *Diablo2StatList) Index(idx int) d2stats.Stat {
if idx < 0 || idx > len(sl.stats) {
return nil
}
return sl.stats[idx]
}
// Stats returns a slice of stats
func (sl *Diablo2StatList) Stats() []d2stats.Stat {
return sl.stats
}
// SetStats sets the stats, given a slice of stats
func (sl *Diablo2StatList) SetStats(stats []d2stats.Stat) d2stats.StatList {
sl.stats = stats
return sl
}
// Pop removes the last stat from the stat list
func (sl *Diablo2StatList) Pop() d2stats.Stat {
num := len(sl.stats)
if num < 1 {
return nil
}
idx := num - 1
last := sl.stats[idx]
sl.stats = sl.stats[:idx]
return last
}
// Push adds a stat at the end of the stat list
func (sl *Diablo2StatList) Push(stat d2stats.Stat) d2stats.StatList {
sl.stats = append(sl.stats, stat)
return sl
}
// Clone returns a deep copy of the stat list
func (sl *Diablo2StatList) Clone() d2stats.StatList {
clone := &Diablo2StatList{}
clone.stats = make([]d2stats.Stat, len(sl.stats))
for idx := range sl.stats {
if stat := sl.Index(idx); stat != nil {
clone.stats[idx] = stat.Clone()
}
}
return clone
}
// ReduceStats combines like stats (does not alter this stat list, returns clone)
func (sl *Diablo2StatList) ReduceStats() d2stats.StatList {
clone := sl.Clone()
reduction := make([]d2stats.Stat, 0)
// for quick lookups
lookup := make(map[string]int)
for len(clone.Stats()) > 0 {
stat := clone.Pop()
// if we find it in the lookup, immediately try to combine
// if it doesn't combine, we append to the reduction
if idx, found := lookup[stat.Name()]; found {
if result, err := reduction[idx].Combine(stat); err == nil {
reduction[idx] = result
continue
}
}
// we didnt find it in the lookup, so we will try to combine with other stats
for idx := range reduction {
if _, err := reduction[idx].Combine(stat); err == nil {
continue
}
}
lookup[stat.Name()] = len(lookup)
reduction = append(reduction, stat)
}
return clone.SetStats(reduction)
}
// RemoveStatAtIndex removes the stat from the stat list, returns the stat
func (sl *Diablo2StatList) RemoveStatAtIndex(idx int) d2stats.Stat {
picked := sl.stats[idx]
sl.stats[idx] = sl.stats[len(sl.stats)-1]
sl.stats[len(sl.stats)-1] = nil
sl.stats = sl.stats[:len(sl.stats)-1]
return picked
}
// AppendStatList adds the stats from the other stat list to this stat list
func (sl *Diablo2StatList) AppendStatList(other d2stats.StatList) d2stats.StatList {
sl.stats = append(sl.stats, other.Stats()...)
return sl
}