From 5c5e5c06ab6aab660bab0795ff24c821fecd4d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <1@72wo.cn> Date: Sun, 23 Nov 2025 00:06:14 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(fight):=20=E4=BC=98=E5=8C=96Boss?= =?UTF-8?q?=E6=88=98=E5=A5=96=E5=8A=B1=E5=8F=91=E6=94=BE=E4=B8=8E=E7=BB=8F?= =?UTF-8?q?=E9=AA=8C=E9=80=9A=E7=9F=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构 Boss 怪物掉落物品发放代码,提高可读性与扩展性 - 注释掉宠物经验变化的通知指令(2509),暂不发送给客户端 - 修复战斗模式判断条件,从 Mode 改为 Status 判断 PVE 战斗 - 调整战斗超时逻辑,修改超时原因并增加调试日志输出 - 优化战斗结束回调执行顺序,确保广播前完成状态更新 - 重写 PetInfo.AddEV 方法,支持更安全 --- logic/controller/fight_boss.go | 20 ++++---- logic/service/fight/input.go | 5 +- logic/service/fight/loop.go | 9 ++-- modules/blazing/model/pet.go | 88 +++++++++++++++++++++++++++++----- 4 files changed, 95 insertions(+), 27 deletions(-) diff --git a/logic/controller/fight_boss.go b/logic/controller/fight_boss.go index d4facd43e..870c200aa 100644 --- a/logic/controller/fight_boss.go +++ b/logic/controller/fight_boss.go @@ -159,23 +159,21 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn if foi.Reason == 0 && foi.WinnerId == c.Info.UserID { if refpet.Item != 0 { - - c.SendPackCmd(8004, &info.S2C_GET_BOSS_MONSTER{ - - ItemList: c.ItemAdd(model.ItemInfo{ - ItemId: refpet.Item, - ItemCnt: uint32(grand.Intn(2) + 1), - }), + items := &info.S2C_GET_BOSS_MONSTER{} + items.ItemList = c.ItemAdd(model.ItemInfo{ + ItemId: refpet.Item, + ItemCnt: uint32(grand.Intn(2) + 1), }) + c.SendPackCmd(8004, items) } - foi.Winpet.ADD_EV(gconv.Uint32s(strings.Split(xmlres.PetMAP[int(mo.ID)].YieldingEV, " "))) + foi.Winpet.AddEV(gconv.Uint32s(strings.Split(xmlres.PetMAP[int(mo.ID)].YieldingEV, " "))) exp := uint32(xmlres.PetMAP[int(mo.ID)].YieldingExp) * mo.Level / 7 c.Info.ExpPool += exp * 4 c.AddPetExp(foi.Winpet, uint32(exp)*2) - c.SendPackCmd(2509, &info.PET_WAR_EXP_NOTICE{ - EXP: exp * 2, - }) + // c.SendPackCmd(2509, &info.PET_WAR_EXP_NOTICE{ + // EXP: exp * 2, + // }) } return 0 diff --git a/logic/service/fight/input.go b/logic/service/fight/input.go index cb6b1541c..498105318 100644 --- a/logic/service/fight/input.go +++ b/logic/service/fight/input.go @@ -219,7 +219,7 @@ func NewFight(p1, p2 common.PlayerI, fn func(*info.FightOverInfo)) (*FightC, err f.ReadyInfo.OpponentInfo, f.ReadyInfo.OpponentPetList = initfightready(f.Opp) var loadtime time.Duration = 120 * time.Second //说明是PVE - if f.Info.Mode == info.BattleMode.FIGHT_WITH_NPC { + if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC { f.Opp.Finished = true //PVE 默认boss数据直接加载完成 loadtime = 60 * time.Second @@ -237,9 +237,10 @@ func NewFight(p1, p2 common.PlayerI, fn func(*info.FightOverInfo)) (*FightC, err }) cool.Cron.AfterFunc(loadtime, func() { + fmt.Println(f.Our.UserID, "战斗超时结算") if !f.Our.Finished || !f.Opp.Finished { //如果有任一没有加载完成 f.closefight = true //阻止继续添加action - f.Reason = info.BattleOverReason.PlayerOVerTime + f.Reason = info.BattleOverReason.PlayerOffline switch { case !f.Opp.Finished: //邀请方没加载完成 先判断邀请方,如果都没加载完成,就算做房主胜利 f.WinnerId = f.Our.Player.GetInfo().UserID diff --git a/logic/service/fight/loop.go b/logic/service/fight/loop.go index 3f4695523..d99d819bf 100644 --- a/logic/service/fight/loop.go +++ b/logic/service/fight/loop.go @@ -72,11 +72,14 @@ func (f *FightC) battleLoop() { //大乱斗,给个延迟 <-time.After(500) } - if f.callback != nil { - f.callback(&f.FightOverInfo) //先执行回调,再执行返回信息,在回调内修改战斗判断 + }) + if f.callback != nil { - } + f.callback(&f.FightOverInfo) //先执行回调,再执行返回信息,在回调内修改战斗判断 + + } + f.Broadcast(func(ff *input.Input) { ff.Player.SendPackCmd(2506, &f.FightOverInfo) ff.Player.QuitFight() diff --git a/modules/blazing/model/pet.go b/modules/blazing/model/pet.go index 1576a53f3..0489208a9 100644 --- a/modules/blazing/model/pet.go +++ b/modules/blazing/model/pet.go @@ -2,8 +2,9 @@ package model import ( "blazing/common/data/xmlres" - "blazing/common/utils" "blazing/cool" + "errors" + "fmt" "math" "math/rand" "time" @@ -96,20 +97,85 @@ type PetInfo struct { // AbilityType uint32 `struc:"skip"` //特性 } -func (pet *PetInfo) ADD_EV(evadd []uint32) { - var sum uint32 - for i := range pet.Ev { - sum += pet.Ev[i] +// 定义常量,提升可维护性(避免魔法数字) +const ( + maxSingleEV uint32 = 255 // 单个EV最大值 + maxTotalEV uint32 = 510 // 6个EV总和最大值 + evFieldCount = 6 // EV字段数量(固定6个) +) + +// AddEV 优化后的EV值增加方法(符合Go命名规范:大写导出,动词开头) +// 功能:为宠物6个EV值增加增量,保证单个≤255、总和≤510 +// 参数:evadd - 6个EV字段的增量数组(长度必须为6) +// 返回:error - 参数非法/逻辑异常时返回错误;bool - 是否触发了超额削减(方便业务监控) +func (pet *PetInfo) AddEV(evadd []uint32) (bool, error) { + // 1. 参数安全校验:避免数组越界panic + if len(evadd) != evFieldCount { + return false, fmt.Errorf("evadd长度必须为%d,当前为%d", evFieldCount, len(evadd)) + } + if len(pet.Ev) != evFieldCount { + return false, errors.New("pet.Ev未初始化或长度不为6") } - cansum := 510 - sum - for i := 0; i < 6; i++ { - - pet.Ev[i] += evadd[i] - pet.Ev[i] = utils.Min(pet.Ev[i], 255) - pet.Ev[i] = utils.Min(pet.Ev[i], cansum) + // 2. 预计算:当前EV总和 + 增量后的临时值(先不修改原数据,避免边改边算) + var ( + totalCurrent uint32 // 当前EV总和 + tempEV [evFieldCount]uint32 // 增量后的临时EV值(避免修改原数组导致计算错误) + ) + // 一次性遍历:计算当前总和 + 初始化临时EV(减少遍历次数) + for i := 0; i < evFieldCount; i++ { + totalCurrent += pet.Ev[i] + // 先计算增量后的值,同时限制单个不超过maxSingleEV + tempEV[i] = pet.Ev[i] + evadd[i] + if tempEV[i] > maxSingleEV { + tempEV[i] = maxSingleEV + } } + // 3. 计算增量后的临时总和,检查是否超过maxTotalEV + totalTemp := uint32(0) + for _, v := range tempEV { + totalTemp += v + } + + // 4. 若总和超额,执行削减逻辑(优先削减数值大的字段,保证公平性) + hasCut := false + if totalTemp > maxTotalEV { + overTotal := totalTemp - maxTotalEV // 需要削减的总量 + hasCut = true + + // 循环削减直到超额量为0(优先削减数值大的字段,避免小值被过度削减) + for overTotal > 0 { + // 找到当前最大的EV索引 + maxIdx := 0 + for i := 1; i < evFieldCount; i++ { + if tempEV[i] > tempEV[maxIdx] { + maxIdx = i + } + } + + // 计算该字段可削减的最大值(至少留到原数值,或削减到能覆盖overTotal) + cutAble := tempEV[maxIdx] - pet.Ev[maxIdx] // 最多削减增量部分,不低于原值 + if cutAble == 0 { + cutAble = tempEV[maxIdx] // 若增量为0,可削减当前值(根据业务调整,也可panic) + } + + // 实际削减量:取可削减量和剩余超额量的较小值 + cut := cutAble + if cut > overTotal { + cut = overTotal + } + + // 执行削减 + tempEV[maxIdx] -= cut + overTotal -= cut + } + } + + // 5. 将处理后的临时值赋值给原EV(批量赋值,减少零散操作) + copy(pet.Ev[:], tempEV[:]) + + return hasCut, nil } func (pet *PetInfo) Cure() { pet.Hp = pet.MaxHp