diff --git a/common/data/xmlres/item.go b/common/data/xmlres/item.go index a607954ba..e327e2b51 100644 --- a/common/data/xmlres/item.go +++ b/common/data/xmlres/item.go @@ -47,10 +47,11 @@ type Item struct { YuanshenDegrade int `xml:"YuanshenDegrade,attr,omitempty"` // 融合精灵还原标识(融合精灵还原药剂) EvRemove int `xml:"EvRemove,attr,omitempty"` // 学习力遗忘类型(各类学习力遗忘剂) //bShowPetBag int `xml:"bShowPetBag,attr,omitempty"` // 宠物背包显示标识(副融合精灵保留药剂等) - Nature *string `xml:"Nature,attr"` // 指向int的指针,无值时为nil - NatureSet *string `xml:"NatureSet,attr"` // 指向string的指针,无值时为nil - Pet *Pet `xml:"pet,omitempty"` // 精灵属性子节点 - TeamPK *TeamPK `xml:"teamPK,omitempty"` // 要塞保卫战子节点 + Nature *string `xml:"Nature,attr"` // 指向int的指针,无值时为nil + NatureSet *string `xml:"NatureSet,attr"` // 指向string的指针,无值时为nil + NatureProbs *string `xml:"NatureProbs,attr"` // 指向string的指针,无值时为nil + Pet *Pet `xml:"pet,omitempty"` // 精灵属性子节点 + TeamPK *TeamPK `xml:"teamPK,omitempty"` // 要塞保卫战子节点 } // Pet 精灵属性子节点,对应标签 diff --git a/logic/controller/item_use.go b/logic/controller/item_use.go index 81f5231d8..651892a2c 100644 --- a/logic/controller/item_use.go +++ b/logic/controller/item_use.go @@ -1,16 +1,12 @@ package controller import ( - "blazing/common/data/xmlres" "blazing/common/socket/errorcode" "blazing/logic/service/fight" "blazing/logic/service/item" "blazing/logic/service/player" "blazing/modules/blazing/model" - "strings" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/grand" "github.com/jinzhu/copier" ) @@ -35,40 +31,33 @@ func (h Controller) ItemUsePet(data *item.C2S_USE_PET_ITEM_OUT_OF_FIGHT, c *play if !ok { return nil, errorcode.ErrorCodes.Err10401 } - // 绑定变量到switch,显式匹配true - switch itemID := data.ItemID; true { - //这是学习力遗忘 - case itemID >= 300037 && itemID <= 300041: - - onpet.Ev[itemID-300037+1] = 0 - // 体力遗忘 - case itemID == 300042: - onpet.Ev[0] = 0 - // 全能遗忘 - case itemID == 300650: - onpet.Ev = [6]uint32{} - - //性格随机 - case itemID == 300025: - - onpet.Nature = (onpet.Nature + uint32(grand.Intn(25))) % 25 - - //性格转换 - case itemID >= 300081 && itemID <= 300086: - onpet.Nature = gconv.Uint32(*xmlres.ItemsMAP[int(itemID)].Nature) - - //性格转换 - case (itemID >= 300602 && itemID <= 300605) || itemID == 300119 || itemID == 300120: - rr := strings.Split(*xmlres.ItemsMAP[int(itemID)].NatureSet, " ") - onpet.Nature = gconv.Uint32(rr[grand.Intn(len(rr))-1]) - default: - // 无效ID处理 - return nil, errorcode.ErrorCodes.ErrSystemError - } if c.Service.Item.CheakItem(data.ItemID) == 0 { return nil, errorcode.ErrorCodes.ErrSystemError } + hd := item.PetItemRegistry.GetHandler(data.ItemID) + if hd == nil { + return nil, errorcode.ErrorCodes.ErrSystemError + } + if data.ItemID == 300025 { + //神经元需要特殊处理 + + if onpet.OldCatchTime == 0 { + return nil, errorcode.ErrorCodes.ErrSystemError + } + oldpetc := onpet.CatchTime + oldpet := c.Service.Pet.PetInfo_One_Unscoped(onpet.OldCatchTime) + + copier.Copy(onpet, oldpet.Data) + onpet.CatchTime = oldpetc + } else { + r := hd(data.ItemID, onpet) + if !r { + return nil, errorcode.ErrorCodes.ErrSystemError + } + + } + c.Service.Item.SubItem(data.ItemID, 1) result = &item.S2C_USE_PET_ITEM_OUT_OF_FIGHT{} onpet.CalculatePetPane() @@ -77,8 +66,8 @@ func (h Controller) ItemUsePet(data *item.C2S_USE_PET_ITEM_OUT_OF_FIGHT, c *play return result, 0 } -func (h Controller) RESET_NATURE(data *item.C2S_PET_RESET_NATURE, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { - if c.Service.Item.CheakItem(data.ItemId) == 0 { +func (h Controller) ResetNature(data *item.C2S_PET_RESET_NATURE, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { + if c.Service.Item.CheakItem(data.ItemId) <= 0 { return nil, errorcode.ErrorCodes.ErrSystemError } _, onpet, ok := c.FindPet(data.CatchTime) diff --git a/logic/service/item/pet.go b/logic/service/item/pet.go index 47f05dd70..9b8eeaa52 100644 --- a/logic/service/item/pet.go +++ b/logic/service/item/pet.go @@ -26,8 +26,9 @@ type S2C_USE_PET_ITEM_OUT_OF_FIGHT struct { // * ev:生命学习力,攻击学习力,防御学习力,特攻学习力,特防学习力,速度学习力 Ev [6]uint32 `fieldDesc:"属性" ` // * battle_lv: atk(0), def(1), sp_atk(2), sp_def(3), spd(4), accuracy(5) - Prop [5]uint32 `fieldDesc:"属性" ` - SkillList []model.SkillInfo `json:"skilllist"` // 技能数组 + Prop [5]uint32 `fieldDesc:"属性" ` + SkillListLen uint32 `struc:"sizeof=SkillList"` + SkillList []model.SkillInfo `json:"skilllist"` // 技能数组 } type C2S_PET_RESET_NATURE struct { Head common.TomeeHeader `cmd:"2343" struc:"skip"` diff --git a/logic/service/item/petuse.go b/logic/service/item/petuse.go new file mode 100644 index 000000000..789acf466 --- /dev/null +++ b/logic/service/item/petuse.go @@ -0,0 +1,258 @@ +package item + +import ( + "blazing/common/data/xmlres" + "blazing/modules/blazing/model" + "errors" + "strconv" + "strings" + + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/grand" + "github.com/jinzhu/copier" +) + +type PetItemHandler func(itemid uint32, ctx *model.PetInfo) bool + +// RangeHandler 范围ID处理器(用于ID区间匹配) +type RangeHandler struct { + Start uint32 + End uint32 + Handler PetItemHandler +} + +// SetHandler 集合ID处理器(用于离散ID匹配) +type SetHandler struct { + IDs []uint32 + Handler PetItemHandler +} + +// PetItemHandlerRegistry 道具处理器注册器 +type PetItemHandlerRegistry struct { + exactHandlers map[uint32]PetItemHandler // 精确ID映射 + rangeHandlers []RangeHandler // 范围ID映射 + setHandlers []SetHandler // 集合ID映射 +} + +// 全局注册器实例 +var PetItemRegistry = &PetItemHandlerRegistry{ + exactHandlers: make(map[uint32]PetItemHandler), +} + +// -------------------------- 4. 注册器方法 -------------------------- +// RegisterExact 注册精确ID的处理函数 +func (r *PetItemHandlerRegistry) RegisterExact(itemID uint32, handler PetItemHandler) { + r.exactHandlers[itemID] = handler +} + +// RegisterRange 注册ID范围的处理函数 +func (r *PetItemHandlerRegistry) RegisterRange(start, end uint32, handler PetItemHandler) { + r.rangeHandlers = append(r.rangeHandlers, RangeHandler{ + Start: start, + End: end, + Handler: handler, + }) +} + +// RegisterSet 注册ID集合的处理函数 +func (r *PetItemHandlerRegistry) RegisterSet(ids []uint32, handler PetItemHandler) { + r.setHandlers = append(r.setHandlers, SetHandler{ + IDs: ids, + Handler: handler, + }) +} + +// GetHandler 根据ItemID获取对应的处理函数 +func (r *PetItemHandlerRegistry) GetHandler(itemID uint32) PetItemHandler { + // 1. 优先匹配精确ID + if handler, ok := r.exactHandlers[itemID]; ok { + return handler + } + + // 2. 匹配范围ID + for _, rh := range r.rangeHandlers { + if itemID >= rh.Start && itemID <= rh.End { + return rh.Handler + } + } + + // 3. 匹配集合ID + for _, sh := range r.setHandlers { + for _, id := range sh.IDs { + if itemID == id { + return sh.Handler + } + } + } + + // 4. 无匹配的处理器 + return nil +} +func nvfunc(itemid uint32, onpet *model.PetInfo) bool { + // 1. 取出配置(保留你原有的取值方式) + itemConf := xmlres.ItemsMAP[int(itemid)] + + // 2. 分割NatureSet(保留你原有的写法) + rr := strings.Split(*itemConf.NatureSet, " ") + + // 3. 分割NatureProbs(新增概率解析) + var probList []string + if itemConf.NatureProbs != nil { + probList = strings.Split(*itemConf.NatureProbs, " ") + } + + // 4. 按概率选值(核心改造:替换原有随机逻辑) + selectedVal, err := randomByProbs(rr, probList) + if err != nil { + return false + } + + // 5. 赋值(保留你原有的类型转换) + onpet.Nature = gconv.Uint32(selectedVal) + return true +} + +// -------------------------- 6. 初始化注册器(注册所有处理器) -------------------------- +func init() { + + PetItemRegistry.RegisterRange(300037, 300041, func(itemid uint32, onpet *model.PetInfo) bool { + onpet.Ev[itemid-300037+1] = 0 + return true + + }) + + PetItemRegistry.RegisterExact(300042, func(itemid uint32, onpet *model.PetInfo) bool { + onpet.Ev[0] = 0 + return true + }) + PetItemRegistry.RegisterExact(300650, func(itemid uint32, onpet *model.PetInfo) bool { + onpet.Ev = [6]uint32{} + return true + }) + PetItemRegistry.RegisterExact(300025, func(itemid uint32, onpet *model.PetInfo) bool { + onpet.Nature = (onpet.Nature + uint32(grand.Intn(25))) % 25 + return true + }) + + PetItemRegistry.RegisterRange(300081, 300086, func(itemid uint32, onpet *model.PetInfo) bool { + onpet.Nature = gconv.Uint32(*xmlres.ItemsMAP[int(itemid)].Nature) + return true + + }) + + PetItemRegistry.RegisterRange(300602, 300605, nvfunc) + + //特判转换 + PetItemRegistry.RegisterSet([]uint32{300119, 300120}, nvfunc) + + PetItemRegistry.RegisterExact(300790, func(itemid uint32, onpet *model.PetInfo) bool { + r := grand.Intn(2) + if r == 0 { + onpet.Dv-- + } else { + onpet.Dv++ + } + return true + }) + //基因重组 + PetItemRegistry.RegisterExact(300024, func(itemid uint32, onpet *model.PetInfo) bool { + oldcat := onpet.CatchTime + + ab := 0 + for _, v := range onpet.EffectInfo { + if v.Type == 1 { + ab = int(v.Idx) + } + + } + r := model.GenPetInfo(int(onpet.ID), -1, -1, ab, 0, 1) + + copier.Copy(onpet, r) + onpet.CatchTime = oldcat + return true + }) + + PetItemRegistry.RegisterExact(300668, func(itemid uint32, onpet *model.PetInfo) bool { + + onpet.Dv = uint32(grand.Intn(32)) + return true + }) + PetItemRegistry.RegisterExact(300791, func(itemid uint32, onpet *model.PetInfo) bool { + + onpet.Dv = 31 + return true + }) + PetItemRegistry.RegisterExact(300792, func(itemid uint32, onpet *model.PetInfo) bool { + + onpet.Dv = uint32(grand.Intn(31-int(onpet.Dv)) + 1) + return true + }) + PetItemRegistry.RegisterExact(300053, func(itemid uint32, onpet *model.PetInfo) bool { + + if !onpet.HaveAN() { + onpet.RnadAN() + return true + } + + return false + }) + PetItemRegistry.RegisterExact(300054, func(itemid uint32, onpet *model.PetInfo) bool { + + if onpet.HaveAN() { + onpet.RnadAN() + return true + } + return false + }) +} + +// 替换你原有性格转换的代码段,新增概率解析+权重随机逻辑 +// 注:保留你原有的变量名(如rr)、函数调用(grand.Intn),仅扩展概率逻辑 + +// 先定义一个辅助函数:按概率从列表中选值(贴合你的代码风格) +func randomByProbs(natureSet []string, probs []string) (string, error) { + // 1. 若概率配置为空/长度不匹配,降级为等概率随机(兼容原有逻辑) + if len(probs) == 0 || len(natureSet) != len(probs) { + if len(natureSet) == 0 { + return "", errors.New("natureSet is empty") + } + // 修复你原有代码的索引越界问题:grand.Intn(len(rr))-1 → 改为grand.Intn(len(rr)) + // 因为grand.Intn(n)返回0~n-1,直接作为索引即可,无需-1 + return natureSet[grand.Intn(len(natureSet))], nil + } + + // 2. 解析概率为int数组,校验非负 + probInts := make([]int, len(probs)) + totalProb := 0 + for i, p := range probs { + val, err := strconv.Atoi(p) + if err != nil || val < 0 { + return "", errors.New("invalid prob value: " + p) + } + probInts[i] = val + totalProb += val + } + + // 3. 总概率为0,降级为等概率 + if totalProb == 0 { + return natureSet[grand.Intn(len(natureSet))], nil + } + + // 4. 计算前缀和(权重随机核心) + prefixSum := make([]int, len(probInts)) + prefixSum[0] = probInts[0] + for i := 1; i < len(probInts); i++ { + prefixSum[i] = prefixSum[i-1] + probInts[i] + } + + // 5. 生成随机数匹配前缀和 + randVal := grand.Intn(totalProb) + for i, sum := range prefixSum { + if randVal < sum { + return natureSet[i], nil + } + } + + // 理论上不会走到这里 + return natureSet[0], nil +} diff --git a/modules/blazing/model/pet.go b/modules/blazing/model/pet.go index ab4799e4f..e536f6576 100644 --- a/modules/blazing/model/pet.go +++ b/modules/blazing/model/pet.go @@ -11,6 +11,7 @@ import ( "time" "github.com/gogf/gf/v2/util/gconv" + "github.com/jinzhu/copier" "github.com/samber/lo" ) @@ -89,7 +90,7 @@ type PetInfo struct { // 捕获等级默认0(@UInt long → uint32) CatchLevel uint32 `fieldDesc:"捕获等级 默认为0" ` EffectInfoLen uint16 `struc:"sizeof=EffectInfo"` - // 特性列表:长度用UShort存储(变长List → []PetEffectInfo + 长度前缀规则) + // 特性列表:长度用UShort存储(变长List → []PetEffectInfo + 长度前缀规则) 第一个一定是特性 EffectInfo []PetEffectInfo `fieldDesc:"特性列表, 长度在头部以UShort存储" serialize:"lengthFirst,lengthType=uint16,type=structArray"` // 皮肤ID默认0(@UInt long → uint32) @@ -196,6 +197,42 @@ func (pet *PetInfo) Cure() { } } +// 随机特性 +func (pet *PetInfo) RnadAN() { + // 随机特性 + randomIndex := rand.Intn(len(xmlres.PlayerEffectMAP)) + + var i int + for _, v := range xmlres.PlayerEffectMAP { + + if i == randomIndex { + ret := &PetEffectInfo{ + Idx: uint16(gconv.Int16(v.Idx)), + Status: 1, + EID: uint16(gconv.Int16(v.Eid)), + Args: v.ArgsS, + } + _, eff1, ok := utils.FindWithIndex(pet.EffectInfo, func(item PetEffectInfo) bool { + return uint16(item.Type) == 1 + }) + if ok { + copier.Copy(eff1, ret) + } + pet.EffectInfo = append(pet.EffectInfo, *ret) + + break + } + i++ + } +} + +func (pet *PetInfo) HaveAN() bool { + + _, _, ok := utils.FindWithIndex(pet.EffectInfo, func(item PetEffectInfo) bool { + return uint16(item.Type) == 1 + }) + return ok +} func (pet *PetInfo) Downgrade(level uint32) { for pet.Level > uint32(level) { diff --git a/modules/blazing/service/pet.go b/modules/blazing/service/pet.go index d1f194ca3..dba4ea23a 100644 --- a/modules/blazing/service/pet.go +++ b/modules/blazing/service/pet.go @@ -50,6 +50,15 @@ func (s *PetService) PetInfo_One(cachetime uint32) model.PetEX { tt.Data.CatchTime = tt.CatchTime return tt } +func (s *PetService) PetInfo_One_Unscoped(cachetime uint32) model.PetEX { + + m := cool.DBM(s.Model).Where("player_id", s.userid).Where("catch_time", cachetime).Unscoped() + var tt model.PetEX + + m.Scan(&tt) + tt.Data.CatchTime = tt.CatchTime + return tt +} func (s *PetService) Pet_del(cachetime uint32) { cool.DBM(s.Model).Where("player_id", s.userid).Where("catch_time", cachetime).Delete()