All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
feat(fight_boss): 优化BOSS战斗奖励逻辑并修复宠物等级突破100级限制 重构了handleMapBossFightRewards函数,将奖励逻辑分离到独立的处理函数中, 增加了shouldGrantBossWinBonus条件判断,确保只有满足条件时才发放胜利奖励。 同时修复了宠物等级系统,允许宠物等级突破100级限制但面板属性仍保持100级上限, 改进了经验获取和面板更新逻辑。 fix(item_use): 添加全能性格转化剂使用验证 添加了UniversalNatureItemID常量定义,增加对道具ID和性格配置的有效性验证, 确保只有正确的道具和性格类型才能被使用。 refactor(fight): 统一战斗结束原因处理逻辑 引入normalizeFightOverReason函数来标准化战斗结束原因, 统一了不同模块中的战斗结果映射逻辑,提高了代码一致性。 perf(pet): 优化宠物升级和经验计算性能 移除了等级100的硬性限制,在保证面板属性不超限的前提下允许宠物等级继续增长, 优化了经验分配和面板重新计算的逻辑流程。 ```
194 lines
4.4 KiB
Go
194 lines
4.4 KiB
Go
package player
|
|
|
|
import (
|
|
"blazing/common/utils"
|
|
"blazing/logic/service/pet"
|
|
"blazing/modules/player/model"
|
|
)
|
|
|
|
type PetBagSlot struct {
|
|
list *[]model.PetInfo
|
|
index int
|
|
info model.PetInfo
|
|
main bool
|
|
}
|
|
|
|
func (slot PetBagSlot) IsValid() bool {
|
|
return slot.list != nil && slot.index >= 0 && slot.index < len(*slot.list)
|
|
}
|
|
|
|
func (slot PetBagSlot) Remove() {
|
|
*slot.list = append((*slot.list)[:slot.index], (*slot.list)[slot.index+1:]...)
|
|
}
|
|
|
|
func (slot PetBagSlot) PetInfo() model.PetInfo {
|
|
return slot.info
|
|
}
|
|
|
|
func (slot PetBagSlot) PetInfoPtr() *model.PetInfo {
|
|
if !slot.IsValid() {
|
|
return nil
|
|
}
|
|
return &(*slot.list)[slot.index]
|
|
}
|
|
|
|
func (slot PetBagSlot) IsMainBag() bool {
|
|
return slot.main
|
|
}
|
|
|
|
func buildCatchTimeSet(petLists ...[]model.PetInfo) map[uint32]struct{} {
|
|
total := 0
|
|
for _, petList := range petLists {
|
|
total += len(petList)
|
|
}
|
|
|
|
catchTimes := make(map[uint32]struct{}, total)
|
|
for _, petList := range petLists {
|
|
for _, petInfo := range petList {
|
|
catchTimes[petInfo.CatchTime] = struct{}{}
|
|
}
|
|
}
|
|
return catchTimes
|
|
}
|
|
|
|
func removePetByCatchTime(petList []model.PetInfo, catchTime uint32) []model.PetInfo {
|
|
for i := range petList {
|
|
if petList[i].CatchTime == catchTime {
|
|
return append(petList[:i], petList[i+1:]...)
|
|
}
|
|
}
|
|
return petList
|
|
}
|
|
|
|
func buildPetInfoMap(petLists ...[]model.PetInfo) map[uint32]*model.PetInfo {
|
|
total := 0
|
|
for _, petList := range petLists {
|
|
total += len(petList)
|
|
}
|
|
|
|
petMap := make(map[uint32]*model.PetInfo, total)
|
|
for _, petList := range petLists {
|
|
for i := range petList {
|
|
petMap[petList[i].CatchTime] = &petList[i]
|
|
}
|
|
}
|
|
return petMap
|
|
}
|
|
|
|
func buildOrderedPetList(
|
|
catchTimes []uint32,
|
|
petMap map[uint32]*model.PetInfo,
|
|
) []model.PetInfo {
|
|
result := make([]model.PetInfo, len(catchTimes))
|
|
for i, catchTime := range catchTimes {
|
|
result[i] = *petMap[catchTime]
|
|
}
|
|
return result
|
|
}
|
|
|
|
func validatePetBagOrder(
|
|
catchTimes []uint32,
|
|
bagCatchTimes map[uint32]struct{},
|
|
used map[uint32]struct{},
|
|
) bool {
|
|
for _, catchTime := range catchTimes {
|
|
if catchTime == 0 {
|
|
return false
|
|
}
|
|
if _, exists := bagCatchTimes[catchTime]; !exists {
|
|
return false
|
|
}
|
|
if _, exists := used[catchTime]; exists {
|
|
return false
|
|
}
|
|
used[catchTime] = struct{}{}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// GetUserBagPetInfo 返回主背包和并列备用精灵列表。
|
|
func (p *Player) GetUserBagPetInfo() *pet.GetUserBagPetInfoOutboundInfo {
|
|
|
|
result := &pet.GetUserBagPetInfoOutboundInfo{
|
|
PetList: p.Info.PetList,
|
|
BackupPetList: p.Info.BackupPetList,
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (p *Player) FindBackupPet(catchTime uint32) (int, *model.PetInfo, bool) {
|
|
return utils.FindWithIndex(p.Info.BackupPetList, func(petInfo model.PetInfo) bool {
|
|
|
|
return petInfo.CatchTime == catchTime
|
|
})
|
|
|
|
}
|
|
|
|
func (p *Player) FindPetBagSlot(catchTime uint32) (PetBagSlot, bool) {
|
|
if index, petInfo, ok := p.FindPet(catchTime); ok {
|
|
return PetBagSlot{
|
|
list: &p.Info.PetList,
|
|
index: index,
|
|
info: *petInfo,
|
|
main: true,
|
|
}, true
|
|
}
|
|
|
|
if index, petInfo, ok := p.FindBackupPet(catchTime); ok {
|
|
return PetBagSlot{
|
|
list: &p.Info.BackupPetList,
|
|
index: index,
|
|
info: *petInfo,
|
|
main: false,
|
|
}, true
|
|
}
|
|
|
|
return PetBagSlot{}, false
|
|
}
|
|
|
|
func (p *Player) AddPetToAvailableBag(petInfo model.PetInfo) bool {
|
|
if len(p.Info.PetList) < 6 {
|
|
p.Info.PetList = append(p.Info.PetList, petInfo)
|
|
return true
|
|
}
|
|
if len(p.Info.BackupPetList) < 6 {
|
|
p.Info.BackupPetList = append(p.Info.BackupPetList, petInfo)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (p *Player) RemoveBackupPet(catchTime uint32) {
|
|
p.Info.BackupPetList = removePetByCatchTime(p.Info.BackupPetList, catchTime)
|
|
}
|
|
|
|
func (p *Player) SavePetBagOrder(petList []uint32, backupPetList []uint32) bool {
|
|
if len(petList) > 6 || len(backupPetList) > 6 {
|
|
return false
|
|
}
|
|
|
|
totalPetCount := len(p.Info.PetList) + len(p.Info.BackupPetList)
|
|
if len(petList)+len(backupPetList) != totalPetCount {
|
|
return false
|
|
}
|
|
|
|
bagCatchTimes := buildCatchTimeSet(p.Info.PetList, p.Info.BackupPetList)
|
|
used := make(map[uint32]struct{}, totalPetCount)
|
|
|
|
if !validatePetBagOrder(petList, bagCatchTimes, used) {
|
|
return false
|
|
}
|
|
if !validatePetBagOrder(backupPetList, bagCatchTimes, used) {
|
|
return false
|
|
}
|
|
if len(used) != totalPetCount {
|
|
return false
|
|
}
|
|
|
|
petMap := buildPetInfoMap(p.Info.PetList, p.Info.BackupPetList)
|
|
p.Info.PetList = buildOrderedPetList(petList, petMap)
|
|
p.Info.BackupPetList = buildOrderedPetList(backupPetList, petMap)
|
|
return true
|
|
}
|