Files
bl/logic/controller/item_use.go
昔念 3e4b091724
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
```
fix(item): 修复物品数量判断逻辑

- 将物品数量判断从 `!= 0` 改为 `> 0`,确保只有正数才添加到列表中
- 将物品检查逻辑从 `< 1` 改为 `<= 0`,确保正确处理边界情况
- 在物品更新方法中增加ID为0的防护,避免无效操作
```
2026-02-22 19:33:17 +08:00

252 lines
8.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controller
import (
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/item"
"blazing/logic/service/player"
"blazing/modules/player/model"
"github.com/jinzhu/copier"
)
const (
// ItemDefaultLeftTime 道具默认剩余时间(毫秒)
ItemDefaultLeftTime = 360000
// ItemNeuronID 神经元道具ID
ItemNeuronID = 300036
)
// GetUserItemList 获取用户道具列表
// data: 包含分页参数的输入信息
// c: 当前玩家对象
// 返回: 道具列表和错误码
func (h Controller) GetUserItemList(data *item.ItemListInboundInfo, c *player.Player) (result *item.ItemListOutboundInfo, err errorcode.ErrorCode) {
result = &item.ItemListOutboundInfo{}
result.ItemList = make([]model.SingleItemInfo, 0)
items := c.Service.Item.Get(data.Param1, data.Param2)
for _, itemData := range items {
itemInfo := model.SingleItemInfo{
ItemId: itemData.ItemId,
ItemCnt: uint32(itemData.ItemCnt),
LeftTime: ItemDefaultLeftTime,
}
if itemInfo.ItemCnt > 0 {
result.ItemList = append(result.ItemList, itemInfo)
}
}
return result, 0
}
// UsePetItemOutOfFight 战斗外使用宠物道具
// data: 包含道具ID和宠物捕获时间的输入信息
// c: 当前玩家对象
// 返回: 使用后的宠物信息和错误码
func (h Controller) UsePetItemOutOfFight(data *item.C2S_USE_PET_ITEM_OUT_OF_FIGHT, c *player.Player) (result *item.S2C_USE_PET_ITEM_OUT_OF_FIGHT, err errorcode.ErrorCode) {
_, currentPet, found := c.FindPet(data.CatchTime)
if !found {
return nil, errorcode.ErrorCodes.Err10401
}
if c.Service.Item.CheakItem(uint32(data.ItemID)) == 0 {
return nil, errorcode.ErrorCodes.ErrSystemError
}
var errcode errorcode.ErrorCode
if data.ItemID == ItemNeuronID {
errcode = h.handleNeuronItem(currentPet, c)
} else {
errcode = h.handleRegularPetItem(uint32(data.ItemID), currentPet)
}
if errcode != 0 {
return nil, errcode
}
c.Service.Item.UPDATE(uint32(data.ItemID), -1)
result = &item.S2C_USE_PET_ITEM_OUT_OF_FIGHT{}
currentPet.CalculatePetPane(false)
copier.Copy(&result, currentPet)
// defer c.Service.Info.Save(*c.Info)
return result, 0
}
// handleNeuronItem 处理神经元道具的特殊逻辑
func (h Controller) handleNeuronItem(currentPet *model.PetInfo, c *player.Player) errorcode.ErrorCode {
if currentPet.OldCatchTime == 0 {
return errorcode.ErrorCodes.ErrSystemError
}
originalCatchTime := currentPet.CatchTime
oldPet := c.Service.Pet.PetInfo_One_Unscoped(currentPet.OldCatchTime)
if oldPet == nil {
return errorcode.ErrorCodes.ErrCannotRevertSpirit
}
copier.CopyWithOption(currentPet, oldPet.Data, copier.Option{DeepCopy: true})
currentPet.CatchTime = originalCatchTime
currentPet.ShinyInfo = oldPet.Data.ShinyInfo
currentPet.EffectInfo = oldPet.Data.EffectInfo
return 0
}
// handleRegularPetItem 处理普通宠物道具
func (h Controller) handleRegularPetItem(itemID uint32, currentPet *model.PetInfo) errorcode.ErrorCode {
handler := item.PetItemRegistry.GetHandler(itemID)
if handler == nil {
return errorcode.ErrorCodes.ErrSystemError
}
if !handler(itemID, currentPet) {
return errorcode.ErrorCodes.ErrSystemError
}
return 0
}
// ResetNature 重置宠物性格
// data: 包含道具ID和宠物捕获时间的输入信息
// c: 当前玩家对象
// 返回: 无数据和错误码
func (h Controller) ResetNature(data *item.C2S_PET_RESET_NATURE, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
_, currentPet, found := c.FindPet(data.CatchTime)
if !found {
return nil, errorcode.ErrorCodes.Err10401
}
if c.Service.Item.CheakItem(data.ItemId) <= 0 {
return nil, errorcode.ErrorCodes.ErrSystemError
}
currentPet.Nature = data.Nature
currentPet.CalculatePetPane(false)
c.Service.Item.UPDATE(data.ItemId, -1)
return result, 0
}
// ==============================
// 双倍经验加速器相关方法
// ==============================
// UseSpeedupItem 使用双倍经验加速器
// data: 包含使用的双倍经验物品ID的输入信息
// c: 当前玩家对象
// 返回: 无数据(响应包单独组装)和错误码
// 说明根据物品ID区分双倍/三倍经验加速器,使用后扣减道具并更新玩家剩余次数
func (h Controller) UseSpeedupItem(data *item.C2S_USE_SPEEDUP_ITEM, c *player.Player) (result *item.S2C_USE_SPEEDUP_ITEM, err errorcode.ErrorCode) {
// 1. 校验道具是否存在且数量充足
itemCount := c.Service.Item.CheakItem(data.ItemID)
if itemCount <= 0 {
return nil, errorcode.ErrorCodes.ErrSystemError // 道具不足复用系统错误码(可根据需求改为专属错误码)
}
result = &item.S2C_USE_SPEEDUP_ITEM{}
// 2. 核心业务逻辑根据物品ID更新双倍/三倍经验剩余次数
// (注:需根据你的道具配置表,补充 ItemID 与双倍/三倍的映射逻辑)
switch data.ItemID {
case 300027: // 假设1001是双倍经验加速器道具ID
if c.Info.TwoTimes != 0 {
return nil, errorcode.ErrorCodes.ErrItemInUse
}
c.Info.TwoTimes += 50 // 玩家对象新增 TwoTimesExp 字段存储双倍剩余次数
case 300067:
if c.Info.TwoTimes != 0 {
return nil, errorcode.ErrorCodes.ErrItemInUse
}
c.Info.TwoTimes += 25 // 玩家对象新增 TwoTimesExp 字段存储双倍剩余次数
case 300051: // 假设1002是三倍经验加速器道具ID
if c.Info.ThreeTimes != 0 {
return nil, errorcode.ErrorCodes.ErrItemInUse
}
c.Info.ThreeTimes += 50 // 玩家对象新增 ThreeTimesExp 字段存储三倍剩余次数
case 300115:
if c.Info.ThreeTimes != 0 {
return nil, errorcode.ErrorCodes.ErrItemInUse
}
c.Info.ThreeTimes += 30 // 玩家对象新增 ThreeTimesExp 字段存储三倍剩余次数
default:
return nil, errorcode.ErrorCodes.ErrSystemError // 未知道具ID
}
// 3. 扣减道具(数量-1
c.Service.Item.UPDATE(data.ItemID, -1)
result.ThreeTimes = c.Info.ThreeTimes // 返回三倍经验剩余次数
result.TwoTimes = c.Info.TwoTimes // 返回双倍经验剩余次数
// 4. (可选)持久化玩家经验次数(根据你的项目存储逻辑补充)
// c.Service.Player.SaveExpTimes(c)
// 5. 返回无数据结果和成功错误码
return result, 0
}
// ==============================
// 能量吸收器相关方法
// ==============================
// UseEnergyXishou 使用能量吸收器
// data: 包含使用的能量吸收器物品ID的输入信息
// c: 当前玩家对象
// 返回: 无数据(响应包单独组装)和错误码
// 说明:使用后扣减道具并更新玩家能量吸收器剩余次数
func (h Controller) UseEnergyXishou(data *item.C2S_USE_ENERGY_XISHOU, c *player.Player) (result *item.S2C_USE_ENERGY_XISHOU, err errorcode.ErrorCode) {
// 1. 校验道具是否存在且数量充足
itemCount := c.Service.Item.CheakItem(data.ItemID)
if itemCount <= 0 {
return nil, errorcode.ErrorCodes.ErrSystemError
}
if c.Info.EnergyTime != 0 {
return nil, errorcode.ErrorCodes.ErrItemInUse
}
// 2. 核心业务逻辑:更新能量吸收器剩余次数
// 可根据道具ID配置不同的次数加成此处默认+1
c.Info.EnergyTime += 40 // 玩家对象新增 EnergyTimes 字段存储能量吸收剩余次数
// 3. 扣减道具(数量-1
c.Service.Item.UPDATE(data.ItemID, -1)
// 4. (可选)持久化玩家能量次数
// c.Service.Player.SaveEnergyTimes(c)
// 5. 返回无数据结果和成功错误码
return result, 0
}
// ==============================
// 自动战斗仪相关方法
// ==============================
// UseAutoFightItem 使用自动战斗仪
// data: 包含使用的自动战斗仪物品ID的输入信息
// c: 当前玩家对象
// 返回: 无数据(响应包单独组装)和错误码
// 说明使用后扣减道具开启自动战斗flag设为3并更新剩余次数
func (h Controller) UseAutoFightItem(data *item.C2S_USE_AUTO_FIGHT_ITEM, c *player.Player) (result *item.S2C_USE_AUTO_FIGHT_ITEM, err errorcode.ErrorCode) {
// 1. 校验道具是否存在且数量充足
itemCount := c.Service.Item.CheakItem(data.ItemID)
if itemCount <= 0 {
return nil, errorcode.ErrorCodes.ErrSystemError
}
if c.Info.AutoFightTime != 0 {
return nil, errorcode.ErrorCodes.ErrItemInUse
}
result = &item.S2C_USE_AUTO_FIGHT_ITEM{}
// 2. 核心业务逻辑:开启自动战斗 + 更新剩余次数
c.Info.AutoFight = 3 // 按需求设置自动战斗flag为3需测试
if data.ItemID == 300028 {
c.Info.AutoFightTime += 100
}
result.AutoFight = 1
switch data.ItemID {
case 300028:
c.Info.AutoFightTime += 100
case 300068:
c.Info.AutoFightTime += 50
}
result.AutoFightTimes = c.Info.AutoFightTime
// 3. 扣减道具(数量-1
c.Service.Item.UPDATE(data.ItemID, -1)
return result, 0
}