物品容器基本实现
This commit is contained in:
parent
eb31ec3982
commit
32f3083e87
|
@ -0,0 +1,105 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/game"
|
||||
"github.com/kercylan98/minotaur/utils/huge"
|
||||
)
|
||||
|
||||
func NewItemContainer[ItemID comparable, Item game.Item[ItemID]]() *ItemContainer[ItemID, Item] {
|
||||
return &ItemContainer[ItemID, Item]{
|
||||
items: map[ItemID]map[int64]*itemContainerInfo[ItemID, Item]{},
|
||||
}
|
||||
}
|
||||
|
||||
type ItemContainer[ItemID comparable, Item game.Item[ItemID]] struct {
|
||||
sizeLimit int
|
||||
size int
|
||||
expandSize int
|
||||
items map[ItemID]map[int64]*itemContainerInfo[ItemID, Item]
|
||||
}
|
||||
|
||||
func (slf *ItemContainer[ItemID, Item]) GetSize() int {
|
||||
return slf.size
|
||||
}
|
||||
|
||||
func (slf *ItemContainer[ItemID, Item]) SetExpandSize(size int) {
|
||||
slf.expandSize = size
|
||||
}
|
||||
|
||||
func (slf *ItemContainer[ItemID, Item]) GetSizeLimit() int {
|
||||
return slf.sizeLimit + slf.expandSize
|
||||
}
|
||||
|
||||
func (slf *ItemContainer[ItemID, Item]) AddItem(item Item, count *huge.Int) error {
|
||||
if count.LessThanOrEqualTo(huge.IntZero) {
|
||||
return ErrCannotAddNegativeItem
|
||||
}
|
||||
infos, exist := slf.items[item.GetID()]
|
||||
if !exist {
|
||||
infos = map[int64]*itemContainerInfo[ItemID, Item]{}
|
||||
slf.items[item.GetID()] = infos
|
||||
|
||||
}
|
||||
info, exist := infos[item.GetGUID()]
|
||||
if !exist {
|
||||
if slf.GetSizeLimit() >= slf.GetSize() {
|
||||
return ErrItemContainerIsFull
|
||||
}
|
||||
infos[item.GetGUID()] = &itemContainerInfo[ItemID, Item]{
|
||||
item: item,
|
||||
count: count,
|
||||
}
|
||||
slf.size++
|
||||
} else {
|
||||
info.count = info.count.Add(count)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (slf *ItemContainer[ItemID, Item]) DeductItem(id ItemID, count *huge.Int) error {
|
||||
return slf.DeductItemWithGuid(id, -1, count)
|
||||
}
|
||||
|
||||
func (slf *ItemContainer[ItemID, Item]) DeductItemWithGuid(id ItemID, guid int64, count *huge.Int) error {
|
||||
infos, exist := slf.items[id]
|
||||
if !exist || len(infos) == 0 {
|
||||
return ErrItemNotExist
|
||||
}
|
||||
|
||||
var backupInfos = make(map[int64]*itemContainerInfo[ItemID, Item])
|
||||
var pending = count.Copy()
|
||||
var deductSize int
|
||||
for g, info := range infos {
|
||||
if g != guid && guid >= 0 {
|
||||
continue
|
||||
}
|
||||
info.bakCount = info.count.Copy()
|
||||
backupInfos[g] = info
|
||||
|
||||
if pending.GreaterThanOrEqualTo(info.count) {
|
||||
pending = pending.Sub(info.count)
|
||||
info.count = huge.IntZero
|
||||
} else {
|
||||
info.count = info.count.Sub(pending)
|
||||
pending = huge.IntZero
|
||||
}
|
||||
|
||||
if info.count.EqualTo(huge.IntZero) {
|
||||
delete(infos, guid)
|
||||
deductSize++
|
||||
}
|
||||
if pending.EqualTo(huge.IntZero) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if pending.GreaterThan(huge.IntZero) {
|
||||
for g, info := range backupInfos {
|
||||
infos[g] = info
|
||||
info.count = info.bakCount
|
||||
info.bakCount = nil
|
||||
}
|
||||
return ErrItemInsufficientQuantity
|
||||
}
|
||||
slf.size -= deductSize
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package builtin
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrCannotAddNegativeItem = errors.New("cannot add items with negative quantities")
|
||||
ErrItemNotExist = errors.New("item not exist")
|
||||
ErrItemInsufficientQuantity = errors.New("item insufficient quantity")
|
||||
ErrItemContainerIsFull = errors.New("item container is full")
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
package builtin
|
||||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/game"
|
||||
"github.com/kercylan98/minotaur/utils/huge"
|
||||
)
|
||||
|
||||
type itemContainerInfo[ItemID comparable, Item game.Item[ItemID]] struct {
|
||||
item Item
|
||||
count *huge.Int
|
||||
bakCount *huge.Int
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package builtin
|
||||
|
||||
import "github.com/kercylan98/minotaur/game"
|
||||
|
||||
type ItemContainerOption[ItemID comparable, Item game.Item[ItemID]] func(container ItemContainer[ItemID, Item])
|
||||
|
||||
// WithItemContainerSizeLimit 通过特定的物品容器非堆叠数量上限创建物品容器
|
||||
func WithItemContainerSizeLimit[ItemID comparable, Item game.Item[ItemID]](sizeLimit int) ItemContainerOption[ItemID, Item] {
|
||||
return func(container ItemContainer[ItemID, Item]) {
|
||||
if sizeLimit <= 0 {
|
||||
return
|
||||
}
|
||||
container.sizeLimit = sizeLimit
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package game
|
||||
|
||||
type Item[ID comparable] interface {
|
||||
// GetID 获取物品ID
|
||||
GetID() ID
|
||||
// GetGUID 获取物品GUID
|
||||
// - 用于标识同一件物品不同的特征
|
||||
// - 负数的GUID在内置功能中可能会被用于特殊判定,如果需要负数建议另外对特殊功能进行实现
|
||||
GetGUID() int64
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package game
|
||||
|
||||
import "github.com/kercylan98/minotaur/utils/huge"
|
||||
|
||||
// ItemContainer 物品容器
|
||||
type ItemContainer[ItemID comparable, I Item[ItemID]] interface {
|
||||
// GetSize 获取容器物品非堆叠数量
|
||||
GetSize() int
|
||||
// GetSizeLimit 获取容器物品非堆叠数量上限
|
||||
GetSizeLimit() int
|
||||
// SetExpandSize 设置拓展非堆叠数量上限
|
||||
SetExpandSize(size int)
|
||||
|
||||
// AddItem 添加物品
|
||||
// - 当物品guid相同时,如果相同物品id及guid的堆叠数量未达到上限,将增加数量,否则增加非堆叠数量
|
||||
// - 当物品guid不同时,堆叠将不可用,每次都将增加非堆叠数量
|
||||
AddItem(item I, count *huge.Int) error
|
||||
// DeductItem 扣除特定物品数量,当数量为0将被移除,数量不足时将不进行任何改变
|
||||
// - 将查找特定id的物品,无论guid是否相同,都有可能被扣除直到达到扣除数量
|
||||
// - 当count为负数时,由于负负得正,无论guid是否相同,都有可能被增加物品数量直到达到扣除数量
|
||||
DeductItem(id ItemID, count *huge.Int) error
|
||||
// DeductItemWithGuid 更为精准的扣除特定物品数量,可参考 DeductItem
|
||||
DeductItemWithGuid(id ItemID, guid int64, count *huge.Int) error
|
||||
}
|
Loading…
Reference in New Issue