feat(pet): 重构宠物属性计算与技能学习逻辑,优化代码结构
This commit is contained in:
@@ -4,8 +4,8 @@ import "github.com/ECUST-XX/xml"
|
||||
|
||||
// Move 表示怪物可学习的技能
|
||||
type PetMoves struct {
|
||||
ID int `xml:"ID,attr"`
|
||||
LearningLv int `xml:"LearningLv,attr"`
|
||||
ID uint32 `xml:"ID,attr"`
|
||||
LearningLv uint32 `xml:"LearningLv,attr"`
|
||||
}
|
||||
|
||||
// LearnableMoves 包含怪物可学习的技能列表
|
||||
@@ -16,31 +16,33 @@ type LearnableMoves struct {
|
||||
// PetInfo 表示一个怪物的信息
|
||||
type PetInfo struct {
|
||||
ID int `xml:"ID,attr"`
|
||||
DefName string `xml:"DefName,attr"` //名字
|
||||
Type int `xml:"Type,attr"` //类型
|
||||
GrowthType int `xml:"GrowthType,attr"` //成长类型
|
||||
HP int `xml:"HP,attr"` //血量种族值
|
||||
Atk uint32 `xml:"Atk,attr"` //攻击种族值
|
||||
Def uint32 `xml:"Def,attr"`
|
||||
SpAtk uint32 `xml:"SpAtk,attr"`
|
||||
SpDef uint32 `xml:"SpDef,attr"`
|
||||
Spd uint32 `xml:"Spd,attr"`
|
||||
YieldingExp int `xml:"YieldingExp,attr"`
|
||||
CatchRate string `xml:"CatchRate,attr"`
|
||||
YieldingEV string `xml:"YieldingEV,attr"`
|
||||
EvolvesFrom int `xml:"EvolvesFrom,attr"`
|
||||
EvolvesTo int `xml:"EvolvesTo,attr"`
|
||||
EvolvingLv int `xml:"EvolvingLv,attr"`
|
||||
FreeForbidden int `xml:"FreeForbidden,attr"`
|
||||
FuseMaster int `xml:"FuseMaster,attr"`
|
||||
FuseSub int `xml:"FuseSub,attr"`
|
||||
Gender int `xml:"Gender,attr"`
|
||||
PetClass int `xml:"PetClass,attr"`
|
||||
FormParam float64 `xml:"FormParam,attr"`
|
||||
CharacterAttrParam int `xml:"CharacterAttrParam,attr"`
|
||||
GradeParam float64 `xml:"GradeParam,attr"`
|
||||
AddSeParam int `xml:"AddSeParam,attr"`
|
||||
LearnableMoves LearnableMoves `xml:"LearnableMoves"`
|
||||
DefName string `xml:"DefName,attr"` // 名字
|
||||
Type int `xml:"Type,attr"` // 类型
|
||||
IsLarge int `xml:"IsLarge,attr"` // 是否为大型怪物
|
||||
GrowthType int `xml:"GrowthType,attr"` // 成长类型
|
||||
HP int `xml:"HP,attr"` // 血量种族值
|
||||
Atk uint32 `xml:"Atk,attr"` // 攻击种族值
|
||||
Def uint32 `xml:"Def,attr"` // 防御种族值
|
||||
SpAtk uint32 `xml:"SpAtk,attr"` // 特殊攻击种族值
|
||||
SpDef uint32 `xml:"SpDef,attr"` // 特殊防御种族值
|
||||
Spd uint32 `xml:"Spd,attr"` // 速度种族值
|
||||
YieldingExp int `xml:"YieldingExp,attr"` // 击败后获得的经验值
|
||||
CatchRate int `xml:"CatchRate,attr"` // 捕捉率
|
||||
YieldingEV string `xml:"YieldingEV,attr"` // 努力值奖励,格式为"HP Atk Def SpAtk SpDef Spd"
|
||||
EvolvesFrom int `xml:"EvolvesFrom,attr"` // 进化前的怪物ID
|
||||
EvolvesTo uint32 `xml:"EvolvesTo,attr"` // 进化后的怪物ID
|
||||
EvolvingLv int `xml:"EvolvingLv,attr"` // 进化等级
|
||||
FreeForbidden int `xml:"FreeForbidden,attr"` // 是否禁止放生
|
||||
FuseMaster int `xml:"FuseMaster,attr"` // 是否可作为融合主素材
|
||||
FuseSub int `xml:"FuseSub,attr"` // 是否可作为融合副素材
|
||||
Gender int `xml:"Gender,attr"` // 性别 0-无性别 1-雄性 2-雌性
|
||||
PetClass int `xml:"PetClass,attr"` // 宠物类别
|
||||
FormParam float64 `xml:"FormParam,attr"` // 形态参数
|
||||
CharacterAttrParam int `xml:"CharacterAttrParam,attr"` // 特性参数
|
||||
GradeParam int `xml:"GradeParam,attr"` // 等级参数
|
||||
AddSeParam int `xml:"AddSeParam,attr"` // 附加状态参数
|
||||
Recycle int `xml:"Recycle,attr"` // 是否可回收
|
||||
LearnableMoves LearnableMoves `xml:"LearnableMoves"` // 可学习的技能
|
||||
}
|
||||
|
||||
// Monsters 表示所有怪物的集合
|
||||
|
||||
@@ -114,34 +114,28 @@ func (h *Controller) PlayerShowPet(
|
||||
}
|
||||
func (h *Controller) PetOneCure(
|
||||
data *pet.PetOneCureInboundInfo, c *player.Player) (result *pet.PetOneCureOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
|
||||
result = &pet.PetOneCureOutboundInfo{
|
||||
data.CatchTime,
|
||||
}
|
||||
var temp []model.PetInfo
|
||||
|
||||
for _, pi := range c.Info.PetList {
|
||||
if pi.CatchTime == data.CatchTime {
|
||||
pi.Hp = pi.MaxHp
|
||||
// 恢复技能PP值
|
||||
var skillList [4]model.SkillInfo
|
||||
for i, skill := range pi.SkillList {
|
||||
// 跳过无效技能
|
||||
if skill.ID == 0 {
|
||||
continue
|
||||
}
|
||||
// 恢复至最大PP值(从配置表获取)
|
||||
if maxPP, ok := xmlres.SkillMap[int(skill.ID)]; ok {
|
||||
skill.PP = uint32(maxPP.MaxPP)
|
||||
skillList[i] = skill
|
||||
}
|
||||
_, onpet, ok := FindWithIndex(c.Info.PetList, func(item model.PetInfo) bool {
|
||||
return item.CatchTime == data.CatchTime
|
||||
})
|
||||
if ok {
|
||||
onpet.Hp = onpet.MaxHp
|
||||
for i := 0; i < 4; i++ {
|
||||
// 跳过无效技能
|
||||
if onpet.SkillList[i].ID == 0 {
|
||||
continue
|
||||
}
|
||||
// 恢复至最大PP值(从配置表获取)
|
||||
if maxPP, ok := xmlres.SkillMap[int(onpet.SkillList[i].ID)]; ok {
|
||||
onpet.SkillList[i].PP = uint32(maxPP.MaxPP)
|
||||
|
||||
}
|
||||
pi.SkillList = skillList
|
||||
}
|
||||
temp = append(temp, pi)
|
||||
}
|
||||
|
||||
c.Info.PetList = temp
|
||||
return result, 0
|
||||
return &pet.PetOneCureOutboundInfo{
|
||||
CatchTime: data.CatchTime,
|
||||
}, 0
|
||||
|
||||
}
|
||||
|
||||
@@ -165,3 +159,14 @@ func (h *Controller) PetFirst(
|
||||
return result, 0
|
||||
|
||||
}
|
||||
|
||||
// FindWithIndex 遍历slice,找到第一个满足条件的元素
|
||||
// 返回:索引、元素指针、是否找到
|
||||
func FindWithIndex[T any](slice []T, predicate func(item T) bool) (int, *T, bool) {
|
||||
for i := range slice {
|
||||
if predicate(slice[i]) {
|
||||
return i, &slice[i], true
|
||||
}
|
||||
}
|
||||
return -1, nil, false
|
||||
}
|
||||
|
||||
@@ -328,28 +328,25 @@ func (f *FightC) battleLoop() {
|
||||
tt, ok := ff.Player.(*player.Player)
|
||||
mo, ism := f.Opp.Player.(*player.AI_player)
|
||||
|
||||
if ok { //如果获取玩家
|
||||
if ok && ism && mo.CanCapture { //如果获取玩家
|
||||
|
||||
if ism && mo.CanCapture { //如果获取到IA
|
||||
ok, _ := f.Our.Capture(f.Opp.CurrentPet, faction.ItemID, -1)
|
||||
if ok { //todo 待补充
|
||||
tt.Service.PetAdd(*f.Opp.CurrentPet.Info)
|
||||
tt.CatchPetInfo(info.CatchMonsterOutboundInfo{
|
||||
CatchTime: uint32(f.Opp.CurrentPet.Info.CatchTime),
|
||||
PetId: uint32(f.Opp.CurrentPet.ID),
|
||||
})
|
||||
ff.Player.SendFightEndInfo(info.FightOverInfo{
|
||||
|
||||
ok, _ := f.Our.Capture(f.Opp.CurrentPet, faction.ItemID, -1)
|
||||
if ok { //todo 待补充
|
||||
tt.Service.PetAdd(*f.Opp.CurrentPet.Info)
|
||||
tt.CatchPetInfo(info.CatchMonsterOutboundInfo{
|
||||
CatchTime: uint32(f.Opp.CurrentPet.Info.CatchTime),
|
||||
PetId: uint32(f.Opp.CurrentPet.ID),
|
||||
})
|
||||
ff.Player.SendFightEndInfo(info.FightOverInfo{
|
||||
|
||||
WinnerId: f.ownerID,
|
||||
})
|
||||
f.closefight = true
|
||||
}
|
||||
|
||||
} else { //说明不是可以捕捉的
|
||||
tt.CatchPetInfo(info.CatchMonsterOutboundInfo{})
|
||||
WinnerId: f.ownerID,
|
||||
})
|
||||
f.closefight = true
|
||||
}
|
||||
|
||||
} else { //说明不是可以捕捉的
|
||||
tt.CatchPetInfo(info.CatchMonsterOutboundInfo{})
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
99
logic/service/player/pet.go
Normal file
99
logic/service/player/pet.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"blazing/common/data/xmlres"
|
||||
"blazing/modules/blazing/model"
|
||||
"math"
|
||||
)
|
||||
|
||||
// calculateExperience 根据公式计算指定等级所需的经验值
|
||||
func calculateExperience(level uint32) uint32 {
|
||||
var x float64
|
||||
// 判断等级奇偶性确定x的值
|
||||
if level%2 == 1 { // 奇数
|
||||
x = 0.5
|
||||
} else { // 偶数
|
||||
x = -0.5
|
||||
}
|
||||
|
||||
// 应用公式计算
|
||||
lvFloat := float64(level)
|
||||
experience := 3.75*lvFloat*lvFloat + 3.75*lvFloat + 1 + x
|
||||
|
||||
// 四舍五入为整数
|
||||
return uint32(math.Round(experience))
|
||||
}
|
||||
|
||||
// 主函数实现
|
||||
// 添加经验
|
||||
// 超NO 加成
|
||||
func (p *Player) AddPetExp(pet *model.PetInfo, addExp uint32) {
|
||||
originalLevel := pet.Level
|
||||
for {
|
||||
needExp := calculateExperience(pet.Level)
|
||||
|
||||
if addExp >= needExp {
|
||||
addExp -= needExp
|
||||
pet.Level++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
pet.Exp = addExp
|
||||
pet.NextLvExp = calculateExperience(pet.Level)
|
||||
pet.LvExp = pet.NextLvExp - pet.Exp
|
||||
// 处理进化逻辑
|
||||
for {
|
||||
|
||||
basic := xmlres.PetMAP[int(pet.ID)]
|
||||
// 检查是否可以进化
|
||||
if basic.EvolvesTo == 0 ||
|
||||
basic.EvolvingLv == 0 ||
|
||||
basic.EvolvingLv >= int(pet.Level) ||
|
||||
basic.IsLarge != 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// 获取进化后的资产
|
||||
|
||||
pet.ID = uint32(basic.EvolvesTo)
|
||||
}
|
||||
|
||||
// 重新计算面板
|
||||
pet.CalculatePetPane()
|
||||
// 发送经验更新消息
|
||||
//player.SendMessage(generatePetUpdateInfo(petEntity, originalExp+addExp-exp, addition))
|
||||
|
||||
// 处理技能学习
|
||||
canLearnSkillList := model.LastFourElements(pet.GetLevelRangeCanLearningSkills(originalLevel, pet.Level)) //获取最后四个技能,如果不足,那就取全部技能
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
|
||||
if pet.SkillList[i].ID == 0 {
|
||||
if len(canLearnSkillList) != 0 {
|
||||
skid := canLearnSkillList[len(canLearnSkillList)-1]
|
||||
pet.SkillList[i].ID = skid
|
||||
pet.SkillList[i].PP = uint32(xmlres.SkillMap[int(skid)].MaxPP)
|
||||
canLearnSkillList = append([]uint32{}, canLearnSkillList[:len(canLearnSkillList)-1]...)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//todo 待实现
|
||||
// // 发送技能更新消息
|
||||
// updateSkillInfo := UpdateSkillInfo{
|
||||
// PetCatchTime: petEntity.captureTime,
|
||||
// ActiveSkillNum: activeSkillNum,
|
||||
// UnActiveSkillNum: unActiveSkillNum,
|
||||
// SkillArray: canLearnSkillList,
|
||||
// }
|
||||
|
||||
// player.SendMessage(UpdateSkillOutboundInfo{
|
||||
// InfoArray: []UpdateSkillInfo{updateSkillInfo},
|
||||
// })
|
||||
|
||||
// return exp
|
||||
}
|
||||
@@ -84,8 +84,6 @@ func GenPetInfo(id int, dv, natureId, abilityTypeEnum, shinyid, level int) *PetI
|
||||
CatchTime: uint32(time.Now().Unix()),
|
||||
Level: uint32(level)} //等级
|
||||
|
||||
naxml := xmlres.NatureRootMap[int(p.Nature)]
|
||||
petxml := xmlres.PetMAP[int(id)]
|
||||
if shinyid != -1 {
|
||||
p.Shiny = uint32(shinyid)
|
||||
} else {
|
||||
@@ -127,89 +125,20 @@ func GenPetInfo(id int, dv, natureId, abilityTypeEnum, shinyid, level int) *PetI
|
||||
}
|
||||
|
||||
}
|
||||
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) //获取最后四个技能,如果不足,那就取全部技能
|
||||
tttt := LastFourElements(p.GetLevelRangeCanLearningSkills(0, p.Level)) //获取最后四个技能,如果不足,那就取全部技能
|
||||
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,
|
||||
)
|
||||
// * battle_lv: atk(0), def(1), sp_atk(2), sp_def(3), spd(4), accuracy(5)
|
||||
p.Prop[0] = p.CalculatePetPanelSize(
|
||||
uint32(petxml.Atk),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvAttack,
|
||||
naxml.AttackCorrect,
|
||||
)
|
||||
|
||||
p.Prop[1] = p.CalculatePetPanelSize(
|
||||
uint32(petxml.Def),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvDefence,
|
||||
naxml.DefenseCorrect,
|
||||
)
|
||||
|
||||
p.Prop[2] = p.CalculatePetPanelSize(
|
||||
uint32(petxml.SpAtk),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvSpecialAttack,
|
||||
naxml.SaCorrect,
|
||||
)
|
||||
|
||||
p.Prop[3] = p.CalculatePetPanelSize(
|
||||
uint32(petxml.SpDef),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvSpecialDefense,
|
||||
naxml.SdCorrect,
|
||||
)
|
||||
|
||||
p.Prop[4] = p.CalculatePetPanelSize(
|
||||
uint32(petxml.Spd),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvSpeed,
|
||||
naxml.SpeedCorrect,
|
||||
)
|
||||
|
||||
// 设置计算结果
|
||||
p.MaxHp = hp
|
||||
p.Hp = hp
|
||||
p.CalculatePetPane()
|
||||
p.Hp = p.MaxHp
|
||||
|
||||
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 {
|
||||
|
||||
|
||||
86
modules/blazing/model/petinfo.go
Normal file
86
modules/blazing/model/petinfo.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package model
|
||||
|
||||
import "blazing/common/data/xmlres"
|
||||
|
||||
// 实现获取等级范围内可学习的技能
|
||||
func (p *PetInfo) GetLevelRangeCanLearningSkills(from, to uint32) []uint32 {
|
||||
|
||||
var skills []uint32
|
||||
|
||||
for _, skillIDs := range xmlres.PetMAP[int(p.ID)].LearnableMoves.Moves {
|
||||
|
||||
if skillIDs.LearningLv >= from && skillIDs.LearningLv <= to {
|
||||
skills = append(skills, skillIDs.ID)
|
||||
}
|
||||
}
|
||||
return skills
|
||||
}
|
||||
|
||||
// 计算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)
|
||||
}
|
||||
|
||||
// 计算生成面板
|
||||
func (p *PetInfo) CalculatePetPane() {
|
||||
naxml := xmlres.NatureRootMap[int(p.Nature)]
|
||||
petxml := xmlres.PetMAP[int(p.ID)]
|
||||
// 计算各项属性
|
||||
hp := p.calculatePetHPPanelSize(
|
||||
uint32(petxml.HP),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvHp,
|
||||
)
|
||||
// * battle_lv: atk(0), def(1), sp_atk(2), sp_def(3), spd(4), accuracy(5)
|
||||
p.Prop[0] = p.calculatePetPanelSize(
|
||||
uint32(petxml.Atk),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvAttack,
|
||||
naxml.AttackCorrect,
|
||||
)
|
||||
|
||||
p.Prop[1] = p.calculatePetPanelSize(
|
||||
uint32(petxml.Def),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvDefence,
|
||||
naxml.DefenseCorrect,
|
||||
)
|
||||
|
||||
p.Prop[2] = p.calculatePetPanelSize(
|
||||
uint32(petxml.SpAtk),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvSpecialAttack,
|
||||
naxml.SaCorrect,
|
||||
)
|
||||
|
||||
p.Prop[3] = p.calculatePetPanelSize(
|
||||
uint32(petxml.SpDef),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvSpecialDefense,
|
||||
naxml.SdCorrect,
|
||||
)
|
||||
|
||||
p.Prop[4] = p.calculatePetPanelSize(
|
||||
uint32(petxml.Spd),
|
||||
p.Dv,
|
||||
p.Level,
|
||||
p.EvSpeed,
|
||||
naxml.SpeedCorrect,
|
||||
)
|
||||
|
||||
// 设置计算结果
|
||||
p.MaxHp = hp
|
||||
}
|
||||
Reference in New Issue
Block a user