物品容器基本实现

This commit is contained in:
kercylan98 2023-05-10 11:33:17 +08:00
parent eb31ec3982
commit 32f3083e87
6 changed files with 176 additions and 0 deletions

View File

@ -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
}

View File

@ -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")
)

View File

@ -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
}

View File

@ -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
}
}

10
game/item.go Normal file
View File

@ -0,0 +1,10 @@
package game
type Item[ID comparable] interface {
// GetID 获取物品ID
GetID() ID
// GetGUID 获取物品GUID
// - 用于标识同一件物品不同的特征
// - 负数的GUID在内置功能中可能会被用于特殊判定如果需要负数建议另外对特殊功能进行实现
GetGUID() int64
}

24
game/item_container.go Normal file
View File

@ -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
}