Files
bl/logic/service/player/pet.go

231 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package player
import (
"blazing/common/data/xmlres"
"blazing/logic/service/fight/info"
"math/rand"
"time"
"blazing/modules/blazing/model"
"math"
"github.com/gogf/gf/v2/util/gconv"
"github.com/jinzhu/copier"
)
// calculateExperience 计算指定等级和种族值所需的经验值
// level: 当前等级
// baseValue: 种族值
func calculateExperience(level uint32, baseValue uint32) uint32 {
// 计算 A 部分:向上取整(3.75 * a * (a + 1))
partA := math.Ceil(3.75 * float64(level) * float64(level+1))
// 计算 B 部分:向上取整(b * log(1 + a / 100))
// 这里使用自然对数 math.Log如果想换底数可以用换底公式
partB := math.Log(1.0 + float64(level)/100.0)
partB = float64(baseValue) * partB
partB = math.Ceil(partB)
// 总经验是两部分之和,并向上取整
totalExp := math.Ceil(partA + partB)
return uint32(totalExp)
}
// 主函数实现
// 添加经验
// 禁止发包
func (p *Player) AddPetExp(petinfo *model.PetInfo, addExp uint32, bro bool) {
originalLevel := petinfo.Level
petinfo.Exp += addExp
p.Info.ExpPool -= addExp //减去已使用的经验
for petinfo.Exp >= petinfo.NextLvExp {
petinfo.Level++
if originalLevel < 100 && petinfo.Level == 100 { //升到100了
p.Info.ExpPool += (petinfo.Exp) //减去已使用的经验
petinfo.Exp = 0
break //停止升级
}
basic := xmlres.PetMAP[int(petinfo.ID)]
// 检查是否可以进化
if basic.EvolvesTo != 0 && // 有明确的进化
int(petinfo.Level) >= basic.EvolvingLv && // 有明确的进化等级
basic.IsLarge == 0 { // 非最终形态
petinfo.ID = uint32(basic.EvolvesTo)
}
petinfo.Exp -= petinfo.NextLvExp
petinfo.LvExp = petinfo.NextLvExp
petinfo.NextLvExp = calculateExperience(petinfo.Level, basic.GetBasic())
}
// 重新计算面板
if originalLevel != petinfo.Level {
petinfo.Cure()
petinfo.CalculatePetPane()
}
if bro {
return
}
t1 := NewTomeeHeader(2508, p.Info.UserID)
rrr := &info.PetUpdateOutboundInfo{}
var petinfwo info.UpdatePropInfo
copier.Copy(&petinfwo, petinfo)
rrr.Data = append(rrr.Data, petinfwo)
p.SendPack(t1.Pack(rrr)) //准备包由各自发,因为协议不一样
// 发送经验更新消息
//player.SendMessage(generatePetUpdateInfo(petEntity, originalExp+addExp-exp, addition))
// 处理技能学习
canLearnSkillList := LastFourElements(petinfo.GetLevelRangeCanLearningSkills(originalLevel, petinfo.Level)) //获取最后四个技能,如果不足,那就取全部技能
for i := 0; i < 4; i++ {
if petinfo.SkillList[i].ID == 0 {
if len(canLearnSkillList) != 0 {
skid := canLearnSkillList[len(canLearnSkillList)-1]
petinfo.SkillList[i].ID = skid
petinfo.SkillList[i].PP = uint32(xmlres.SkillMap[int(skid)].MaxPP)
petinfo.SkillListLen += 1
canLearnSkillList = canLearnSkillList[:len(canLearnSkillList)-1]
}
}
}
//todo 待实现
// // 发送技能更新消息
// updateSkillInfo := UpdateSkillInfo{
// PetCatchTime: petEntity.captureTime,
// ActiveSkillNum: activeSkillNum,
// UnActiveSkillNum: unActiveSkillNum,
// SkillArray: canLearnSkillList,
// }
// player.SendMessage(UpdateSkillOutboundInfo{
// InfoArray: []UpdateSkillInfo{updateSkillInfo},
// })
// return exp
}
func LastFourElements[T any](s []T) []T {
n := len(s)
if n <= 4 {
// 切片长度小于等于4时返回整个切片
return s
}
// 切片长度大于4时返回最后4个元素从n-4索引到末尾
return s[n-4:]
}
// -1是随机
// * @param petTypeId 精灵类型ID
// * @param individualValue 个体值
// * @param natureId 性格ID
// * @param abilityTypeEnum 特性类型
// * @param isShiny 是否为闪光
// * @param level 等级
// * @return 生成的精灵实体
func (player *Player) GenPetInfo(id int, dv, natureId, abilityTypeEnum, shinyid, level int) *model.PetInfo {
// 设置随机数种子,确保每次运行生成不同的随机数序列
rand.Seed(time.Now().UnixNano())
p := &model.PetInfo{ID: uint32(id),
EffectInfo: make([]model.PetEffectInfo, 0),
CatchTime: uint32(time.Now().Unix()),
Level: uint32(level)} //等级
if shinyid != -1 {
p.Shiny = uint32(shinyid)
}
if natureId != -1 {
p.Nature = uint32(natureId)
} else {
p.Nature = uint32(rand.Intn(25))
}
if dv != -1 {
p.Dv = uint32(dv)
} else {
p.Dv = uint32(CalculateIndividualValue(rand.New(rand.NewSource(time.Now().UnixNano()))))
}
if abilityTypeEnum != -1 {
if abilityTypeEnum != 0 {
v := xmlres.PlayerEffectMAP[int(abilityTypeEnum)]
p.EffectInfo = append(p.EffectInfo, model.PetEffectInfo{
Idx: uint16(gconv.Int16(v.Idx)),
Status: 1,
EID: uint16(gconv.Int16(v.Eid)),
Args: v.ArgsS,
})
}
} else {
for i, v := range xmlres.PlayerEffectMAP {
if rand.Intn(len(xmlres.PlayerEffectMAP)) == i {
p.EffectInfo = append(p.EffectInfo, model.PetEffectInfo{
Idx: uint16(gconv.Int16(v.Idx)),
Status: 1,
EID: uint16(gconv.Int16(v.Eid)),
Args: v.ArgsS,
})
}
}
}
tttt := LastFourElements(p.GetLevelRangeCanLearningSkills(0, p.Level)) //获取最后四个技能,如果不足,那就取全部技能
for i := 0; i < len(tttt); i++ {
p.SkillList[i].ID = tttt[i]
p.SkillList[i].PP = uint32(xmlres.SkillMap[int(tttt[i])].MaxPP)
}
p.SkillListLen = uint32(len(tttt))
p.CalculatePetPane()
p.Hp = p.MaxHp
player.AddPetExp(p, 0, true)
return p
}
// 除数数组放大100倍
// 数组按递增顺序排列,用于判断个体值等级
var divisors = []int{
600, 1200, 1900, 2700, 3600, 4600, 5700, 6900, 8200, 9600,
11100, 12700, 14400, 16200, 18100, 20100, 22100, 24000,
25800, 27500, 29100, 30600, 32000, 33300, 34500, 35600,
36600, 37500, 38300, 39000, 39600,
}
// CalculateIndividual 根据给定的a值计算个体值
// 返回值表示a大于等于多少个除数范围0-31
func CalculateIndividual(a int) int {
individual := 0
for _, divisor := range divisors {
if a >= divisor {
individual++
} else {
break // 数组是递增的,可提前跳出循环
}
}
return individual
}
// CalculateIndividualValue 计算个体值0-31
// 接收外部随机数生成器,便于控制随机性和复用
func CalculateIndividualValue(random *rand.Rand) int {
// 生成0-40000的随机数作为个体值计算的输入
a := random.Intn(40001)
return CalculateIndividual(a)
}