package controller import ( "blazing/common/data/xmlres" "blazing/common/socket/errorcode" "blazing/common/utils" "blazing/logic/service/fight" "blazing/logic/service/pet" "blazing/logic/service/player" "blazing/modules/player/model" ) type GetPetLearnableSkillsOutboundInfo struct { SkillListLen uint32 `struc:"sizeof=SkillList"` SkillList []uint32 `json:"skillList"` } func isSameUint32Slice(a []uint32, b []uint32) bool { if len(a) != len(b) { return false } for index := range a { if a[index] != b[index] { return false } } return true } 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 _, currentPet, ok := c.FindPet(data.CatchTime) if !ok { return nil, 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 }) if ok { return nil, errorcode.ErrorCodes.ErrSystemBusy } if data.HasSkill == 0 && len(currentPet.SkillList) >= 4 { return nil, errorcode.ErrorCodes.ErrSystemBusy } if data.HasSkill != 0 { _, _, found := utils.FindWithIndex(currentPet.SkillList, func(item model.SkillInfo) bool { return item.ID == data.HasSkill }) if !found { return nil, errorcode.ErrorCodes.ErrSystemBusy } } if !c.GetCoins(setSkillCost) { return nil, errorcode.ErrorCodes.ErrSunDouInsufficient10016 } c.Info.Coins -= setSkillCost maxPP := uint32(skillInfo.MaxPP) if data.HasSkill != 0 { _, targetSkill, _ := utils.FindWithIndex(currentPet.SkillList, func(item model.SkillInfo) bool { return item.ID == data.HasSkill }) targetSkill.ID = data.ReplaceSkill targetSkill.PP = maxPP } else { currentPet.SkillList = append(currentPet.SkillList, model.SkillInfo{ ID: data.ReplaceSkill, PP: maxPP, }) } return &pet.ChangeSkillOutInfo{ CatchTime: data.CatchTime, }, 0 } // SortPetSkills 排序宠物技能,消耗50赛尔豆 func (h Controller) SortPetSkills(data *C2S_Skill_Sort, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { const skillSortCost = 50 _, currentPet, ok := c.FindPet(data.CapTm) 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] } if !c.GetCoins(skillSortCost) { return nil, errorcode.ErrorCodes.ErrSunDouInsufficient10016 } c.Info.Coins -= skillSortCost currentPet.SkillList = newSkillList return nil, 0 } // CommitPetSkills 按最终技能列表一次性提交学习/替换/排序结果。 func (h Controller) CommitPetSkills( data *CommitPetSkillsInboundInfo, c *player.Player, ) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { const setSkillCost = 50 const skillSortCost = 50 _, currentPet, ok := c.FindPet(data.CatchTime) if !ok { return nil, errorcode.ErrorCodes.ErrPokemonNotExists } currentSkillSet := make(map[uint32]model.SkillInfo, len(currentPet.SkillList)) currentSkillOrder := make([]uint32, 0, len(currentPet.SkillList)) for _, skill := range currentPet.SkillList { if skill.ID == 0 { continue } currentSkillSet[skill.ID] = skill currentSkillOrder = append(currentSkillOrder, skill.ID) } finalSkillIDs := make([]uint32, 0, 4) usedSkillSet := make(map[uint32]struct{}, 4) for _, skillID := range data.Skill { if skillID == 0 { continue } if _, exists := usedSkillSet[skillID]; exists { continue } usedSkillSet[skillID] = struct{}{} finalSkillIDs = append(finalSkillIDs, skillID) } if len(finalSkillIDs) == 0 { return nil, errorcode.ErrorCodes.ErrSystemBusy } if len(finalSkillIDs) > 4 { finalSkillIDs = finalSkillIDs[:4] } if isSameUint32Slice(currentSkillOrder, finalSkillIDs) { return nil, 0 } learnableSkillSet := make(map[uint32]struct{}) for _, skillID := range collectPetLearnableSkillList(currentPet) { learnableSkillSet[skillID] = struct{}{} } newSkillCount := 0 finalSkillList := make([]model.SkillInfo, 0, len(finalSkillIDs)) for _, skillID := range finalSkillIDs { if skill, exists := currentSkillSet[skillID]; exists { finalSkillList = append(finalSkillList, skill) continue } if _, exists := learnableSkillSet[skillID]; !exists { return nil, errorcode.ErrorCodes.ErrSystemBusy } skillInfo, exists := xmlres.SkillMap[int(skillID)] if !exists { return nil, errorcode.ErrorCodes.ErrSystemBusy } newSkillCount++ finalSkillList = append(finalSkillList, model.SkillInfo{ ID: skillID, PP: uint32(skillInfo.MaxPP), }) } totalCost := int64(newSkillCount * setSkillCost) if newSkillCount == 0 { totalCost += int64(skillSortCost) } if totalCost > 0 && !c.GetCoins(totalCost) { return nil, errorcode.ErrorCodes.ErrSunDouInsufficient10016 } c.Info.Coins -= totalCost currentPet.SkillList = finalSkillList return nil, 0 }