Files
bl/modules/blazing/model/pet.go
昔念 72e6b8c706 refactor(fight): 重构战斗系统效果处理逻辑
- 移除 Effect0 基类效果
- 调整 Input 结构,删除未使用的属性
- 优化 Effect 接口,增加 GetMaxStack 方法
- 重构效果初始化逻辑,支持不同类型效果的初始化
- 优化效果的添加和移除操作
- 调整宠物效果信息结构,合并参数
2025-09-16 22:51:22 +08:00

323 lines
9.3 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 model
import (
"blazing/common/data/xmlres"
"blazing/cool"
"math"
"math/rand"
"time"
)
const TableNamePet = "pet"
// Pet mapped from table <pet>
type Pet struct {
*cool.Model
PlayerID uint32 `gorm:"not null;index:idx_pet_by_player_id;comment:'所属玩家ID'" json:"player_id"`
InBag int `gorm:"not null;comment:'是否在背包中'" json:"in_bag"` //"0为放入仓库1为放入背包
CatchTime uint32 `gorm:"not null;comment:'捕捉时间'" json:"catch_time"`
// Owner uint32 `struc:"skip"` //仅作为存储
// FreedTime uint32 `struc:"skip"` //放生时间
//是否可交易这里应该定义在精灵ID里
//是否上架
Data string `gorm:"type:text;not null;comment:'精灵全部数据'" json:"data"`
}
func GetGaussRandomNum(min, max int64) int64 {
σ := (float64(min) + float64(max)) / 2
μ := (float64(max) - σ) / 3
rand.Seed(time.Now().UnixNano())
x := rand.Float64()
x1 := rand.Float64()
a := math.Cos(2*math.Pi*x) * math.Sqrt((-2)*math.Log(x1))
result := a*μ + σ
return int64(result)
}
// RandomInRange 从切片表示的范围中返回对应结果:
// - 切片包含1个元素时返回该元素本身
// - 切片包含2个元素时从[min, max]闭区间随机生成一个整数自动调整min和max顺序
// - 其他情况返回0
func RandomInRange(rangeSlice []int) int {
rand.Seed(time.Now().UnixNano())
switch len(rangeSlice) {
case 1:
// 只有一个元素时返回自身
return rangeSlice[0]
case 2:
// 两个元素时处理为范围
min, max := rangeSlice[0], rangeSlice[1]
// 确保 min ≤ max
if min > max {
min, max = max, min
}
// 生成 [min, max] 区间的随机整数
return int(GetGaussRandomNum(int64(min), int64(max))) //(rand.Intn(int(max-min+1)) + int(min))
default:
// 其他长度返回0
return 0
}
}
func LastFourElements[T any](s []T) []T {
n := len(s)
if n <= 4 {
// 切片长度小于等于4时返回整个切片
return s
}
// 切片长度大于4时返回最后4个元素从n-4索引到末尾
return s[n-4:]
}
// * @param petTypeId 精灵类型ID
// * @param individualValue 个体值
// * @param natureId 性格ID
// * @param abilityTypeEnum 特性类型
// * @param isShiny 是否为闪光
// * @param level 等级
// * @return 生成的精灵实体
func GenPetInfo(id int, dv, natureId, abilityTypeEnum, shinyid, level []int) *PetInfo {
p := &PetInfo{ID: uint32(id),
Shiny: uint32(RandomInRange(shinyid)), //闪光
Nature: uint32(RandomInRange(natureId)), //性格
Dv: uint32(RandomInRange(dv)),
EffectInfo: make([]PetEffectInfo, 0),
CatchTime: uint32(time.Now().Unix()),
Level: uint32(RandomInRange(level))} //等级
p.EffectInfo = append(p.EffectInfo, PetEffectInfo{
EID: 28,
})
naxml := xmlres.NatureRootMap[int(p.Nature)]
petxml := xmlres.PetMAP[int(id)]
p.EffectInfo[0].Args = []int{petxml.Type, 5} //默认等级1
tttt := make([]uint32, 0)
for _, v := range petxml.LearnableMoves.Moves {
if p.Level >= uint32(v.LearningLv) {
tttt = append(tttt, uint32(v.ID))
}
}
tttt = LastFourElements(tttt) //获取最后四个技能,如果不足,那就取全部技能
for i := 0; i < len(tttt); i++ {
p.SkillList[i].ID = tttt[i]
p.SkillList[i].PP = uint32(xmlres.SkillMap[int(tttt[i])].MaxPP)
}
p.SkillListLen = uint32(len(tttt))
// 计算各项属性
hp := p.CalculatePetHPPanelSize(
uint32(petxml.HP),
p.Dv,
p.Level,
p.EvHp,
)
attack := p.CalculatePetPanelSize(
uint32(petxml.Atk),
p.Dv,
p.Level,
p.EvAttack,
naxml.AttackCorrect,
)
defense := p.CalculatePetPanelSize(
uint32(petxml.Def),
p.Dv,
p.Level,
p.EvDefence,
naxml.DefenseCorrect,
)
specialAttack := p.CalculatePetPanelSize(
uint32(petxml.SpAtk),
p.Dv,
p.Level,
p.EvSpecialAttack,
naxml.SaCorrect,
)
specialDefense := p.CalculatePetPanelSize(
uint32(petxml.SpDef),
p.Dv,
p.Level,
p.EvSpecialDefense,
naxml.SdCorrect,
)
speed := p.CalculatePetPanelSize(
uint32(petxml.Spd),
p.Dv,
p.Level,
p.EvSpeed,
naxml.SpeedCorrect,
)
// 设置计算结果
p.MaxHp = hp
p.Hp = hp
p.Attack = attack
p.Defence = defense
p.SpecialAttack = specialAttack
p.SpecialDefence = specialDefense
p.Speed = speed
return p
}
// 计算HP面板值无性格修正
func (c *PetInfo) CalculatePetHPPanelSize(base, dv, level, ev uint32) uint32 {
return uint32((float64(base)*2+float64(ev)/4.0+float64(dv))*(float64(level)/100.0) + float64(level) + 10)
}
// 计算其他属性面板值(带性格修正)
func (c *PetInfo) CalculatePetPanelSize(base, dv, level, ev uint32, natureCorrect float64) uint32 {
base1 := float64((float64(base)*2+float64(ev)/4.0+float64(dv))*(float64(level)/100.0) + 5)
return uint32(float64(base1) * natureCorrect)
}
// PetInfo 精灵信息结构(合并后的优化版本)
type PetInfo struct {
// 精灵编号(@UInt long → uint32
ID uint32 `fieldDesc:"精灵编号" `
// 名字默认为全0补齐到16字节固定长度 → [16]byte
Name string `struc:"[16]byte" `
// 个体值(@UInt long → uint32
Dv uint32 `fieldDesc:"个体值" `
// 性格(@UInt long → uint32
Nature uint32 `fieldDesc:"性格" `
// 等级(@UInt long → uint32
Level uint32 `fieldDesc:"等级" `
// 当前等级已获得经验(@UInt long → uint32
Exp uint32 `fieldDesc:"当前等级已经获得的经验 2538" `
// 当前等级所需经验(@UInt long → uint32
LvExp uint32 `fieldDesc:"当前等级所需的经验" `
// 升到下一级的经验(@UInt long → uint32
NextLvExp uint32 `fieldDesc:"升到下一级的经验" `
// 当前生命(@UInt long → uint32
Hp uint32 `fieldDesc:"当前生命" `
// 最大生命(@UInt long → uint32
MaxHp uint32 `fieldDesc:"最大生命" `
// 攻击(@UInt long → uint32
Attack uint32 `fieldDesc:"攻击" `
// 防御(@UInt long → uint32
Defence uint32 `fieldDesc:"防御" `
// 特攻(@UInt long → uint32
SpecialAttack uint32 `fieldDesc:"特攻" `
// 特防(@UInt long → uint32
SpecialDefence uint32 `fieldDesc:"特防" `
// 速度(@UInt long → uint32
Speed uint32 `fieldDesc:"速度" `
// 生命学习力(@UInt long → uint32
EvHp uint32 `fieldDesc:"生命学习力" `
// 攻击学习力(@UInt long → uint32
EvAttack uint32 `fieldDesc:"攻击学习力" `
// 防御学习力(@UInt long → uint32
EvDefence uint32 `fieldDesc:"防御学习力" `
// 特攻学习力(@UInt long → uint32
EvSpecialAttack uint32 `fieldDesc:"特攻学习力" `
// 特防学习力(@UInt long → uint32注意原Java拼写evSpecialDefense
EvSpecialDefense uint32 `fieldDesc:"特防学习力" `
// 速度学习力(@UInt long → uint32
EvSpeed uint32 `fieldDesc:"速度学习力" `
SkillListLen uint32
// 技能信息固定4条空则赋值0固定长度List → [4]SkillInfo零值即符合“赋值0”
SkillList [4]SkillInfo
// 捕捉时间(@UInt long → 若为时间戳用uint32若需时间类型可改为time.Time需配合序列化处理
CatchTime uint32 `fieldDesc:"捕捉时间" `
// 捕捉地图(@UInt long → uint32
CatchMap uint32 `fieldDesc:"捕捉地图" `
// 未知默认0@UInt long → uint32
CatchRect uint32 `fieldDesc:"未知默认为0" `
// 捕获等级默认0@UInt long → uint32
CatchLevel uint32 `fieldDesc:"捕获等级 默认为0" `
EffectInfoLen uint16 `struc:"sizeof=EffectInfo"`
// 特性列表长度用UShort存储变长List → []PetEffectInfo + 长度前缀规则)
EffectInfo []PetEffectInfo `fieldDesc:"特性列表, 长度在头部以UShort存储" serialize:"lengthFirst,lengthType=uint16,type=structArray"`
// 皮肤ID默认0@UInt long → uint32
SkinID uint32 `fieldDesc:"皮肤id默认为0" `
// 是否闪光(@UInt long → uint320=否1=是)
Shiny uint32 `fieldDesc:"是不是闪" `
// AbilityType uint32 `struc:"skip"` //特性
}
// PetEffectInfo 精灵特性信息结构
// <!-- NewSeIdx: 精灵特效索引 (默认0: 无效) -->
// <!-- Type: 0 - 仅单人战斗; 1 - 仅组队战斗; 2 - both; (默认0: 仅单人) -->
// <!-- Eid: 精灵特效eid (默认0: 无效) -->
// <!-- Stat: 精灵特效Stat: 0: 无效(默认值), 1: 永久, 2: 有`有效次数'的特效 3: 爆发特效 4: 异能精灵特质-->
// <!-- Times: 精灵特效可使用次数: 当type==2时有效 (默认值:0) -->
// <!-- Args: 特效参数, 不超过8个 (注意: 每个参数不能超过 65535) -->
// <!-- AdditionType:特效加成类型 1 种族值加成 2 技能威力加成 -->
type PetEffectInfo struct {
ItemID uint32 `struc:"uint32" json:"item_id"` //如果是能量珠,就显示
Status byte `struc:"byte" json:"status"` //特性为1,能量珠为2
LeftCount byte `struc:"byte" json:"left_count"` //剩余次数
EID uint16 `struc:"uint16" json:"effect_id"` //特效ID
ArgsLen uint32 `struc:"sizeof=Args"`
Args []int ` json:"Args"` //自定义参数装载
}
// SkillInfo 精灵技能信息结构SkillInfo
type SkillInfo struct {
ID uint32
PP uint32
}
// TableName Pet's table name
func (*Pet) TableName() string {
return TableNamePet
}
// GroupName Pet's table group
func (*Pet) GroupName() string {
return "default"
}
// NewPet create a new Pet
func NewPet() *Pet {
return &Pet{
Model: cool.NewModel(),
}
}
// init 创建表
func init() {
_ = cool.CreateTable(&Pet{})
// fmt.Println(err)
}