2025-11-25 21:10:52 +08:00
|
|
|
package controller
|
2025-11-26 01:33:48 +08:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"blazing/common/data/xmlres"
|
|
|
|
|
"blazing/common/socket/errorcode"
|
|
|
|
|
"blazing/logic/service/pet"
|
|
|
|
|
"blazing/logic/service/player"
|
2025-12-21 17:18:33 +00:00
|
|
|
"blazing/modules/config/service"
|
2026-01-19 18:51:56 +08:00
|
|
|
"blazing/modules/player/model"
|
2025-12-02 02:50:20 +00:00
|
|
|
|
2025-12-05 00:24:02 +08:00
|
|
|
"github.com/alpacahq/alpacadecimal"
|
2025-12-30 00:10:59 +08:00
|
|
|
"github.com/gogf/gf/v2/util/grand"
|
2026-03-31 08:19:53 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
petFusionCost = 1000
|
|
|
|
|
petFusionKeepAuxItemID = 300043
|
|
|
|
|
petFusionFailureItemID = 300044
|
|
|
|
|
petFusionSoulID = 1000017
|
2025-11-26 01:33:48 +08:00
|
|
|
)
|
|
|
|
|
|
2026-04-05 07:24:36 +08:00
|
|
|
func (h Controller) PetFusion(data *C2S_PetFusion, c *player.Player) (result *pet.PetFusionInfo, err errorcode.ErrorCode) {
|
2026-03-31 08:19:53 +08:00
|
|
|
result = &pet.PetFusionInfo{
|
|
|
|
|
SoulID: petFusionSoulID,
|
2025-11-26 01:33:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if data.Mcatchtime == data.Auxcatchtime {
|
2025-12-04 00:26:49 +08:00
|
|
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady
|
2025-11-26 01:33:48 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
_, masterPet, ok := c.FindPet(data.Mcatchtime)
|
2025-11-26 01:33:48 +08:00
|
|
|
if !ok {
|
2025-12-04 00:26:49 +08:00
|
|
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady2
|
2025-11-26 01:33:48 +08:00
|
|
|
}
|
2026-03-31 08:19:53 +08:00
|
|
|
masterCfg, ok := xmlres.PetMAP[int(masterPet.ID)]
|
|
|
|
|
if !ok || masterCfg.FuseMaster == 0 {
|
2025-12-04 00:26:49 +08:00
|
|
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady3
|
2025-11-26 01:33:48 +08:00
|
|
|
}
|
2026-03-31 08:19:53 +08:00
|
|
|
|
|
|
|
|
_, auxPet, ok := c.FindPet(data.Auxcatchtime)
|
2025-11-26 01:33:48 +08:00
|
|
|
if !ok {
|
2025-12-04 00:26:49 +08:00
|
|
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady2
|
2025-11-26 01:33:48 +08:00
|
|
|
}
|
2026-03-31 08:19:53 +08:00
|
|
|
auxCfg, ok := xmlres.PetMAP[int(auxPet.ID)]
|
|
|
|
|
if !ok || auxCfg.FuseSub == 0 {
|
2025-12-04 00:26:49 +08:00
|
|
|
return result, errorcode.ErrorCodes.ErrPokemonNotFusionReady3
|
2025-11-26 01:33:48 +08:00
|
|
|
}
|
2026-02-26 10:24:30 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
materialCounts := collectItemCounts(data.Item1[:])
|
|
|
|
|
if !hasEnoughItems(c, materialCounts) {
|
|
|
|
|
return result, errorcode.ErrorCodes.ErrInsufficientItems
|
2026-02-10 23:06:41 +08:00
|
|
|
}
|
2026-02-26 10:24:30 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
materialService := service.NewPetFusionMaterialService()
|
|
|
|
|
effect := int(materialService.Data(data.Item1))
|
2026-01-25 23:17:46 +08:00
|
|
|
if effect == 0 {
|
|
|
|
|
return result, errorcode.ErrorCodes.ErrSpiritOrbNotExists
|
|
|
|
|
}
|
2026-02-26 22:32:15 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
fusionService := service.NewPetFusionService()
|
|
|
|
|
resultPetID := int(fusionService.Data(masterPet.ID, auxPet.ID, masterPet.Level+auxPet.Level))
|
2026-01-03 13:53:38 +00:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
if !c.GetCoins(petFusionCost) {
|
|
|
|
|
return result, errorcode.ErrorCodes.ErrSunDouInsufficient10016
|
2026-02-26 11:44:52 +08:00
|
|
|
}
|
2026-02-03 20:20:13 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
consumeItems(c, materialCounts)
|
|
|
|
|
c.Info.Coins -= petFusionCost
|
2026-01-03 01:35:32 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
if resultPetID == 0 {
|
|
|
|
|
if useOptionalItem(c, data.GoldItem1[:], petFusionFailureItemID) {
|
2026-02-03 20:20:13 +08:00
|
|
|
result.CostItemFlag = 1
|
2026-03-31 08:19:53 +08:00
|
|
|
} else if auxPet.Level > 5 {
|
|
|
|
|
auxPet.Downgrade(auxPet.Level - 5)
|
2026-01-03 01:35:32 +08:00
|
|
|
} else {
|
2026-03-31 08:19:53 +08:00
|
|
|
auxPet.Downgrade(1)
|
2026-01-03 01:35:32 +08:00
|
|
|
}
|
2025-12-02 03:59:28 +08:00
|
|
|
return &pet.PetFusionInfo{}, 0
|
|
|
|
|
}
|
2026-01-03 01:35:32 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
natureID := int32(-1)
|
|
|
|
|
if auxPet.Nature == masterPet.Nature {
|
|
|
|
|
natureID = int32(auxPet.Nature)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dv1 := alpacadecimal.NewFromInt(2).Div(alpacadecimal.NewFromInt(3)).Mul(alpacadecimal.NewFromInt(int64(masterPet.Dv)))
|
|
|
|
|
dv2 := alpacadecimal.NewFromInt(1).Div(alpacadecimal.NewFromInt(3)).Mul(alpacadecimal.NewFromInt(int64(auxPet.Dv)))
|
2025-12-05 00:24:02 +08:00
|
|
|
dv := dv1.Add(dv2).Add(alpacadecimal.NewFromInt(1)).IntPart()
|
2026-03-31 08:19:53 +08:00
|
|
|
newPet := model.GenPetInfo(resultPetID, int(dv), int(natureID), effect, 1, nil, -1)
|
|
|
|
|
newPet.OldCatchTime = masterPet.CatchTime
|
2025-12-30 00:10:59 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
shinyChance := 1
|
|
|
|
|
if masterPet.IsShiny() || auxPet.IsShiny() {
|
|
|
|
|
shinyChance = 50
|
2025-12-30 00:10:59 +08:00
|
|
|
}
|
2026-03-31 08:19:53 +08:00
|
|
|
if masterPet.IsShiny() && auxPet.IsShiny() {
|
|
|
|
|
shinyChance = 100
|
2025-12-30 00:10:59 +08:00
|
|
|
}
|
2026-03-31 08:19:53 +08:00
|
|
|
if grand.Meet(shinyChance, 100) {
|
|
|
|
|
newPet.RandomByWeightShiny()
|
2025-12-30 00:10:59 +08:00
|
|
|
}
|
2026-01-03 01:35:32 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
c.Service.Pet.PetAdd(newPet, 0)
|
2026-04-05 05:47:25 +08:00
|
|
|
//println(c.Info.UserID, "进行融合", len(c.Info.PetList), masterPet.ID, auxPet.ID, newPet.ID)
|
2026-01-03 01:35:32 +08:00
|
|
|
|
2026-03-31 08:19:53 +08:00
|
|
|
c.PetDel(data.Mcatchtime)
|
|
|
|
|
if useOptionalItem(c, data.GoldItem1[:], petFusionKeepAuxItemID) {
|
2026-02-03 20:20:13 +08:00
|
|
|
result.CostItemFlag = 1
|
2026-01-03 01:35:32 +08:00
|
|
|
} else {
|
|
|
|
|
c.PetDel(data.Auxcatchtime)
|
|
|
|
|
}
|
2026-03-31 08:19:53 +08:00
|
|
|
|
|
|
|
|
result.ObtainTime = newPet.CatchTime
|
|
|
|
|
result.StarterCpTm = newPet.ID
|
2026-02-03 20:20:13 +08:00
|
|
|
return result, 0
|
2025-11-26 01:33:48 +08:00
|
|
|
}
|
2026-03-31 08:19:53 +08:00
|
|
|
|
|
|
|
|
func collectItemCounts(itemIDs []uint32) map[uint32]int {
|
|
|
|
|
counts := make(map[uint32]int, len(itemIDs))
|
|
|
|
|
for _, itemID := range itemIDs {
|
|
|
|
|
counts[itemID]++
|
|
|
|
|
}
|
|
|
|
|
return counts
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func hasEnoughItems(c *player.Player, itemCounts map[uint32]int) bool {
|
|
|
|
|
if len(itemCounts) == 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
itemIDs := make([]uint32, 0, len(itemCounts))
|
|
|
|
|
for itemID := range itemCounts {
|
|
|
|
|
itemIDs = append(itemIDs, itemID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hadItems := c.Service.Item.CheakItemM(itemIDs...)
|
|
|
|
|
ownedCounts := make(map[uint32]int64, len(hadItems))
|
|
|
|
|
for _, item := range hadItems {
|
|
|
|
|
ownedCounts[item.ItemId] = item.ItemCnt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for itemID, need := range itemCounts {
|
|
|
|
|
if ownedCounts[itemID] < int64(need) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func consumeItems(c *player.Player, itemCounts map[uint32]int) {
|
|
|
|
|
for itemID, count := range itemCounts {
|
|
|
|
|
_ = c.Service.Item.UPDATE(itemID, -count)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func useOptionalItem(c *player.Player, itemIDs []uint32, target uint32) bool {
|
|
|
|
|
if c.Service.Item.CheakItem(target) <= 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
for _, itemID := range itemIDs {
|
|
|
|
|
if itemID == target {
|
|
|
|
|
_ = c.Service.Item.UPDATE(target, -1)
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|