| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 |
- package player
- import (
- "f1-game/internal/battle"
- capp "f1-game/internal/cherry_app"
- "f1-game/internal/code"
- "f1-game/internal/constant"
- "f1-game/internal/data"
- "f1-game/internal/enum"
- "f1-game/internal/event"
- "f1-game/internal/extend/math"
- nameEvent "f1-game/internal/name/event"
- nameLocal "f1-game/internal/name/local"
- "f1-game/internal/pb"
- "f1-game/internal/types"
- "f1-game/nodes/game/player/asset"
- ao "f1-game/nodes/game/player/asset/origin"
- "f1-game/nodes/game/player/chapter"
- "fmt"
- "time"
- ctime "github.com/cherry-game/cherry/extend/time"
- cfacade "github.com/cherry-game/cherry/facade"
- cproto "github.com/cherry-game/cherry/net/proto"
- )
- func (p *actorPlayer) initChapter() {
- p.Local().Register(nameLocal.Player_ChapterBattle, p.chapterBattle)
- p.Local().Register(nameLocal.Player_ChapterVerify, p.chapterVerify)
- p.Local().Register(nameLocal.Player_ChapterLevelSweep, p.chapterLevelSweep)
- p.Local().Register(nameLocal.Player_ChapterStarReward, p.chapterReward)
- p.Local().Register(nameLocal.Player_ChapterLevelTimesBuy, p.chapterLevelTimesBuy)
- p.Local().Register(nameLocal.Player_ChapterLastRecoverTime, p.chapterLastRecoverTime)
- p.Local().Register(nameLocal.Player_ChapterTakeOutStamina, p.chapterTakeOutStamina)
- p.EventRegister(nameEvent.Vip_LevelUp, p.chapterRefreshEvent)
- }
- // 发起探险战斗
- func (p *actorPlayer) chapterBattle(session *cproto.Session, req *pb.I32) {
- var (
- levelID = req.Value
- lineupID = constant.Adventure_Type // 阵容ID默认填1,如果后面扩展了再由前端传入
- )
- errCode := p.CheckChapterEnter(levelID)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- playerBattleParam, errCode := chapter.Service().GetChapterBattleCampParam(p.playerID, lineupID)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- chapterLevelRow, found := data.ChapterLevel.GetByID(levelID)
- if !found {
- p.ResponseCode(session, code.ConfigNotFound_ChapterLevel)
- return
- }
- var (
- chapterTable = p.ChapterTable()
- monsterGroupID = chapterLevelRow.MonsterGroupID
- battleSceneID = chapterLevelRow.BattleSceneID
- )
- monsterBattleParam := data.BuildBattleCampParam(monsterGroupID, enum.BattleCampType_Right)
- if len(monsterBattleParam.Squads) < 1 {
- p.ResponseCode(session, code.ChapterMonsterGroupConfigError)
- return
- }
- // 缓存关卡ID和随机种子
- battleRandomSeed := time.Now().UnixNano()
- battleParam := &pb.BattleParam{
- BattleType: enum.BattleType_Chapter,
- RandomSeed: uint64(battleRandomSeed),
- MapID: battleSceneID,
- Camps: []*pb.BattleCampParam{
- playerBattleParam,
- monsterBattleParam,
- },
- }
- // 发起战斗就直接去验证服获取校验码
- recordID := fmt.Sprintf("pve_%d_%d_%s", p.playerID, levelID, ctime.Now().ToShortDateTimeFormat())
- validation := battle.Validation(recordID, battleParam)
- if validation == nil {
- p.ResponseCode(session, code.ChapterBattleError)
- return
- }
- chapterTable.Chapter.SetBattleData(levelID, validation.Checksum)
- chapterTable.Save2Queue()
- p.Response(session, battleParam)
- }
- // 探险战斗验证
- func (p *actorPlayer) chapterVerify(session *cproto.Session, req *pb.BattleResult) {
- var (
- chapterTable = p.ChapterTable()
- )
- // 没有挑战过,返回失败
- if chapterTable.Chapter.BattleLevelID == 0 || chapterTable.Chapter.Checksum == 0 {
- p.ResponseCode(session, code.IllegalArgument)
- return
- }
- if capp.IsBattleValidation() && chapterTable.Chapter.Checksum != req.Checksum {
- p.Debug("chapterVerify checksum not match. req.Checksum = %d server.Checksum = %d", req.Checksum, chapterTable.Chapter.Checksum)
- p.ResponseCode(session, code.ChapterBattleResultVerifyFail)
- return
- }
- var (
- isWin = req.VictoriousCamp == enum.BattleCampType_Left
- rsp = &pb.ChapterVerifyResponse{
- Result: isWin,
- }
- )
- if isWin {
- challengeLevel, errCode := p.ChapterBattleResult(session, req)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- rsp.Challenge = challengeLevel
- }
- p.Response(session, rsp)
- }
- // 关卡扫荡
- func (p *actorPlayer) chapterLevelSweep(session *cproto.Session, req *pb.I32I32) {
- var (
- chapterTable = p.ChapterTable()
- levelID = req.Key
- sweepNum = req.Value
- )
- chapterLevelRow, found := data.ChapterLevel.GetByID(levelID)
- if !found {
- p.ResponseCode(session, code.ConfigNotFound_ChapterLevel)
- return
- }
- // 判断关卡是否解锁
- chapterLevel, found := chapterTable.Chapter.GetLevel(levelID)
- if !found {
- p.ResponseCode(session, code.ChapterLevelNotUnlocked)
- return
- }
- // 判断是否满星通关
- if chapterLevel.IsNotFullStar(len(chapterLevelRow.Conditions)) {
- p.ResponseCode(session, code.ChapterLevelNotFullStar)
- return
- }
- // 如果存在每日挑战次数上限
- if chapterLevelRow.DayChallengeCount > 0 {
- // 总挑战次数
- totalChallengeCount := chapterLevel.DayBuyChallengeCount + chapterLevelRow.DayChallengeCount
- // 判断条件次数是否满足
- if !chapterLevel.CheckChallengeCount(sweepNum, totalChallengeCount) {
- p.ResponseCode(session, code.ChapterLevelCountNotEnough)
- return
- }
- }
- var (
- beforeIsFull = chapterTable.Chapter.LastRecoverTime <= 0
- costs = chapterLevelRow.GetChapterLevelCost(sweepNum)
- )
- // 扣除精力
- _, errCode := asset.Service().Subs(p.playerID, costs, ao.ChapterLevelSweepCost)
- if code.IsFail(errCode) {
- p.ResponseCode(session, code.ChapterStaminaNotEnough)
- return
- }
- // 原来是满精力 判断扣除精力后精力是否还满
- if beforeIsFull {
- if full := chapter.Service().IsStaminaFull(p.playerID); !full {
- // 体力不满 更新上次精力的恢复时间
- chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
- }
- }
- var (
- resp = &pb.ChapterLevelSweepReward{}
- rewards = types.Assets{}
- )
- // 获取扫荡奖励
- for num := int32(0); num < sweepNum; num++ {
- // 扫荡一次随机奖励
- singleRewards := chapterLevelRow.RandomChapterLevelReward()
- rewards.AddAssets(singleRewards)
- proto := singleRewards.ToAssetListProto()
- resp.Rewards = append(resp.Rewards, &proto)
- }
- _, errCode = asset.Service().Adds(p.playerID, rewards, ao.ChapterLevelSweepReward, true)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- chapterLevel.DayChallengeCount += sweepNum
- chapterTable.Chapter.FinishChallengeCount += sweepNum
- chapterTable.Chapter.TotalSweepCount += sweepNum
- chapterTable.Save2Queue()
- // 发送探险次数事件
- p.PostEvent(event.NewChapterChallenge(p.playerID, levelID, sweepNum, true))
- // 关卡信息更新 通知客户端
- chapter.Service().ChangePush(p.playerID, levelID)
- // 返回扫荡奖励
- p.Response(session, resp)
- }
- // 领取累计星级奖励
- func (p *actorPlayer) chapterReward(session *cproto.Session, req *pb.I32) {
- var (
- chapterTable = p.ChapterTable()
- chapterID = req.Value
- )
- chapterRow, found := data.Chapter.GetByID(chapterID)
- if !found {
- p.ResponseCode(session, code.ConfigNotFound_Chapter)
- return
- }
- // 判断章节是否解锁
- if !chapterTable.Chapter.IsChapterUnlocked(chapterID) {
- p.ResponseCode(session, code.ChapterNotUnlocked)
- return
- }
- chapterRewardRows, found := data.ChapterReward.ListByID(chapterRow.RewardPoolID)
- if !found {
- p.ResponseCode(session, code.ConfigNotFound_ChapterReward)
- return
- }
- var (
- // 当前星级
- curStars = chapterTable.Chapter.GetChapterStar(chapterRow.StartID, chapterRow.EndID)
- rewards = types.Assets{}
- stars = []int32{}
- )
- for _, chapterRewardRow := range chapterRewardRows {
- star := chapterRewardRow.StarNum
- // 判断章节星级奖励是否已领取 已领取跳过
- if chapterTable.Chapter.IsRewardReceived(chapterID, star) {
- continue
- }
- // 判断星数不足,直接退出
- if curStars < star {
- break
- }
- rewards.AddAssets(chapterRewardRow.Reward)
- stars = append(stars, star)
- }
- // 暂无可领取奖励
- if rewards.IsEmpty() {
- p.ResponseCode(session, code.ChapterRewardIsEmpty)
- return
- }
- // 领取奖励
- _, errCode := asset.Service().Adds(p.playerID, rewards, ao.ChapterStarRewardGet, true)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 更新领取信息
- chapterReward := chapterTable.Chapter.ReceiveChapterReward(chapterID, stars...)
- chapterTable.Save2Queue()
- resp := chapterReward.ToChapterRewardProto()
- p.Response(session, resp)
- }
- // 探险关卡挑战次数购买
- func (p *actorPlayer) chapterLevelTimesBuy(session *cproto.Session, req *pb.I32I32) {
- var (
- chapterTable = p.ChapterTable()
- levelID = req.Key
- buyTimes = req.Value
- )
- if buyTimes <= 0 {
- p.ResponseCode(session, code.ChapterLevelBuyTimesError)
- return
- }
- chapterLevelRow, found := data.ChapterLevel.GetByID(levelID)
- if !found {
- p.ResponseCode(session, code.ConfigNotFound_ChapterLevel)
- return
- }
- level, found := chapterTable.Chapter.GetLevel(levelID)
- if !found {
- p.ResponseCode(session, code.ChapterLevelNotUnlocked)
- return
- }
- // 超出每日购买次数上限
- if level.DayBuyChallengeCount+buyTimes > chapterLevelRow.DayCanBuyTimes {
- p.ResponseCode(session, code.ChapterLevelBuyTimesNotEnough)
- return
- }
- cost := data.Const.ChapterTimesBuyCost
- _, errCode := asset.Service().Sub(p.playerID, cost.ID, cost.Num*int64(buyTimes), ao.ChapterLevelTimesBuyCost)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 更新关卡挑战购买次数
- level.DayBuyChallengeCount += buyTimes
- chapterTable.Save2Queue()
- // 更新关卡信息 通知客户端
- chapter.Service().ChangePush(p.playerID, levelID)
- p.ResponseCode(session, code.OK)
- }
- // 精力池上一次恢复时间
- func (p *actorPlayer) chapterLastRecoverTime(session *cproto.Session, _ *pb.None) {
- chapterTable := p.ChapterTable()
- resp := &pb.I64{
- Value: chapterTable.Chapter.LastRecoverTime,
- }
- p.Response(session, resp)
- }
- // 取出精力
- func (p *actorPlayer) chapterTakeOutStamina(session *cproto.Session, req *pb.I64) {
- var (
- chapterTable = p.ChapterTable()
- takeOutNum = req.Value
- )
- if takeOutNum <= 0 {
- p.ResponseCode(session, code.IllegalArgument)
- return
- }
- // 获取缺少的精力值
- var (
- curStaminaNum = asset.Service().Get(p.playerID, data.Const.ChapterStaminaAddValue.ID)
- staminaLimit = chapter.Service().GetStaminaLimit(p.playerID)
- diffStamina = staminaLimit - curStaminaNum
- )
- // 当前精力已满
- if diffStamina <= 0 {
- p.ResponseCode(session, code.ChapterStaminaFull)
- return
- }
- // 实际取出的精力值
- takeOutNum = math.Min(takeOutNum, diffStamina)
- // 判断消耗是否足够
- _, errCode := asset.Service().Sub(p.playerID, enum.ItemIDTempStamina, takeOutNum, ao.ChapterStaminaTakeOutCost)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 恢复精力值
- _, errCode = asset.Service().Add(p.playerID, data.Const.ChapterStaminaAddValue.ID, takeOutNum, ao.ChapterStaminaTakeOutReward, true)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 判断是否需要定时恢复精力
- if chapterTable.Chapter.LastRecoverTime <= 0 {
- chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
- chapterTable.Save2Queue()
- }
- resp := &pb.I64I64{
- Key: takeOutNum,
- Value: chapterTable.Chapter.LastRecoverTime,
- }
- p.Response(session, resp)
- }
- // vip升级触发精力恢复检测(vip提升精力&精力池上限)
- func (p *actorPlayer) chapterRefreshEvent(e cfacade.IEventData) {
- if _, ok := e.(*event.VipLevelUp); !ok {
- return
- }
- chapterTable := p.ChapterTable()
- if chapterTable.Chapter.LastRecoverTime > 0 {
- return
- }
- // 精力未满
- if staminaFull := chapter.Service().IsStaminaFull(p.playerID); !staminaFull {
- chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
- chapterTable.Save2Queue()
- return
- }
- // 精力池未满
- if staminaPoolFull := chapter.Service().IsStaminaPoolFull(p.playerID); !staminaPoolFull {
- chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
- chapterTable.Save2Queue()
- }
- }
- // 进入探险的检查
- func (p *actorPlayer) CheckChapterEnter(levelID int32) int32 {
- chapterLevelRow, found := data.ChapterLevel.GetByID(levelID)
- if !found {
- return code.ConfigNotFound_ChapterLevel
- }
- // 章节ID
- chapterID := chapterLevelRow.ChapterID
- chapterRow, found := data.Chapter.GetByID(chapterID)
- if !found {
- return code.ConfigNotFound_Chapter
- }
- // 验证当前章节是否有这个关卡
- if !chapterRow.VaildateLevel(levelID) {
- return code.ChapterLevelError
- }
- chapterTable := p.ChapterTable()
- // 章节是否已解锁
- if !chapterTable.Chapter.IsChapterUnlocked(chapterID) {
- return code.ChapterNotUnlocked
- }
- // 关卡是否已解锁
- if !chapterTable.Chapter.IsLevelUnlocked(levelID) {
- return code.ChapterLevelNotUnlocked
- }
- // 如果存在每日挑战次数上限 判断每日挑战次数是否达到上限
- if chapterLevelRow.DayChallengeCount > 0 {
- // 总挑战次数
- totalChallengeCount := chapterLevelRow.DayChallengeCount
- chapterLevel, found := chapterTable.Chapter.GetLevel(levelID)
- if found {
- totalChallengeCount += chapterLevel.DayBuyChallengeCount
- }
- // 判断是否存在进入次数 首次挑战也会扣除次数
- if !chapterTable.Chapter.CheckLevelChallengeCount(levelID, totalChallengeCount) {
- return code.ChapterLevelCountNotEnough
- }
- }
- // 检测精力是否足够
- errCode := asset.Service().IsAllEnough(p.playerID, chapterLevelRow.CostStamina)
- if code.IsFail(errCode) {
- return errCode
- }
- return code.OK
- }
- // 关卡挑战结果
- func (p *actorPlayer) ChapterBattleResult(session *cproto.Session, result *pb.BattleResult) (*pb.ChapterLevelChallenge, int32) {
- var (
- chapterTable = p.ChapterTable()
- levelID = chapterTable.Chapter.BattleLevelID
- )
- chapterLevelRow, found := data.ChapterLevel.GetByID(levelID)
- if !found {
- return nil, code.ConfigNotFound_ChapterLevel
- }
- chapterRow, found := data.Chapter.GetByID(chapterLevelRow.ChapterID)
- if !found {
- return nil, code.ConfigNotFound_Chapter
- }
- // 扣除体力前是否满体力
- beforeIsFull := chapterTable.Chapter.LastRecoverTime <= 0
- // 扣除精力
- _, errCode := asset.Service().Subs(p.playerID, chapterLevelRow.CostStamina, ao.ChapterLevelChallengeCost)
- if code.IsFail(errCode) {
- return nil, errCode
- }
- // 原来是满体力 判断扣除精力后精力是否还满
- if beforeIsFull {
- if full := chapter.Service().IsStaminaFull(p.playerID); !full {
- // 体力不满 更新上次精力的恢复时间
- chapterTable.Chapter.LastRecoverTime = ctime.Now().ToSecond()
- }
- }
- stars := chapter.Service().GetChapterStars(p.playerID, chapterLevelRow, result)
- // 更新关卡数据
- firstWin := chapterTable.Chapter.BattleEndHandle(levelID, stars)
- var (
- rewards types.Assets
- origin ao.Origin
- )
- // 首胜奖励
- if firstWin {
- rewards = chapterLevelRow.GetFirstRewards()
- origin = ao.ChapterLevelFirstReward
- } else {
- rewards = chapterLevelRow.RandomChapterLevelReward()
- origin = ao.ChapterLevelChallengeReward
- }
- // 发送首胜/挑战奖励
- _, errCode = asset.Service().Adds(p.playerID, rewards, origin, true)
- if code.IsFail(errCode) {
- p.Warn("chapter battle win add asset error: %v", errCode)
- }
- // 首胜检测是否更新下一章节或者下一关
- if firstWin {
- chapter.Service().CheckNextLevelOrChapter(chapterTable, chapterRow, levelID)
- }
- chapterTable.Chapter.FinishChallengeCount += 1
- // 清理战斗数据
- chapterTable.Chapter.ClearBattleData()
- chapterTable.Save2Queue()
- // 发送探险次数事件
- p.PostEvent(event.NewChapterChallenge(p.playerID, levelID, 1, false))
- level, _ := chapterTable.Chapter.GetLevel(levelID)
- challengeLevel := &pb.ChapterLevelChallenge{
- ChapterID: chapterTable.Chapter.ChapterID,
- LevelID: chapterTable.Chapter.LevelID,
- Level: level.ToChapterLevelProto(levelID),
- }
- // 奖励
- if !rewards.IsEmpty() {
- proto := rewards.ToAssetListProto()
- challengeLevel.Rewards = &proto
- }
- return challengeLevel, code.OK
- }
|