新增 PlayerExp 控制器方法,用于返回玩家的累计经验值。同时调整了经验池字段类型为 uint32 并修复相关使用逻辑。 feat(pet): 实现宠物经验增加与升级逻辑 在 Player 结构体中新增 AddPetExp 方法,支持宠物经验增长、自动升级及进化判断。升级后会重新计算面板属性并推送更新包。 feat(fight): 重构战斗伤害计算与效果系统 引入 DamageZone 和 EnumDamageType 类型,统一红伤处理流程;移除旧有的 Pet/Skill/Prop 属性获取临时修改机制,改为直接访问真实属性。更新多个技能效果实现以适配新结构。 refactor(effect): 优化技能效果初始化和生命周期方法 统一技能效果初始化方式,明确各阶段回调函数职责,如 PreActionStart、PreAttacked 等。删除已废弃的属性修改钩子函数,并更新状态类效果实现。 refactor(input): 移除 deepcopy 依赖并替换为 go-deepcopy 将原先使用的 mohae/deepcopy 替换为 barkimedes/go-deepcopy,用于战斗节点中的 effect 拷贝逻辑,提升性能和安全性。 refactor(model): 调整玩家信息字段类型 将 PlayerInfo 中的 GoldBean 字段由 int32 改为 uint32,ExpPool 字段由 int64 改为 uint32,确保数据类型一致性与合理性。 feat(nono): 增加 Nono 跟随/收回协议结构定义 新增 NonoFollowOrHomeInInfo 和 NonoFollowOutInfo 结构体,用于处理 Nono 宠物的跟随与收回操作指令。 chore(deps): 添加 go-deepcopy 依赖 在 go.mod 中引入 github.com/barkimedes/go-deepcopy 依赖库,用于替代原有的 deepcopy 工具。
199 lines
5.7 KiB
Go
199 lines
5.7 KiB
Go
package input
|
||
|
||
import (
|
||
"blazing/common/utils"
|
||
"blazing/logic/service/common"
|
||
"blazing/logic/service/fight/info"
|
||
"fmt"
|
||
"math"
|
||
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
"github.com/jinzhu/copier"
|
||
)
|
||
|
||
type Input struct {
|
||
CanChange bool //是否可以死亡切换CanChange
|
||
CurrentPet *info.BattlePetEntity //当前精灵
|
||
AllPet []*info.BattlePetEntity
|
||
Player common.PlayerI
|
||
Finished bool //是否加载完成
|
||
*info.AttackValue
|
||
FightC common.FightI
|
||
// info.BattleActionI
|
||
Effects *utils.OrderedMap[int, Effect] //effects 实际上全局就是effect无限回合 //effects容器 技能的
|
||
DamageZone map[info.EnumDamageType]int //伤害容器
|
||
First bool //是否先手
|
||
}
|
||
|
||
func NewInput(c common.FightI, p common.PlayerI) *Input {
|
||
ret := &Input{FightC: c, Player: p}
|
||
ret.Effects = utils.NewOrderedMap[int, Effect]()
|
||
ret.DamageZone = make(map[info.EnumDamageType]int)
|
||
// t := Geteffect(EffectType.Damage, 0)
|
||
// t.Effect.SetArgs(ret)
|
||
// ret.AddEffect(t) //添加默认基类,实现继承
|
||
p.SetFightC(c) //给玩家设置战斗容器
|
||
|
||
return ret
|
||
|
||
}
|
||
func (i *Input) GetPetInfo() *info.BattlePetEntity {
|
||
|
||
return i.CurrentPet
|
||
|
||
}
|
||
|
||
// 这个每回合都会调用
|
||
func (i *Input) InitAttackValue() {
|
||
i.AttackValue = info.NewAttackValue(i.Player.GetInfo().UserID)
|
||
|
||
}
|
||
func (i *Input) GetPet(id uint32) (ii *info.BattlePetEntity, Reason info.ChangePetInfo) {
|
||
for _, v := range i.AllPet {
|
||
if v.Info.CatchTime == uint32(id) {
|
||
copier.Copy(&Reason, &v.Info)
|
||
Reason.UserId = i.Player.GetInfo().UserID
|
||
|
||
ii = v
|
||
}
|
||
|
||
}
|
||
return
|
||
|
||
}
|
||
|
||
// GetStatusBonus 获取最高的状态倍率
|
||
// 遍历状态数组,返回存在的状态中最高的倍率(无状态则返回1.0)
|
||
func (i *Input) GetStatusBonus() float64 {
|
||
// 异常状态倍率映射表(状态索引 -> 倍率)
|
||
var statusBonuses = map[info.EnumBattleStatus]float64{
|
||
info.PetStatus.Paralysis: 1.5,
|
||
info.PetStatus.Poisoned: 1.5,
|
||
info.PetStatus.Sleep: 2.0,
|
||
// /info.BattleStatus.Frozen: 2.0,
|
||
}
|
||
maxBonus := 1.0 // 默认无状态倍率
|
||
|
||
for statusIdx := 0; statusIdx < 20; statusIdx++ {
|
||
t := Geteffect(EffectType.Status, statusIdx)
|
||
|
||
// 检查状态是否存在(数组中值为1表示存在该状态)
|
||
if t.ID != 0 && t.Effect.Stack() > 0 {
|
||
if bonus, exists := statusBonuses[info.EnumBattleStatus(statusIdx)]; exists && bonus > maxBonus {
|
||
maxBonus = bonus
|
||
}
|
||
}
|
||
}
|
||
|
||
return maxBonus
|
||
}
|
||
|
||
// 特殊胶囊必定成功
|
||
// CaptureParams 捕捉参数
|
||
// type CaptureParams struct {
|
||
// PetID int // 精灵ID
|
||
// MaxHP int // 目标最大HP
|
||
// CurrentHP int // 目标当前HP
|
||
// CatchRate int // 目标捕获率分子
|
||
// CatchDenom int // 捕获率分母(如100、1000)
|
||
// ItemID int // 使用的道具ID
|
||
// Statuses [20]byte // 异常状态数组,存在的状态对应位置为1
|
||
// OwnedCount int // 已拥有数量(-1=保底,0=锁定,≥1=衰减)
|
||
|
||
// -1是保底模式,0是锁定模式,》0是衰减模式
|
||
// Capture 执行捕捉 ,捕捉精灵,使用的道具,模式
|
||
func (c *Input) Capture(pet *info.BattlePetEntity, ItemID uint32, ownerpet int) (bool, CaptureDetails) {
|
||
|
||
if getItemBonus(ItemID) >= 255 {
|
||
return true, CaptureDetails{
|
||
Success: true,
|
||
Mode: "特殊胶囊必定成功",
|
||
BaseRate: 100.0,
|
||
ModifiedRate: 100.0,
|
||
GuaranteeBonus: 0,
|
||
StatusBonus: c.GetStatusBonus(),
|
||
Details: fmt.Sprintf("道具ID=%d,必定成功", ItemID),
|
||
}
|
||
}
|
||
|
||
// 锁定模式
|
||
if ownerpet == 0 {
|
||
return false, CaptureDetails{
|
||
Success: false,
|
||
Mode: "锁定模式",
|
||
BaseRate: 0,
|
||
ModifiedRate: 0,
|
||
GuaranteeBonus: 0,
|
||
StatusBonus: c.GetStatusBonus(),
|
||
Details: "已拥有数量为0,无法捕捉",
|
||
}
|
||
}
|
||
|
||
// 计算基础捕捉率
|
||
baseRate := c.calcBaseRate(pet, ItemID)
|
||
denominator := c.Player.GetPlayerCaptureContext().Denominator
|
||
numerator := int(baseRate * float64(denominator))
|
||
|
||
// 衰减模式
|
||
if ownerpet > 0 {
|
||
decay := math.Pow(1-c.Player.GetPlayerCaptureContext().DecayFactor, float64(ownerpet))
|
||
baseRate *= decay
|
||
if baseRate < 0.01 {
|
||
baseRate = 0.01 // 最低1%成功率
|
||
}
|
||
numerator = int(baseRate * float64(denominator))
|
||
}
|
||
|
||
// 走统一保底判定
|
||
success, basePct, bonusPct := c.Player.Roll(numerator, denominator)
|
||
|
||
return success, CaptureDetails{
|
||
Success: success,
|
||
Mode: map[int]string{-1: "保底模式", 0: "锁定模式", 1: "衰减模式"}[ownerpet],
|
||
BaseRate: basePct,
|
||
ModifiedRate: basePct + bonusPct,
|
||
GuaranteeBonus: bonusPct,
|
||
StatusBonus: c.GetStatusBonus(),
|
||
Details: fmt.Sprintf("a=%d, 分子=%d, 分母=%d", c.calcBaseA(pet, ItemID), numerator, denominator),
|
||
}
|
||
}
|
||
|
||
// calcBaseA 按公式计算a值
|
||
func (c *Input) calcBaseA(pet *info.BattlePetEntity, ItemID uint32) int {
|
||
catchRate := gconv.Int(pet.CatchRate)
|
||
catchRate = (catchRate * c.Player.GetPlayerCaptureContext().Denominator) / 1000 // 归一化到1000分母
|
||
if catchRate < 3 {
|
||
catchRate = 3
|
||
}
|
||
|
||
currentHP := pet.Info.Hp
|
||
if currentHP <= 0 {
|
||
currentHP = 1
|
||
}
|
||
|
||
hpRatio := (3.0*float64(pet.Info.MaxHp) - 2.0*float64(currentHP)) / (3.0 * float64(pet.Info.MaxHp))
|
||
if hpRatio < 0 {
|
||
hpRatio = 0
|
||
}
|
||
|
||
itemBonus := getItemBonus(ItemID)
|
||
statusBonus := c.GetStatusBonus()
|
||
|
||
return int(hpRatio * float64(catchRate) * itemBonus * statusBonus)
|
||
}
|
||
|
||
// calcBaseRate 按公式计算基础成功率
|
||
func (c *Input) calcBaseRate(pet *info.BattlePetEntity, ItemID uint32) float64 {
|
||
if getItemBonus(ItemID) >= 255 {
|
||
return 1.0
|
||
}
|
||
|
||
a := c.calcBaseA(pet, ItemID)
|
||
if a >= 255 {
|
||
return 1.0
|
||
}
|
||
|
||
g := int(1048560.0 / math.Floor(math.Sqrt(math.Floor(math.Sqrt(math.Floor(16711680.0/float64(a)))))))
|
||
return math.Pow(float64(g)/65536.0, 4.0)
|
||
}
|