From afb31bd79bceb7e3f996fd2a833e259ee627fc76 Mon Sep 17 00:00:00 2001 From: 1 <1@72wo.cn> Date: Sun, 21 Sep 2025 17:01:31 +0000 Subject: [PATCH] =?UTF-8?q?feat(pet):=20=E9=87=8D=E6=9E=84=E5=AE=A0?= =?UTF-8?q?=E7=89=A9=E5=B1=9E=E6=80=A7=E8=AE=A1=E7=AE=97=E4=B8=8E=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E5=AD=A6=E4=B9=A0=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/data/xmlres/pet.go | 56 +++++++++--------- logic/controller/pet.go | 51 ++++++++-------- logic/service/fight/fightc.go | 33 +++++------ logic/service/player/pet.go | 99 ++++++++++++++++++++++++++++++++ modules/blazing/model/pet.go | 77 +------------------------ modules/blazing/model/petinfo.go | 86 +++++++++++++++++++++++++++ 6 files changed, 260 insertions(+), 142 deletions(-) create mode 100644 logic/service/player/pet.go create mode 100644 modules/blazing/model/petinfo.go diff --git a/common/data/xmlres/pet.go b/common/data/xmlres/pet.go index 334d9f7a8..188d97051 100644 --- a/common/data/xmlres/pet.go +++ b/common/data/xmlres/pet.go @@ -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 表示所有怪物的集合 diff --git a/logic/controller/pet.go b/logic/controller/pet.go index 31e81621c..a24b7660e 100644 --- a/logic/controller/pet.go +++ b/logic/controller/pet.go @@ -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 +} diff --git a/logic/service/fight/fightc.go b/logic/service/fight/fightc.go index 1bfd7ff5c..6cf7cf81c 100644 --- a/logic/service/fight/fightc.go +++ b/logic/service/fight/fightc.go @@ -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{}) + } }) diff --git a/logic/service/player/pet.go b/logic/service/player/pet.go new file mode 100644 index 000000000..8ffaeb184 --- /dev/null +++ b/logic/service/player/pet.go @@ -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 +} diff --git a/modules/blazing/model/pet.go b/modules/blazing/model/pet.go index aa65c74dd..08ea7101f 100644 --- a/modules/blazing/model/pet.go +++ b/modules/blazing/model/pet.go @@ -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 { diff --git a/modules/blazing/model/petinfo.go b/modules/blazing/model/petinfo.go new file mode 100644 index 000000000..8d5d9ead2 --- /dev/null +++ b/modules/blazing/model/petinfo.go @@ -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 +}