Files
bl/logic/controller/item_use.go
昔念 b953e7831a ```
feat(fight_boss): 优化BOSS战斗奖励逻辑并修复宠物等级突破100级限制

重构了handleMapBossFightRewards函数,将奖励逻辑分离到独立的处理函数中,
增加了shouldGrantBossWinBonus条件判断,确保只有满足条件时才发放胜利奖励。

同时修复了宠物等级系统,允许宠物等级突破100级限制但面板属性仍保持100级上限,
改进了经验获取和面板更新逻辑。

fix(item
2026-04-14 00:38:50 +08:00

342 lines
11 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 (
element "blazing/common/data/Element"
"blazing/common/data/xmlres"
"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
// UniversalNatureItemID 全能性格转化剂Ω
UniversalNatureItemID uint32 = 300136
)
// GetUserItemList 获取用户道具列表
// data: 包含分页参数的输入信息
// c: 当前玩家对象
// 返回: 道具列表和错误码
func (h Controller) GetUserItemList(data *ItemListInboundInfo, c *player.Player) (result *item.ItemListOutboundInfo, err errorcode.ErrorCode) {
result = &item.ItemListOutboundInfo{
ItemList: c.Service.Item.GetUserItemList(data.Param1, data.Param2, ItemDefaultLeftTime),
}
return result, 0
}
// UsePetItemOutOfFight 战斗外使用宠物道具
// data: 包含道具ID和宠物捕获时间的输入信息
// c: 当前玩家对象
// 返回: 使用后的宠物信息和错误码
func (h Controller) UsePetItemOutOfFight(data *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
}
itemID := uint32(data.ItemID)
if c.Service.Item.CheakItem(itemID) == 0 {
return nil, errorcode.ErrorCodes.ErrInsufficientItems
}
oldHP := currentPet.Hp
itemCfg, ok := xmlres.ItemsMAP[int(itemID)]
if !ok {
errcode := h.handleRegularPetItem(itemID, currentPet)
if errcode != 0 {
return nil, errcode
}
refreshPetPaneKeepHP(currentPet, oldHP)
c.Service.Item.UPDATE(itemID, -1)
result = &item.S2C_USE_PET_ITEM_OUT_OF_FIGHT{}
copier.Copy(&result, currentPet)
return result, 0
}
var errcode errorcode.ErrorCode
switch {
case itemID == 300036:
errcode = h.handleNeuronItem(currentPet, c)
if errcode == 0 {
refreshPetPaneKeepHP(currentPet, oldHP)
}
case itemID == 300212:
errcode = h.handlexuancaiItem(currentPet, c)
case itemCfg.Bonus != 0:
errcode = errorcode.ErrorCodes.ErrItemUnusable
case itemCfg.HP != 0:
errcode = h.handleRecoverHPItemOutOfFight(itemCfg.HP, currentPet)
case itemCfg.PP != 0:
errcode = h.handleRecoverPPItemOutOfFight(itemCfg.PP, currentPet)
default:
errcode = h.handleRegularPetItem(itemID, currentPet)
if errcode == 0 {
refreshPetPaneKeepHP(currentPet, oldHP)
}
}
if errcode != 0 {
return nil, errcode
}
c.Service.Item.UPDATE(itemID, -1)
result = &item.S2C_USE_PET_ITEM_OUT_OF_FIGHT{}
copier.Copy(&result, currentPet)
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.PetInfoOneUnscoped(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
}
// 炫彩碎片 处理神300212
func (h Controller) handlexuancaiItem(currentPet *model.PetInfo, c *player.Player) errorcode.ErrorCode {
r, _ := element.Calculator.GetCombination(int(xmlres.PetMAP[int(currentPet.ID)].Type))
if r.Secondary != nil {
return errorcode.ErrorCodes.ErrItemUnusable
}
itemid := uint32(currentPet.Type()) + 400686
items := c.Service.Item.CheakItem(itemid)
if items < 100 {
return errorcode.ErrorCodes.ErrInsufficientItems
}
ok := currentPet.FixShiny()
if !ok {
return errorcode.ErrorCodes.ErrItemUnusable
}
c.Service.Item.UPDATE(itemid, -100)
return 0
}
func (h Controller) handleRecoverHPItemOutOfFight(recoverHP int, currentPet *model.PetInfo) errorcode.ErrorCode {
if currentPet.Hp >= currentPet.MaxHp {
return errorcode.ErrorCodes.ErrItemUnusable
}
currentPet.ModelHP(int64(recoverHP))
if currentPet.Hp == 0 {
currentPet.Hp = 1
}
return 0
}
func (h Controller) handleRecoverPPItemOutOfFight(recoverPP int, currentPet *model.PetInfo) errorcode.ErrorCode {
if !canRecoverPP(currentPet) {
return errorcode.ErrorCodes.ErrItemUnusable
}
currentPet.HealPP(recoverPP)
return 0
}
func canRecoverPP(currentPet *model.PetInfo) bool {
for _, skill := range currentPet.SkillList {
skillCfg, ok := xmlres.SkillMap[int(skill.ID)]
if ok && skill.PP < uint32(skillCfg.MaxPP) {
return true
}
}
return false
}
func refreshPetPaneKeepHP(currentPet *model.PetInfo, hp uint32) {
currentPet.CalculatePetPane(100)
if hp > currentPet.MaxHp {
currentPet.Hp = currentPet.MaxHp
return
}
currentPet.Hp = hp
}
// handleRegularPetItem 处理普通宠物道具
func (h Controller) handleRegularPetItem(itemID uint32, currentPet *model.PetInfo) errorcode.ErrorCode {
return item.PetItemRegistry.Handle(itemID, currentPet)
}
// ResetNature 重置宠物性格
// data: 包含道具ID和宠物捕获时间的输入信息
// c: 当前玩家对象
// 返回: 无数据和错误码
func (h Controller) ResetNature(data *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 data.ItemId != UniversalNatureItemID {
return nil, errorcode.ErrorCodes.ErrItemUnusable
}
if _, ok := xmlres.NatureRootMap[int(data.Nature)]; !ok {
return nil, errorcode.ErrorCodes.ErrItemUnusable
}
if c.Service.Item.CheakItem(data.ItemId) <= 0 {
return nil, errorcode.ErrorCodes.ErrInsufficientItems
}
currentHP := currentPet.Hp
currentPet.Nature = data.Nature
refreshPetPaneKeepHP(currentPet, currentHP)
c.Service.Item.UPDATE(data.ItemId, -1)
return result, 0
}
// ==============================
// 双倍经验加速器相关方法
// ==============================
// UseSpeedupItem 使用双倍经验加速器
// data: 包含使用的双倍经验物品ID的输入信息
// c: 当前玩家对象
// 返回: 无数据(响应包单独组装)和错误码
// 说明根据物品ID区分双倍/三倍经验加速器,使用后扣减道具并更新玩家剩余次数
func (h Controller) UseSpeedupItem(data *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.ErrInsufficientItems
}
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 = uint32(c.Info.ThreeTimes) // 返回三倍经验剩余次数
result.TwoTimes = uint32(c.Info.TwoTimes) // 返回双倍经验剩余次数
// 4. (可选)持久化玩家经验次数(根据你的项目存储逻辑补充)
// c.Service.Player.SaveExpTimes(c)
// 5. 返回无数据结果和成功错误码
return result, 0
}
// ==============================
// 能量吸收器相关方法
// ==============================
// UseEnergyXishou 使用能量吸收器
// data: 包含使用的能量吸收器物品ID的输入信息
// c: 当前玩家对象
// 返回: 无数据(响应包单独组装)和错误码
// 说明:使用后扣减道具并更新玩家能量吸收器剩余次数
func (h Controller) UseEnergyXishou(data *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.ErrInsufficientItems
}
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)
result = &item.S2C_USE_ENERGY_XISHOU{
EnergyTimes: uint32(c.Info.EnergyTime),
}
// 4. (可选)持久化玩家能量次数
// c.Service.Player.SaveEnergyTimes(c)
// 5. 返回无数据结果和成功错误码
return result, 0
}
// ==============================
// 自动战斗仪相关方法
// ==============================
// UseAutoFightItem 使用自动战斗仪
// data: 包含使用的自动战斗仪物品ID的输入信息
// c: 当前玩家对象
// 返回: 无数据(响应包单独组装)和错误码
// 说明使用后扣减道具开启自动战斗flag设为3并更新剩余次数
func (h Controller) UseAutoFightItem(data *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.ErrInsufficientItems
}
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
}