Files
bl/logic/controller/fight_boss.go
昔念 fcb55d3a46 ```
refactor(controller): 替换BossCompletedTask为专用方法名

在战斗控制器中将p.BossCompletedTask替换为p.SptCompletedTask,
以及在塔沃控制器中将BossCompletedTask相关调用替换为TawerCompletedTask,
以更好地区分不同的任务完成逻辑。

---

fix(item_use): 添加nil检查防止程序崩溃

在处理神经元道具时,增加对oldPet对象的nil检查,
如果为空则返回系统错误码,避免程序出现
2026-01-20 04:40:36 +08:00

241 lines
6.0 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/data"
"blazing/common/data/xmlres"
"blazing/common/socket/errorcode"
"strings"
"blazing/logic/service/fight"
"blazing/logic/service/fight/info"
"blazing/logic/service/player"
"blazing/modules/config/service"
"blazing/modules/player/model"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"github.com/samber/lo"
)
// processMonID 处理怪物ID字符串如果是多个ID则随机选择一个
func processMonID(bm string) string {
// 按空格分割字符串
monid := strings.Split(bm, " ")
// 过滤分割后可能的空字符串(如连续空格导致的空元素)
filtered := make([]string, 0, len(monid))
for _, m := range monid {
if m != "" {
filtered = append(filtered, m)
}
}
monid = filtered
var selected string
switch len(monid) {
case 0:
// 无元素时,可返回空或默认值(根据业务需求调整)
selected = ""
case 1:
// 长度为1时取第一个唯一的元素
selected = monid[0]
default:
// 长度大于1时随机选取一个
randomIdx := grand.Intn(len(monid))
selected = monid[randomIdx]
}
return selected
}
// PlayerFightBoss 挑战地图boss
// data: 包含挑战Boss信息的输入数据
// player: 当前玩家对象
// 返回: 战斗结果和错误码
func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !p.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNoStamina
}
var monster *model.PetInfo
monsterInfo := &model.PlayerInfo{}
var taskID int
var canCapture int
mdata, ok := xmlres.MonsterMap[int(p.Info.MapID)]
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
if len(mdata.Bosses) == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
for _, bc := range mdata.Bosses {
if bc.Id == nil {
bc.Id = gconv.PtrInt(0)
}
if (bc.Id == nil && data.BossId == 0) || uint32(*bc.Id) == data.BossId { //打默认第一个boss
if bc.TaskID != nil {
taskID = *bc.TaskID
}
for i, bm := range bc.BossMon {
monster = model.GenPetInfo(
gconv.Int(processMonID(bm.MonID)), 24, //24个体
-1,
0, //野怪没特性
bm.Lv, nil)
monster.CatchTime = uint32(i)
if bm.Hp != 0 {
monster.Hp = uint32(bm.Hp)
monster.MaxHp = uint32(bm.Hp)
}
for _, v := range strings.Split(bm.NewSeIdxs, " ") {
idx := gconv.Uint16(v)
if idx == 0 {
continue
}
EID, args := service.NewEffectService().Args(uint32(idx))
monster.EffectInfo = append(monster.EffectInfo, model.PetEffectInfo{
Idx: idx,
EID: gconv.Uint16(EID),
Args: gconv.Ints(args),
})
}
monsterInfo.PetList = append(monsterInfo.PetList, *monster)
}
if bc.BossCatchable == 1 {
canCapture = xmlres.PetMAP[int(monster.ID)].CatchRate
if grand.Meet(1, 100) {
r := monsterInfo.PetList[0]
r.RandShiny()
monsterInfo.PetList[0] = r
}
}
monsterInfo.Nick = bc.Name //xmlres.PetMAP[int(monster.ID)].DefName
break
}
}
if len(monsterInfo.PetList) == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
p.Fightinfo.Status = info.BattleMode.FIGHT_WITH_NPC
p.Fightinfo.Mode = info.BattleMode.MULTI_MODE
ai := player.NewAI_player(monsterInfo)
ai.CanCapture = canCapture
ai.Prop[0] = 2
fight.NewFight(p, ai, func(foi info.FightOverInfo) {
if taskID != 0 {
if foi.Reason == 0 && foi.WinnerId == p.Info.UserID {
p.SptCompletedTask(taskID, 1)
}
}
//p.Done.Exec(model.MilestoneMode.BOSS, []uint32{p.Info.MapID, data.BossId, uint32(foi.Reason)}, nil)
})
return nil, -1
}
// OnPlayerFightNpcMonster 战斗野怪
// data: 包含战斗野怪信息的输入数据
// player: 当前玩家对象
// 返回: 战斗结果和错误码
func (h Controller) OnPlayerFightNpcMonster(data1 *fight.FightNpcMonsterInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !p.CanFight() {
return nil, errorcode.ErrorCodes.ErrSystemError
}
refPet := p.OgreInfo.Data[data1.Number]
if refPet.Id == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
if refPet.Ext != 0 {
refPet.Id = refPet.Ext
}
monster := model.GenPetInfo(
int(refPet.Id), -1,
-1,
0, //野怪没特性
int(refPet.Lv),
refPet.ShinyInfo)
if refPet.Ext != 0 {
if grand.Meet(3, 100) {
monster.RandShiny()
}
}
monsterInfo := &model.PlayerInfo{}
monsterInfo.Nick = xmlres.PetMAP[int(monster.ID)].DefName
monsterInfo.PetList = append(monsterInfo.PetList, *monster)
ai := player.NewAI_player(monsterInfo)
ai.CanCapture = handleNPCFightSpecial(monster.ID)
p.Fightinfo.Status = info.BattleMode.FIGHT_WITH_NPC //打野怪
p.Fightinfo.Mode = info.BattleMode.MULTI_MODE //多人模式
fight.NewFight(p, ai, func(foi info.FightOverInfo) {
//p.Done.Exec(model.MilestoneMode.Moster, []uint32{p.Info.MapID, monsterInfo.PetList[0].ID, uint32(foi.Reason)}, nil)
if foi.Reason == 0 && foi.WinnerId == p.Info.UserID {
if !p.CanGetExp() {
return
}
exp := uint32(xmlres.PetMAP[int(monster.ID)].YieldingExp) * monster.Level / 7
items := &info.S2C_GET_BOSS_MONSTER{
//EV: 45,
EXP: exp * 2,
}
if refPet.Item != 0 {
p.ItemAdd(refPet.Item, uint32(grand.Intn(2)+1))
items.ItemList = append(items.ItemList, data.ItemInfo{
ItemId: refPet.Item,
ItemCnt: uint32(grand.Intn(2) + 1),
})
}
evs := gconv.Uint32s(strings.Split(xmlres.PetMAP[int(monster.ID)].YieldingEV, " "))
items.EV = lo.Sum(evs) - 1
p.Info.EVPool += lo.Sum(evs) //给予累计学习力
foi.Winpet.AddEV(evs)
p.Info.ExpPool += exp * 4
p.AddPetExp(foi.Winpet, uint32(exp)*2)
p.SendPackCmd(8004, items)
}
})
return nil, -1
}
// handleNPCFightSpecial 处理NPC战斗特殊情况
func handleNPCFightSpecial(petID uint32) int {
npcPetID := int(petID)
petCfg, ok := xmlres.PetMAP[npcPetID]
if !ok {
// log.Error(context.Background(), "NPC宠物配置不存在", "petID", npcPetID)
return 0
}
catchRate := gconv.Int(petCfg.CatchRate)
return catchRate
}