feat(pet): 新增精灵可学习技能查询功能

新增 GetPetLearnableSkills 接口用于查询当前精灵可学习技能(包含等级技能和额外技能ExtSKill),
优化 SetPetSkill 和 SortPetSkills 方法中的技能处理逻辑,提升技能管理和排序的准确性。

同时修复了宠物存储信息查询时缺少参数验证的问题,在管理后台接口中增加 free 参数支持。

BREAKING CHANGE: 管理后台
This commit is contained in:
昔念
2026-04-05 12:45:00 +08:00
parent c3da3162ee
commit 3ee1283a2c
4 changed files with 136 additions and 29 deletions

View File

@@ -80,6 +80,12 @@ type C2S_Skill_Sort struct {
Skill [4]uint32 `json:"skill_1"`
}
// GetPetLearnableSkillsInboundInfo 查询当前精灵可学习技能含额外技能ExtSKill
type GetPetLearnableSkillsInboundInfo struct {
Head common.TomeeHeader `cmd:"52312" struc:"skip"`
CatchTime uint32 `json:"catchTime"`
}
type C2S_PetFusion struct {
Head common.TomeeHeader `cmd:"2351" struc:"skip"`
Mcatchtime uint32 `json:"mcatchtime" msgpack:"mcatchtime"`

View File

@@ -8,10 +8,63 @@ import (
"blazing/logic/service/pet"
"blazing/logic/service/player"
"blazing/modules/player/model"
"github.com/samber/lo"
)
type GetPetLearnableSkillsOutboundInfo struct {
SkillListLen uint32 `struc:"sizeof=SkillList"`
SkillList []uint32 `json:"skillList"`
}
func collectPetLearnableSkillList(currentPet *model.PetInfo) []uint32 {
skillSet := make(map[uint32]struct{})
skills := make([]uint32, 0)
appendSkill := func(skillID uint32) {
if skillID == 0 {
return
}
if _, exists := skillSet[skillID]; exists {
return
}
skillSet[skillID] = struct{}{}
skills = append(skills, skillID)
}
for _, skillID := range currentPet.GetLevelRangeCanLearningSkills(1, currentPet.Level) {
appendSkill(skillID)
}
for _, skillID := range currentPet.ExtSKill {
appendSkill(skillID)
}
for _, skill := range currentPet.SkillList {
delete(skillSet, skill.ID)
}
result := make([]uint32, 0, len(skillSet))
for _, skillID := range skills {
if _, exists := skillSet[skillID]; exists {
result = append(result, skillID)
}
}
return result
}
// GetPetLearnableSkills 查询当前精灵可学习技能(等级技能 + 额外技能ExtSKill
func (h Controller) GetPetLearnableSkills(
data *GetPetLearnableSkillsInboundInfo,
c *player.Player,
) (result *GetPetLearnableSkillsOutboundInfo, err errorcode.ErrorCode) {
_, currentPet, ok := c.FindPet(data.CatchTime)
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
return &GetPetLearnableSkillsOutboundInfo{
SkillList: collectPetLearnableSkillList(currentPet),
}, 0
}
// SetPetSkill 设置宠物技能消耗50赛尔豆
func (h Controller) SetPetSkill(data *ChangeSkillInfo, c *player.Player) (result *pet.ChangeSkillOutInfo, err errorcode.ErrorCode) {
const setSkillCost = 50
@@ -26,15 +79,20 @@ func (h Controller) SetPetSkill(data *ChangeSkillInfo, c *player.Player) (result
if !ok {
return nil, errorcode.ErrorCodes.ErrSystemBusy
}
canleaernskill := currentPet.GetLevelRangeCanLearningSkills(1, currentPet.Level)
_, ok = lo.Find(canleaernskill, func(item uint32) bool {
return item == data.ReplaceSkill
})
if !ok {
return result, errorcode.ErrorCodes.ErrSystemBusy
canLearnSkillSet := make(map[uint32]struct{})
for _, skillID := range collectPetLearnableSkillList(currentPet) {
canLearnSkillSet[skillID] = struct{}{}
}
if _, exists := canLearnSkillSet[data.ReplaceSkill]; !exists {
return nil, errorcode.ErrorCodes.ErrSystemBusy
}
skillInfo, exists := xmlres.SkillMap[int(data.ReplaceSkill)]
if !exists {
return nil, errorcode.ErrorCodes.ErrSystemBusy
}
_, _, ok = utils.FindWithIndex(currentPet.SkillList, func(item model.SkillInfo) bool { //已经存在技能
return item.ID == data.ReplaceSkill
})
@@ -42,13 +100,25 @@ func (h Controller) SetPetSkill(data *ChangeSkillInfo, c *player.Player) (result
return nil, errorcode.ErrorCodes.ErrSystemBusy
}
// 查找要学习的技能并替换
_, targetSkill, ok := utils.FindWithIndex(currentPet.SkillList, func(item model.SkillInfo) bool {
return item.ID == data.HasSkill
})
if ok {
maxPP := uint32(skillInfo.MaxPP)
if data.HasSkill != 0 {
// 查找要学习的技能并替换
_, targetSkill, found := utils.FindWithIndex(currentPet.SkillList, func(item model.SkillInfo) bool {
return item.ID == data.HasSkill
})
if !found {
return nil, errorcode.ErrorCodes.ErrSystemBusy
}
targetSkill.ID = data.ReplaceSkill
targetSkill.PP = uint32(xmlres.SkillMap[int(targetSkill.ID)].MaxPP)
targetSkill.PP = maxPP
} else {
if len(currentPet.SkillList) >= 4 {
return nil, errorcode.ErrorCodes.ErrSystemBusy
}
currentPet.SkillList = append(currentPet.SkillList, model.SkillInfo{
ID: data.ReplaceSkill,
PP: maxPP,
})
}
return &pet.ChangeSkillOutInfo{
@@ -67,18 +137,45 @@ func (h Controller) SortPetSkills(data *C2S_Skill_Sort, c *player.Player) (resul
c.Info.Coins -= skillSortCost
_, currentPet, ok := c.FindPet(data.CapTm)
if ok {
var newSkillList []model.SkillInfo
for _, skillID := range data.Skill {
_, skill, found := utils.FindWithIndex(currentPet.SkillList, func(item model.SkillInfo) bool {
return item.ID == skillID
})
if found {
newSkillList = append(newSkillList, *skill)
}
}
currentPet.SkillList = newSkillList
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
usedSkillSet := make(map[uint32]struct{})
newSkillList := make([]model.SkillInfo, 0, 4)
for _, skillID := range data.Skill {
if skillID == 0 {
continue
}
if _, used := usedSkillSet[skillID]; used {
continue
}
_, skill, found := utils.FindWithIndex(currentPet.SkillList, func(item model.SkillInfo) bool {
return item.ID == skillID
})
if !found {
continue
}
newSkillList = append(newSkillList, *skill)
usedSkillSet[skillID] = struct{}{}
}
for _, skill := range currentPet.SkillList {
if skill.ID == 0 {
continue
}
if _, used := usedSkillSet[skill.ID]; used {
continue
}
newSkillList = append(newSkillList, skill)
usedSkillSet[skill.ID] = struct{}{}
}
if len(newSkillList) > 4 {
newSkillList = newSkillList[:4]
}
currentPet.SkillList = newSkillList
return nil, 0
}

View File

@@ -95,13 +95,17 @@ func (c *PetBagController) Level(ctx context.Context, req *PetLevelReq) (res *co
type PetStorageReq struct {
g.Meta `path:"/storage" method:"POST"`
IsVIP int `json:"is_vip"`
Free int `json:"free"`
}
func (c *PetBagController) Storage(ctx context.Context, req *PetStorageReq) (res *cool.BaseRes, err error) {
admin := cool.GetAdmin(ctx)
res = &cool.BaseRes{}
res.Data = service.NewPetService(uint32(admin.UserId)).StorageInfo(req.IsVIP)
if req.Free < 0 || req.Free > 2 {
req.Free = 0
}
res.Data = service.NewPetService(uint32(admin.UserId)).StorageInfo(req.IsVIP, req.Free)
return
}

View File

@@ -58,9 +58,9 @@ func (s *PetService) PetInfo(flag int) []model.Pet {
return tt
}
func (s *PetService) StorageInfo(isVip int) []model.Pet {
func (s *PetService) StorageInfo(isVip int, free int) []model.Pet {
var tt []model.Pet
if err := s.dbm_fix(s.Model).Where("free", 0).Where("is_vip", isVip).Scan(&tt); err != nil {
if err := s.dbm_fix(s.Model).Where("free", free).Where("is_vip", isVip).Scan(&tt); err != nil {
return nil
}
for i := range tt {