package chapter import ( "f1-game/internal/code" "f1-game/internal/constant" "f1-game/internal/data" "f1-game/internal/enum" facade "f1-game/internal/facade" nameRoute "f1-game/internal/name/route" "f1-game/internal/pb" "f1-game/internal/sessions" "f1-game/nodes/game/internal/db" "f1-game/nodes/game/player/asset" ao "f1-game/nodes/game/player/asset/origin" "f1-game/nodes/game/player/hero" "f1-game/nodes/game/player/vip" ctime "github.com/cherry-game/cherry/extend/time" clog "github.com/cherry-game/cherry/logger" cproto "github.com/cherry-game/cherry/net/proto" ) var srv = &service{ typ: newServiceType(), } func init() { } func Service() *service { return srv } type service struct { facade.PlayerServiceBase[*db.PlayerTable] typ serviceType // 星级类型类型服务类(封装各种星级完成细节) } func (p *service) OnLogin(playerTable *db.PlayerTable, session *cproto.Session) { chapterTable := db.GetChapterTable(playerTable.PlayerID) // 初始化 if chapterTable.Chapter.ChapterID == 0 && chapterTable.Chapter.LevelID == 0 { firstChapterRow, found := data.Chapter.GetFirstChapter() if !found { clog.Warnf("[playerID=%d]OnLogin chapter init fail") return } chapterTable.Chapter.ChapterID = firstChapterRow.ID chapterTable.Chapter.LevelID = firstChapterRow.StartID chapterTable.Save2Queue() } } func (p *service) OnReset(playerTable *db.PlayerTable, _ *ctime.CherryTime, byLogin bool) { var ( chapterTable = db.GetChapterTable(playerTable.PlayerID) updateLevelIDs = []int32{} ) // 跨天重置关卡挑战次数 for levelID, level := range chapterTable.Chapter.Levels { update := false // 重置挑战次数 if level.DayChallengeCount > 0 { level.DayChallengeCount = 0 update = true } // 重置购买挑战次数 if level.DayBuyChallengeCount > 0 { level.DayBuyChallengeCount = 0 update = true } if update { updateLevelIDs = append(updateLevelIDs, levelID) } } if len(updateLevelIDs) > 0 { chapterTable.Save2Queue() p.ChangePush(playerTable.PlayerID, updateLevelIDs...) clog.Infof("chapter reset level day challenge count, playerID = %d, updateLevelIDs = %v", playerTable.PlayerID, updateLevelIDs) } } // Push 探险数据推送 func (*service) Push(playerTable *db.PlayerTable, session *cproto.Session) { chapterTable := db.GetChapterTable(playerTable.PlayerID) rsp := chapterTable.Chapter.ToProto() sessions.PushWithSession(session, nameRoute.PushGamePlayer_Chapter, &rsp) } // ChangePush 关卡信息变更推送 func (p *service) ChangePush(playerID int64, updateLevelIDs ...int32) { if len(updateLevelIDs) < 1 { return } var ( chapterTable = db.GetChapterTable(playerID) levels = []*pb.ChapterLevel{} ) for _, levelID := range updateLevelIDs { level, found := chapterTable.Chapter.GetLevel(levelID) if found { levels = append(levels, level.ToChapterLevelProto(levelID)) } } if len(levels) < 1 { return } resp := &pb.UpdateChapterLevel{ ChapterID: chapterTable.Chapter.ChapterID, LevelID: chapterTable.Chapter.LevelID, Levels: levels, } sessions.PushPlayer(playerID, nameRoute.PushGamePlayer_ChapterLevel, resp) } // 精力定时恢复 func (p *service) StaminaRecoverTimer(playerID int64, nowSecond int64) { chapterTable := db.GetChapterTable(playerID) // 当前精力/精力池都已满 if chapterTable.Chapter.LastRecoverTime <= 0 { return } var ( staminaAddInterval = p.GetStaminaAddInterval(playerID) // 获取单次精力恢复时间间隔 diffSecond = nowSecond - chapterTable.Chapter.LastRecoverTime // 获取精力恢复间隔 addStaminaTimes = diffSecond / staminaAddInterval // 添加精力次数 ) // 需要恢复精力数量<=0 跳过 if addStaminaTimes <= 0 { return } var ( staminaID = data.Const.ChapterStaminaAddValue.ID staminaLimit = p.GetStaminaLimit(playerID) curStaminaNum = asset.Service().Get(playerID, staminaID) addStaminaNum = addStaminaTimes * data.Const.ChapterStaminaAddValue.Num // 添加精力数量 finalAddStaminaNum = addStaminaNum // 最终恢复精力数量 staminaFull = curStaminaNum >= staminaLimit ) // 当前精力未满 恢复精力 if !staminaFull { // 恢复精力超出上限 if curStaminaNum+finalAddStaminaNum > staminaLimit { finalAddStaminaNum = staminaLimit - curStaminaNum staminaFull = true } _, errCode := asset.Service().Add(playerID, staminaID, finalAddStaminaNum, ao.ChapterStaminaRecoverReward, true) if code.IsFail(errCode) { clog.Warnf("[StaminaRecoverTimer] recover stamina fail, playerID = %d, errCode = %d", playerID, errCode) return } addStaminaNum -= finalAddStaminaNum } // 当前仍有精力需要恢复 恢复精力池精力 if addStaminaNum > 0 { var ( curStaminaPoolValue = asset.Service().Get(playerID, enum.ItemIDTempStamina) staminaPoolLimit = p.GetStaminaPoolLimit(playerID) ) // 当前精力池精力未满 if curStaminaPoolValue < staminaPoolLimit { // 如果超出精力池上限 超出部分直接舍弃 if curStaminaPoolValue+addStaminaNum > staminaPoolLimit { addStaminaNum = staminaPoolLimit - curStaminaPoolValue } _, errCode := asset.Service().Add(playerID, enum.ItemIDTempStamina, addStaminaNum, ao.ChapterStaminaRecoverReward, true) if code.IsFail(errCode) { clog.Warnf("[StaminaRecoverTimer] recover temp stamina fail, playerID = %d, errCode = %d", playerID, errCode) return } finalAddStaminaNum += addStaminaNum } } update := false // 发生精力池精力恢复 if finalAddStaminaNum > 0 { // 更新最近一次恢复时间 chapterTable.Chapter.LastRecoverTime += addStaminaTimes * staminaAddInterval update = true } // 精力和精力池都到达上限 重置上一次恢复时间 if staminaFull && p.IsStaminaPoolFull(playerID) { chapterTable.Chapter.LastRecoverTime = 0 update = true } if update { chapterTable.Save2Queue() } } // 检测更新下一章节或者下一关 func (p *service) CheckNextLevelOrChapter(chapterTable *db.ChapterTable, chapterRow *data.ChapterRow, levelID int32) { // 当前章节未结束 切换到下一关 并 返回 if levelID < chapterRow.EndID { chapterTable.Chapter.LevelID++ return } // 判断是否存在下一章 nextChapterID := chapterRow.ID + 1 nextChapterRow, found := data.Chapter.GetByID(nextChapterID) if !found { return } // 下一章解锁条件不满足 返回 // TODO 感觉这个没什么用处 if !chapterTable.Chapter.IsLevelPassed(nextChapterRow.UnlockID) { return } chapterTable.Chapter.ChapterID = nextChapterID chapterTable.Chapter.LevelID = nextChapterRow.StartID } // 获取探险挑战星级情况 // TODO 传入战斗结束英雄数据和结果 func (p service) GetChapterStars(playerID int64, chapterLevelRow *data.ChapterLevelRow, result *pb.BattleResult) []int32 { stars := []int32{} if chapterLevelRow == nil { return stars } for _, condition := range chapterLevelRow.Conditions { chapterStarRow, found := data.ChapterStar.GetByID(condition) if !found { clog.Warnf("[playerID=%d]chapter star config not found: %d", playerID, condition) continue } parser, errCode := p.typ.get(chapterStarRow.Type) if code.IsFail(errCode) { clog.Warnf("[playerID=%d]chapter star type not found: %d", playerID, chapterStarRow.Type) continue } if parser.IsFinish(playerID, chapterStarRow, result) { stars = append(stars, condition) } } return stars } // 获取探险阵型的战斗参数 func (p *service) GetChapterBattleCampParam(playerID int64, lineupID int32) (*pb.BattleCampParam, int32) { var ( teamTable = db.GetLineupTable(playerID) heroTable = db.GetHeroTable(playerID) ) lineups, found := teamTable.LineupMap.GetLineups(constant.Adventure_Type) if !found { return nil, code.ChapterLineupNotFound } lineup, found := lineups.GetLineup(lineupID) if !found { return nil, code.ChapterLineupNotFound } if lineup.IsNotCanFight() { return nil, code.TeamIsEmpty } ret := &pb.BattleCampParam{ Camp: enum.BattleCampType_Left, PlayerID: playerID, } for _, member := range lineup.Members { if heroEntity, found := heroTable.Heroes.Get(member.HeroGUID); found { fighter := hero.Service().GetChapterFighter(playerID, heroEntity, lineupID) ret.Squads = append(ret.Squads, &pb.BattleSquadParam{ TileIndex: member.Index, Fighter: fighter, // Soldiers: nil, // 探险没有小兵 }) } } return ret, code.OK } // 获取精力上限 func (p *service) GetStaminaLimit(playerID int64) int64 { staminalLimit := data.Const.ChapterStaminaLimit // vip 精力上限加成 staminalLimit += vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaLimit) return staminalLimit } // 获取精力池上限 func (p *service) GetStaminaPoolLimit(playerID int64) int64 { playerTable, found := db.GetPlayerTable(playerID) if !found { return 0 } staminaPoolLimit := int64(0) // 领主等级加成 lordLevelRow, found := data.LordLevel.GetByLevel(playerTable.Lord.Level) if found { staminaPoolLimit += lordLevelRow.StaminaPoolLimit } // vip 精力池上限加成 staminaPoolLimit += vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaLimit) return staminaPoolLimit } // 获取精力恢复的时间间隔 func (p *service) GetStaminaAddInterval(playerID int64) int64 { staminalAddInterval := data.Const.ChapterStaminaAddInterval // vip 精力恢复时间加成(减少时间间隔) staminalAddInterval -= vip.Service().GetVipAttrAdd(playerID, enum.AttrStaminaRecoverTime) return max(0, staminalAddInterval) } // 检测精力是否已达上限 func (p *service) IsStaminaFull(playerID int64) bool { // 1.检测当前精力是否是满的 var ( curStaminaNum = asset.Service().Get(playerID, data.Const.ChapterStaminaAddValue.ID) staminaLimit = p.GetStaminaLimit(playerID) ) return curStaminaNum >= staminaLimit } // 检测精力池是否已达上限 func (p *service) IsStaminaPoolFull(playerID int64) bool { var ( curStaminaPoolValue = asset.Service().Get(playerID, enum.ItemIDTempStamina) staminaPoolLimit = p.GetStaminaPoolLimit(playerID) ) return curStaminaPoolValue >= staminaPoolLimit }