diff --git a/game/builtin/item_container.go b/game/builtin/item_container.go index 7873698..d1b7798 100644 --- a/game/builtin/item_container.go +++ b/game/builtin/item_container.go @@ -3,6 +3,7 @@ package builtin import ( "github.com/kercylan98/minotaur/game" "github.com/kercylan98/minotaur/utils/huge" + "github.com/kercylan98/minotaur/utils/super" "sync/atomic" ) @@ -10,7 +11,6 @@ func NewItemContainer[ItemID comparable, Item game.Item[ItemID]](options ...Item itemContainer := &ItemContainer[ItemID, Item]{ items: map[int64]*ItemContainerMember[ItemID, Item]{}, itemIdGuidRef: map[ItemID]map[int64]bool{}, - stackLimits: map[ItemID]*huge.Int{}, } for _, option := range options { option(itemContainer) @@ -25,16 +25,18 @@ type ItemContainer[ItemID comparable, Item game.Item[ItemID]] struct { expandSize int items map[int64]*ItemContainerMember[ItemID, Item] itemIdGuidRef map[ItemID]map[int64]bool - sort []*itemContainerSort[ItemID] - stackLimits map[ItemID]*huge.Int + sort []*int64 + maxSort int + vacancy []int + stackLimit map[ItemID]*huge.Int } func (slf *ItemContainer[ItemID, Item]) GetSize() int { - return slf.size + slf.expandSize + return slf.size } func (slf *ItemContainer[ItemID, Item]) GetSizeLimit() int { - return slf.sizeLimit + return slf.sizeLimit + slf.expandSize } func (slf *ItemContainer[ItemID, Item]) SetExpandSize(size int) { @@ -50,8 +52,26 @@ func (slf *ItemContainer[ItemID, Item]) GetItem(guid int64) (game.ItemContainerM } func (slf *ItemContainer[ItemID, Item]) GetItems() []game.ItemContainerMember[ItemID, Item] { - //TODO implement me - panic("implement me") + var result = make([]game.ItemContainerMember[ItemID, Item], 0, len(slf.sort)) + for _, guid := range slf.sort { + if guid == nil { + continue + } + result = append(result, slf.items[*guid]) + } + return result +} + +func (slf *ItemContainer[ItemID, Item]) GetItemsFull() []game.ItemContainerMember[ItemID, Item] { + var result = make([]game.ItemContainerMember[ItemID, Item], len(slf.sort), len(slf.sort)) + for i, guid := range slf.sort { + if guid == nil { + result[i] = nil + } else { + result[i] = slf.items[*guid] + } + } + return result } func (slf *ItemContainer[ItemID, Item]) GetItemsMap() map[int64]game.ItemContainerMember[ItemID, Item] { @@ -78,6 +98,9 @@ func (slf *ItemContainer[ItemID, Item]) AddItem(item Item, count *huge.Int) erro for guid := range slf.itemIdGuidRef[item.GetID()] { member := slf.items[guid] if member.GetItem().IsSame(item) { + if stackLimit := slf.stackLimit[item.GetID()]; stackLimit != nil && member.count.Copy().Add(count).GreaterThan(stackLimit) { + continue + } member.count.Add(count) return nil } @@ -90,6 +113,22 @@ func (slf *ItemContainer[ItemID, Item]) AddItem(item Item, count *huge.Int) erro item: item, guid: guid, count: count.Copy(), + sort: super.If(len(slf.vacancy) == 0, + func() int { + sort := len(slf.sort) + slf.sort = append(slf.sort, &guid) + if sort > slf.maxSort { + slf.maxSort = sort + } + return sort + }(), + func() int { + sort := slf.vacancy[0] + slf.vacancy = slf.vacancy[1:] + slf.sort[sort] = &guid + return sort + }(), + ), } guids, exist := slf.itemIdGuidRef[item.GetID()] if !exist { @@ -110,7 +149,14 @@ func (slf *ItemContainer[ItemID, Item]) DeductItem(guid int64, count *huge.Int) member.count.Sub(count) if member.count.EqualTo(huge.IntZero) { slf.size-- + slf.sort[member.sort] = nil + slf.vacancy = append(slf.vacancy, member.sort) delete(slf.items, guid) + sizeLimit := slf.GetSizeLimit() + for slf.sort[slf.maxSort] == nil && slf.maxSort > sizeLimit { + slf.sort = append(slf.sort[0:slf.maxSort], slf.sort[slf.maxSort+1:]...) + slf.maxSort-- + } } return nil } else { @@ -129,6 +175,13 @@ func (slf *ItemContainer[ItemID, Item]) DeductItem(guid int64, count *huge.Int) if len(guids) == 0 { delete(slf.itemIdGuidRef, member.GetID()) } + slf.sort[member.sort] = nil + slf.vacancy = append(slf.vacancy, member.sort) + sizeLimit := slf.GetSizeLimit() + for slf.sort[slf.maxSort] == nil && slf.maxSort > sizeLimit { + slf.sort = append(slf.sort[0:slf.maxSort], slf.sort[slf.maxSort+1:]...) + slf.maxSort-- + } }) } else { member.count.Sub(need) diff --git a/game/builtin/item_container_member.go b/game/builtin/item_container_member.go index 578cc35..a25fd63 100644 --- a/game/builtin/item_container_member.go +++ b/game/builtin/item_container_member.go @@ -13,11 +13,10 @@ func NewItemContainerMember[ItemID comparable, I game.Item[ItemID]](guid int64, } type ItemContainerMember[ItemID comparable, I game.Item[ItemID]] struct { - item I - guid int64 - sort int - count *huge.Int - bakCount *huge.Int + item I + guid int64 + sort int + count *huge.Int } func (slf *ItemContainerMember[ItemID, I]) GetID() ItemID { diff --git a/game/builtin/item_container_options.go b/game/builtin/item_container_options.go index 923afc1..d58df44 100644 --- a/game/builtin/item_container_options.go +++ b/game/builtin/item_container_options.go @@ -1,6 +1,9 @@ package builtin -import "github.com/kercylan98/minotaur/game" +import ( + "github.com/kercylan98/minotaur/game" + "github.com/kercylan98/minotaur/utils/huge" +) type ItemContainerOption[ItemID comparable, Item game.Item[ItemID]] func(container *ItemContainer[ItemID, Item]) @@ -13,3 +16,16 @@ func WithItemContainerSizeLimit[ItemID comparable, Item game.Item[ItemID]](sizeL container.sizeLimit = sizeLimit } } + +// WithItemContainerStackLimit 通过设置特定物品堆叠数量创建容器 +func WithItemContainerStackLimit[ItemID comparable, Item game.Item[ItemID]](id ItemID, stackLimit *huge.Int) ItemContainerOption[ItemID, Item] { + return func(container *ItemContainer[ItemID, Item]) { + if stackLimit.LessThanOrEqualTo(huge.IntZero) { + return + } + if container.stackLimit == nil { + container.stackLimit = map[ItemID]*huge.Int{} + } + container.stackLimit[id] = stackLimit + } +} diff --git a/game/item_container.go b/game/item_container.go index 33ea5b5..825f464 100644 --- a/game/item_container.go +++ b/game/item_container.go @@ -10,18 +10,24 @@ type ItemContainer[ItemID comparable, I Item[ItemID]] interface { GetSizeLimit() int // SetExpandSize 设置拓展非堆叠数量上限 SetExpandSize(size int) - // GetItem 获取物品 GetItem(guid int64) (ItemContainerMember[ItemID, I], error) - // GetItems 获取所有物品 + // GetItems 获取所有非空物品 + // - 物品顺序为容器内顺序 + // - 空的容器空间将被忽略 GetItems() []ItemContainerMember[ItemID, I] + // GetItemsFull 获取所有物品 + // - 物品顺序为容器内顺序 + // - 空的容器空间将被设置为nil + // - 当容器非堆叠物品上限为0时,最后一个非空物品之后的所有空物品都将被忽略 + // - 当容器非堆叠物品未达到上限时,其余空间将使用nil填充 + GetItemsFull() []ItemContainerMember[ItemID, I] // GetItemsMap 获取所有物品 GetItemsMap() map[int64]ItemContainerMember[ItemID, I] // ExistItem 物品是否存在 ExistItem(guid int64) bool // ExistItemWithID 是否存在特定ID的物品 ExistItemWithID(id ItemID) bool - // AddItem 添加物品 AddItem(item I, count *huge.Int) error // DeductItem 扣除特定物品数量,当数量为0将被移除,数量不足时将不进行任何改变