```
feat(fight): 优化Boss战奖励发放与经验通知逻辑 - 重构 Boss 怪物掉落物品发放代码,提高可读性与扩展性 - 注释掉宠物经验变化的通知指令(2509),暂不发送给客户端 - 修复战斗模式判断条件,从 Mode 改为 Status 判断 PVE 战斗 - 调整战斗超时逻辑,修改超时原因并增加调试日志输出 - 优化战斗结束回调执行顺序,确保广播前完成状态更新 - 重写 PetInfo.AddEV 方法,支持更安全
This commit is contained in:
@@ -159,23 +159,21 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn
|
|||||||
if foi.Reason == 0 && foi.WinnerId == c.Info.UserID {
|
if foi.Reason == 0 && foi.WinnerId == c.Info.UserID {
|
||||||
|
|
||||||
if refpet.Item != 0 {
|
if refpet.Item != 0 {
|
||||||
|
items := &info.S2C_GET_BOSS_MONSTER{}
|
||||||
c.SendPackCmd(8004, &info.S2C_GET_BOSS_MONSTER{
|
items.ItemList = c.ItemAdd(model.ItemInfo{
|
||||||
|
ItemId: refpet.Item,
|
||||||
ItemList: c.ItemAdd(model.ItemInfo{
|
ItemCnt: uint32(grand.Intn(2) + 1),
|
||||||
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
|
exp := uint32(xmlres.PetMAP[int(mo.ID)].YieldingExp) * mo.Level / 7
|
||||||
c.Info.ExpPool += exp * 4
|
c.Info.ExpPool += exp * 4
|
||||||
c.AddPetExp(foi.Winpet, uint32(exp)*2)
|
c.AddPetExp(foi.Winpet, uint32(exp)*2)
|
||||||
c.SendPackCmd(2509, &info.PET_WAR_EXP_NOTICE{
|
// c.SendPackCmd(2509, &info.PET_WAR_EXP_NOTICE{
|
||||||
EXP: exp * 2,
|
// EXP: exp * 2,
|
||||||
})
|
// })
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -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)
|
f.ReadyInfo.OpponentInfo, f.ReadyInfo.OpponentPetList = initfightready(f.Opp)
|
||||||
var loadtime time.Duration = 120 * time.Second
|
var loadtime time.Duration = 120 * time.Second
|
||||||
//说明是PVE
|
//说明是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数据直接加载完成
|
f.Opp.Finished = true //PVE 默认boss数据直接加载完成
|
||||||
loadtime = 60 * time.Second
|
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() {
|
cool.Cron.AfterFunc(loadtime, func() {
|
||||||
|
fmt.Println(f.Our.UserID, "战斗超时结算")
|
||||||
if !f.Our.Finished || !f.Opp.Finished { //如果有任一没有加载完成
|
if !f.Our.Finished || !f.Opp.Finished { //如果有任一没有加载完成
|
||||||
f.closefight = true //阻止继续添加action
|
f.closefight = true //阻止继续添加action
|
||||||
f.Reason = info.BattleOverReason.PlayerOVerTime
|
f.Reason = info.BattleOverReason.PlayerOffline
|
||||||
switch {
|
switch {
|
||||||
case !f.Opp.Finished: //邀请方没加载完成 先判断邀请方,如果都没加载完成,就算做房主胜利
|
case !f.Opp.Finished: //邀请方没加载完成 先判断邀请方,如果都没加载完成,就算做房主胜利
|
||||||
f.WinnerId = f.Our.Player.GetInfo().UserID
|
f.WinnerId = f.Our.Player.GetInfo().UserID
|
||||||
|
|||||||
@@ -72,11 +72,14 @@ func (f *FightC) battleLoop() {
|
|||||||
//大乱斗,给个延迟
|
//大乱斗,给个延迟
|
||||||
<-time.After(500)
|
<-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.SendPackCmd(2506, &f.FightOverInfo)
|
||||||
|
|
||||||
ff.Player.QuitFight()
|
ff.Player.QuitFight()
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"blazing/common/data/xmlres"
|
"blazing/common/data/xmlres"
|
||||||
"blazing/common/utils"
|
|
||||||
"blazing/cool"
|
"blazing/cool"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
@@ -96,20 +97,85 @@ type PetInfo struct {
|
|||||||
// AbilityType uint32 `struc:"skip"` //特性
|
// AbilityType uint32 `struc:"skip"` //特性
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pet *PetInfo) ADD_EV(evadd []uint32) {
|
// 定义常量,提升可维护性(避免魔法数字)
|
||||||
var sum uint32
|
const (
|
||||||
for i := range pet.Ev {
|
maxSingleEV uint32 = 255 // 单个EV最大值
|
||||||
sum += pet.Ev[i]
|
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
|
// 2. 预计算:当前EV总和 + 增量后的临时值(先不修改原数据,避免边改边算)
|
||||||
for i := 0; i < 6; i++ {
|
var (
|
||||||
|
totalCurrent uint32 // 当前EV总和
|
||||||
pet.Ev[i] += evadd[i]
|
tempEV [evFieldCount]uint32 // 增量后的临时EV值(避免修改原数组导致计算错误)
|
||||||
pet.Ev[i] = utils.Min(pet.Ev[i], 255)
|
)
|
||||||
pet.Ev[i] = utils.Min(pet.Ev[i], cansum)
|
// 一次性遍历:计算当前总和 + 初始化临时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() {
|
func (pet *PetInfo) Cure() {
|
||||||
pet.Hp = pet.MaxHp
|
pet.Hp = pet.MaxHp
|
||||||
|
|||||||
Reference in New Issue
Block a user