| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108 |
- package mapPlayer
- import (
- "f1-game/internal/battle"
- "f1-game/internal/code"
- "f1-game/internal/component/redis"
- "f1-game/internal/constant"
- "f1-game/internal/data"
- "f1-game/internal/enum"
- "f1-game/internal/event"
- "f1-game/internal/extend/math"
- nameActor "f1-game/internal/name/actor"
- nameLocal "f1-game/internal/name/local"
- nameRemote "f1-game/internal/name/remote"
- nameRoute "f1-game/internal/name/route"
- "f1-game/internal/pb"
- "f1-game/internal/sessions"
- "f1-game/internal/types"
- ao "f1-game/nodes/game/player/asset/origin"
- mapCall "f1-game/nodes/map/internal/call"
- "f1-game/nodes/map/internal/db"
- dbBattleReport "f1-game/nodes/map/internal/db/data/battle_report"
- "sort"
- cherryNUID "github.com/cherry-game/cherry/extend/nuid"
- ctime "github.com/cherry-game/cherry/extend/time"
- cfacade "github.com/cherry-game/cherry/facade"
- clog "github.com/cherry-game/cherry/logger"
- cproto "github.com/cherry-game/cherry/net/proto"
- )
- func (p *actorPlayer) initBattle() {
- p.Local().Register(nameLocal.MapPlayer_ReportInfo, p.reportInfo)
- p.Local().Register(nameLocal.MapPlayer_ReportList, p.reportList)
- p.Local().Register(nameLocal.MapPlayer_ReportLike, p.reportLike)
- p.Local().Register(nameLocal.MapPlayer_ReportRead, p.reportRead)
- p.Remote().Register(nameRemote.MapPlayer_BattleStart, p.battleStart)
- p.Remote().Register(nameRemote.MapPlayer_ReportAdd, p.reportAdd)
- // 初始化战斗处理函数
- p.initBattleHandler()
- }
- func (p *actorPlayer) initBattleHandler() {
- p.battleHandlers = map[enum.TileBattleType]func(*pb.BattleReq, *pb.BattleRsp){
- enum.TileBattle_PVP_Meet: p.battleStartPlayer,
- enum.TileBattle_PVP_Occupy: p.battleStartPlayer,
- enum.TileBattle_PVE_Occupy: p.battleStartRes,
- enum.TileBattle_PVE_SiegeGarrison: p.battleStartSiegePVE,
- enum.TileBattle_PVE_SiegeDurability: p.battleStartSiegePVE,
- enum.TileBattle_PVP_Siege: p.battleStartPlayer,
- enum.TileBattle_PVE_SnatchGarrison: p.battleStartSiegePVE,
- enum.TileBattle_PVP_Snatch: p.battleStartPlayer,
- enum.TileBattle_PVE_Snatch: p.battleStartSiegePVE,
- enum.TileBattle_PVE_Crusade: p.battleStartMonster,
- enum.TileBattle_PVN_SiegeDurability: p.battleStartSiegePVN,
- enum.TileBattle_PVN_Snatch: p.battleStartSiegePVN,
- }
- }
- // 个人战报列表
- func (p *actorPlayer) reportList(session *cproto.Session, req *pb.I32Str) {
- var (
- mapPlayerReportTable = db.GetMapPlayerReportTable(p.playerID)
- category = enum.ReportCategory(req.Key) // 分类 0:全部 1:开拓 2:交战 3:侦察
- groupID = req.Value // 战报组ID
- rsp = &pb.ReportGroupList{}
- )
- // 根据分类和战报组ID来精确获取战报组列表
- reportGroups := dbBattleReport.FilterReportGroups(mapPlayerReportTable.BattleReport.Groups, category, groupID, data.Const.MapBattleReportPage)
- if len(reportGroups) == 0 {
- p.Response(session, rsp)
- return
- }
- var (
- groupIDList []string // 战报组ID列表
- reportIDList []string // 战报ID列表
- )
- for _, group := range reportGroups {
- groupIDList = append(groupIDList, group.GroupID)
- }
- // 批量获取战报组ID对应的战报ID列表
- reportIDMap := redis.Game.GetReportIDListOfGroup(groupIDList...)
- for _, ids := range reportIDMap {
- reportIDList = append(reportIDList, ids...)
- }
- // 从redis批量获取战报集合
- reportMap := redis.Game.GetBattleReports(reportIDList...)
- for _, group := range reportGroups {
- groupProto := group.ToProto(reportIDMap, reportMap, false)
- if groupProto == nil {
- continue
- }
- rsp.List = append(rsp.List, groupProto)
- }
- p.Response(session, rsp)
- }
- // 个人收藏战报和未读数量信息
- func (p *actorPlayer) reportInfo(session *cproto.Session, _ *pb.None) {
- var (
- mapPlayerReportTable = db.GetMapPlayerReportTable(p.playerID)
- groupIDList []string // 战报组ID列表
- reportIDList []string // 战报ID列表
- )
- likes := mapPlayerReportTable.BattleReport.Likes
- for _, like := range likes {
- switch like.LikeType {
- case enum.ReportLikeType_Group:
- groupIDList = append(groupIDList, like.LikeID)
- case enum.ReportLikeType_Report:
- reportIDList = append(reportIDList, like.LikeID)
- }
- }
- // 获取战报组ID对应的战报ID列表
- groupReportIDMap := redis.Game.GetReportIDListOfGroup(groupIDList...)
- for _, ids := range groupReportIDMap {
- reportIDList = append(reportIDList, ids...)
- }
- // 从redis批量获取战报信息
- reportIDMap := redis.Game.GetBattleReports(reportIDList...)
- var likeList []*pb.ReportLike
- for _, like := range likes {
- var reportList []*pb.Report
- switch like.LikeType {
- case enum.ReportLikeType_Group:
- for _, reportID := range groupReportIDMap[like.LikeID] {
- if report, ok := reportIDMap[reportID]; ok {
- reportList = append(reportList, report)
- }
- }
- case enum.ReportLikeType_Report:
- if report, ok := reportIDMap[like.LikeID]; ok {
- reportList = append(reportList, report)
- }
- }
- if len(reportList) == 0 {
- continue
- }
- if len(reportList) > 1 {
- sort.Slice(reportList, func(i, j int) bool {
- return reportList[i].Time > reportList[j].Time
- })
- }
- likeList = append(likeList, like.ToProto(reportList))
- }
- p.Response(session, &pb.ReportInfo{
- Count: mapPlayerReportTable.BattleReport.GetUnreadCount(),
- List: likeList,
- })
- }
- // 收藏战报或取消收藏
- func (p *actorPlayer) reportLike(session *cproto.Session, req *pb.ReportLikeRequest) {
- if req.LikeType < 0 || req.LikeID == "" {
- p.ResponseCode(session, code.IllegalArgument)
- return
- }
- var (
- mapPlayerReportTable = db.GetMapPlayerReportTable(p.playerID)
- likeType = enum.ReportLikeType(req.LikeType) // 收藏类型 1:战报组 2:单个战报
- likeID = req.LikeID // 收藏ID
- isLike = req.IsLike // 是否收藏 true:收藏 false:取消收藏
- )
- if !isLike { // 取消收藏
- if mapPlayerReportTable.BattleReport.IsLike(likeType, likeID) {
- mapPlayerReportTable.BattleReport.RemoveLike(likeType, likeID)
- mapPlayerReportTable.Save2Queue()
- }
- p.ResponseCode(session, code.OK)
- return
- }
- // 检查战报组或战报是否存在
- switch likeType {
- case enum.ReportLikeType_Group:
- if len(redis.Game.GetReportIDListOfGroup(likeID)) == 0 {
- p.ResponseCode(session, code.BattleReportNotExist)
- return
- }
- case enum.ReportLikeType_Report:
- if len(redis.Game.GetBattleReports(likeID)) == 0 {
- p.ResponseCode(session, code.BattleReportNotExist)
- return
- }
- default:
- p.ResponseCode(session, code.IllegalArgument)
- return
- }
- // 已经收藏过
- if mapPlayerReportTable.BattleReport.IsLike(likeType, likeID) {
- p.ResponseCode(session, code.OK)
- return
- }
- mapPlayerReportTable.BattleReport.AddLike(likeType, likeID, ctime.Now().ToSecond())
- mapPlayerReportTable.Save2Queue()
- p.ResponseCode(session, code.OK)
- }
- // 战报一键阅读
- func (p *actorPlayer) reportRead(session *cproto.Session, req *pb.Str) {
- var (
- mapPlayerReportTable = db.GetMapPlayerReportTable(p.playerID)
- groupID = req.Value // 战报组ID 0:全部
- )
- ok := mapPlayerReportTable.BattleReport.Read(groupID)
- if !ok {
- p.ResponseCode(session, code.BattleReportNotExist)
- return
- }
- mapPlayerReportTable.Save2Queue()
- p.ResponseCode(session, code.OK)
- }
- // 增加战报组
- func (p *actorPlayer) reportAdd(reportGroup *pb.ReportGroup) {
- if len(reportGroup.List) < 1 {
- return
- }
- // 战报放入redis
- redis.Game.AddReports(reportGroup.GroupID, reportGroup.List...)
- // 添加个人战报记录
- mapPlayerReportTable := db.GetMapPlayerReportTable(p.playerID)
- dbBattleReport.AddReportGroup(&mapPlayerReportTable.BattleReport.Groups, reportGroup.GroupID, enum.ReportCategory(reportGroup.Category), reportGroup.List[0].Time)
- mapPlayerReportTable.Save2Queue()
- // 通知客户端
- sessions.PushPlayer(p.playerID, nameRoute.PushMapPlayer_ReportNew, reportGroup)
- playerTable := db.GetMapPlayerTable(p.playerID)
- if playerTable != nil && playerTable.LeagueID > 0 && !enum.IsDurabilityBattle(enum.TileBattleType(reportGroup.List[0].BattleType)) {
- // 添加联盟战报
- mapCall.League.BattleReportAdd(playerTable.LeagueID, reportGroup)
- }
- // 发送战斗结果事件
- p.PostEvent(event.NewBattleResult(p.playerID, reportGroup))
- }
- // 根据玩家ID从战斗参数里获取玩家部队信息
- func getTeamDataByPlayerID(battleReq *pb.BattleReq, playerID int64) *pb.BattleTeamData {
- for _, attacker := range battleReq.Attackers {
- if attacker.PlayerID == playerID {
- return attacker
- }
- }
- return battleReq.Defender
- }
- // 构建战报
- func (p *actorPlayer) buildReportGroup(battleReq *pb.BattleReq, attacker *pb.BattleCampParam, defender *pb.BattleCampParam,
- resultVerify *pb.BattleResult, isDefender bool, recordID string, feat int64) *pb.ReportGroup {
- attackerTeamData := getTeamDataByPlayerID(battleReq, attacker.PlayerID)
- defenderTeamData := getTeamDataByPlayerID(battleReq, defender.PlayerID)
- report := &pb.Report{
- ReportID: cherryNUID.Next(),
- BattleType: battleReq.BattleType,
- Point: battleReq.Tile.Point,
- ConfigID: battleReq.Tile.ObjectConfigID,
- Time: ctime.Now().ToMillisecond(),
- BattleRecordID: recordID,
- Attacker: buildReportTeam(attackerTeamData, attacker, resultVerify),
- Defender: buildReportTeam(defenderTeamData, defender, resultVerify),
- IsDefender: isDefender,
- }
- var (
- groupID = attackerTeamData.ReportGroupID // 战报组
- result = resultVerify.VictoriousCamp // TODO 战斗结果 战斗验证逻辑会有平局,但是现有业务逻辑判断只有胜负
- )
- if isDefender { // 防守方取反
- switch resultVerify.VictoriousCamp {
- case enum.BattleCampType_Left:
- result = enum.BattleCampType_Right
- case enum.BattleCampType_Right:
- result = enum.BattleCampType_Left
- }
- groupID = battleReq.Defender.ReportGroupID
- }
- // 战斗结果 0:赢
- report.Result = result
- // 扣除耐久
- report.ReportResult = &pb.ReportResult{
- Rewards: &pb.AssetList{
- List: []*pb.Asset{},
- },
- }
- // 进攻方赢,防守方输才显示战果,耐久,资源
- if isDefender {
- if result != enum.BattleCampType_Left {
- // 被扣除了耐久
- report.ReportResult.Durability = battleReq.Durability
- // 被掠夺了资源
- if battleReq.Rewards != nil {
- for _, reward := range battleReq.Rewards.List {
- report.ReportResult.Rewards.List = append(report.ReportResult.Rewards.List, reward)
- }
- }
- }
- } else {
- if result == enum.BattleCampType_Left {
- // 扣除耐久
- report.ReportResult.Durability = battleReq.Durability
- // 获得的资源
- if battleReq.Rewards != nil {
- for _, reward := range battleReq.Rewards.List {
- report.ReportResult.Rewards.List = append(report.ReportResult.Rewards.List, reward)
- }
- }
- }
- }
- // 功勋
- if feat > 0 {
- report.ReportResult.Rewards.List = append(report.ReportResult.Rewards.List, &pb.Asset{
- Id: enum.ItemIDFeat,
- Num: feat,
- })
- }
- // TODO 战报分类 新增侦察类型再进行判断处理
- category := enum.ReportCategory_PVE
- if enum.IsTilePVPBattle(enum.TileBattleType(battleReq.BattleType)) {
- category = enum.ReportCategory_PVP
- }
- // 如果地图没有给战报组ID,则生成一个唯一的战报组ID避免战报无法记录,最多就是单独的一个战报
- if len(groupID) == 0 {
- groupID = cherryNUID.Next()
- }
- return &pb.ReportGroup{
- GroupID: groupID,
- Category: int32(category),
- List: []*pb.Report{report},
- }
- }
- func buildReportTeam(battleTeamData *pb.BattleTeamData, camp *pb.BattleCampParam, resultVerify *pb.BattleResult) *pb.BattleReportTeam {
- if camp == nil {
- return nil
- }
- team := &pb.BattleReportTeam{}
- for _, squad := range camp.Squads {
- squadResult := battle.GetBattleSquadResult(camp.Camp, squad.Fighter.Id, resultVerify)
- team.List = append(team.List, &pb.BattleReportObject{
- Id: squad.Fighter.Id,
- ObjConfigID: squad.Fighter.ConfigID,
- BattleObjType: squad.Fighter.BattleObjType,
- Level: squad.Fighter.Level,
- Star: squad.Fighter.Star,
- LineupID: squad.TileIndex,
- IsDead: squadResult.FighterResult.IsDead,
- TroopsID: squad.TroopsID,
- TotalSoldier: squad.TroopsNum,
- RemainSoldier: squadResult.SoldierNum,
- MaxHealth: battle.GetMaxHealth(squad.Fighter.Attrs),
- Health: squadResult.FighterResult.Hp,
- })
- }
- // 玩家信息
- if battleTeamData != nil {
- team.PlayerID = battleTeamData.PlayerID
- team.PlayerName = battleTeamData.PlayerName
- team.LeagueID = battleTeamData.LeagueID
- team.LeagueName = battleTeamData.LeagueName
- }
- return team
- }
- // 守军战斗逻辑, 返回是否胜利
- func (p *actorPlayer) onBattleDefend(req *pb.BattleReq, attackerServerParam *pb.ServerBattleCampParam, teamBattleDamage *pb.TeamBattleDamage, defender *pb.BattleCampParam, monsterIndex int32) (int64, bool) {
- var (
- playerTable = db.GetMapPlayerTable(p.playerID)
- attacker = attackerServerParam.Param
- )
- // 设置守军参数
- setDefendBattleParam(playerTable, req.Tile.ObjectID, monsterIndex, defender)
- // 判断守军是否还能参战,兵力都为0就跳过
- if checkDefendSoldier(playerTable, req.Tile.ObjectID, monsterIndex) {
- return 0, true
- }
- // 录像ID
- recordID := cherryNUID.Next()
- // 战斗验证
- resultVerify, isVerify := p.battleVerify(recordID, attacker, defender)
- if resultVerify == nil {
- return 0, false
- }
- // 如果不是战斗验证的没有录像
- if !isVerify {
- recordID = ""
- }
- // 构建战报
- reportGroup := p.buildReportGroup(req, attacker, defender, resultVerify, false, recordID, 0)
- p.reportAdd(reportGroup)
- // 如果打的地块有归属也需要构建对方战报
- if req.Defender.PlayerID > 0 {
- defenderReport := p.buildReportGroup(req, defender, attacker, resultVerify, true, recordID, 0)
- mapCall.Player.BattleReportAdd(req.Defender.PlayerID, defenderReport)
- }
- // 更新进攻方兵力
- battle.UpdateBattleParam(attacker, resultVerify)
- // 战斗结束后保存守军信息
- recoverTime := saveDefendStatus(playerTable, req.Tile.ObjectID, monsterIndex, resultVerify)
- // 记录进攻方剩余兵力
- recordBattleSoldierNum(teamBattleDamage, attackerServerParam.HeroTeamIndex, battle.GetBattleCampResult(resultVerify, enum.BattleCampType_Left))
- return recoverTime, resultVerify.VictoriousCamp == enum.BattleCampType_Left
- }
- // 战斗验证
- func (p *actorPlayer) battleVerify(recordID string, attacker *pb.BattleCampParam, defender *pb.BattleCampParam) (*pb.BattleResult, bool) {
- // 构建战斗参数
- param := &pb.BattleParam{
- MapID: 2, //TODO 根据战斗的类型配置不同的战斗地图ID
- RandomSeed: uint64(ctime.Now().ToMillisecond()),
- BattleType: enum.BattleType_SLG,
- Camps: []*pb.BattleCampParam{
- attacker,
- defender,
- },
- GenerateConfigData: true, // 设置生成配置数据,战斗验证结果会返回配置数据
- }
- // 只要双方有战斗小队数量为0直接构建战斗结果
- if !battle.CheckBattleSquadTroopsNum(attacker) || !battle.CheckBattleSquadTroopsNum(defender) {
- return battle.BuildValidationResult(param), false
- }
- // 验证战斗结果
- return battle.Validation(recordID, param), true
- }
- func (p *actorPlayer) battleStart(req *pb.BattleReq) {
- rsp := &pb.BattleRsp{
- Data: req,
- }
- battleType := enum.TileBattleType(req.BattleType)
- if fn, ok := p.battleHandlers[battleType]; ok {
- fn(req, rsp)
- } else {
- p.Error("battleStart battleType = %d, not found", battleType)
- }
- // 打耐久的战斗不需要返回,只需要记录战报
- if battleType != enum.TileBattle_PVN_SiegeDurability {
- // 把战斗结果返回给map
- mapCall.Logic.BattleEnd(rsp)
- }
- }
- // battleStartSiegePVE 与攻城守军战斗
- func (p *actorPlayer) battleStartSiegePVE(req *pb.BattleReq, rsp *pb.BattleRsp) {
- // 批量构建进攻方战斗数据
- battleParamMap, ok := battle.GetServerBattleCampParams(req)
- if !ok {
- p.Error("battleStartSiegePVE GetServerBattleCampParams error")
- return
- }
- if len(req.Tile.Monsters) == 0 {
- p.Warn("battleStartSiegePVE failed. tileID = %d, monsters is empty", req.Tile.Id)
- return
- }
- monsterGroupID := req.Tile.Monsters[0]
- defender := data.BuildBattleCampParam(monsterGroupID, enum.BattleCampType_Right)
- if len(defender.Squads) == 0 {
- p.Warn("battleStartSiegePVE failed. tileID = %d, monsterGroupID = %d", req.Tile.Id, monsterGroupID)
- return
- }
- // 构建进攻方数据
- var (
- attackerTeamData = req.Attackers[0]
- attackerServerParam = battleParamMap[attackerTeamData.PlayerID]
- attacker = attackerServerParam.Param
- attackerTeamBattleDamage = battle.NewTeamBattleDamage(attackerTeamData.TeamID, attackerTeamData.ObjectID)
- )
- // 记录战斗之前的兵力
- recordBattleTroops(attackerTeamBattleDamage, attackerServerParam)
- // 录像ID
- recordID := cherryNUID.Next()
- // 战斗验证
- resultVerify, isVerify := p.battleVerify(recordID, attacker, defender)
- if resultVerify == nil {
- p.Warn("battleStartSiegePVE verify failed. tileID = %d, monsterGroupID = %d", req.Tile.Id, monsterGroupID)
- return
- }
- // 如果不是战斗验证的没有录像
- if !isVerify {
- recordID = ""
- }
- // 构建战报
- reportGroup := p.buildReportGroup(req, attacker, defender, resultVerify, false, recordID, 0)
- if p.playerID == attackerTeamData.PlayerID {
- p.reportAdd(reportGroup)
- } else {
- mapCall.Player.BattleReportAdd(attackerTeamData.PlayerID, reportGroup)
- }
- // 如果打建筑有归属也需要构建对方战报
- if req.Defender.PlayerID > 0 || req.Defender.LeagueID > 0 {
- defenderReport := p.buildReportGroup(req, defender, attacker, resultVerify, true, "", 0)
- if req.Defender.PlayerID > 0 {
- mapCall.Player.BattleReportAdd(req.Defender.PlayerID, defenderReport)
- }
- if req.Defender.LeagueID > 0 {
- mapCall.League.BattleReportAdd(req.Defender.LeagueID, defenderReport)
- }
- }
- // 记录进攻方剩余兵力
- recordBattleSoldierNum(attackerTeamBattleDamage, attackerServerParam.HeroTeamIndex, battle.GetBattleCampResult(resultVerify, enum.BattleCampType_Left))
- // 更新进攻方兵力
- battle.UpdateBattleParam(attacker, resultVerify)
- // 更新防守方兵力
- troopLoss := battle.UpdateBattleParam(defender, resultVerify)
- if troopLoss > 0 {
- attackerTeamBattleDamage.KillTroops += troopLoss
- }
- // 把战损扣除的兵力带回去
- rsp.MarchTroops = append(rsp.MarchTroops, convertMarchSyncTroops(attackerTeamBattleDamage))
- // 兵力扣除和更新
- p.subTeamTroopsNum(attackerTeamBattleDamage)
- rsp.IsWin = resultVerify.VictoriousCamp == enum.BattleCampType_Left
- if !rsp.IsWin {
- // 失败设置重伤
- var (
- injuresTime = ctime.Now().ToSecond() + data.Const.GetHeroInjureTime()
- arg = &pb.I32I64{Key: attackerTeamData.TeamID, Value: injuresTime}
- )
- p.setTeamInjury(arg)
- }
- }
- // battleStartSiegePVN 无守军的拆耐久战
- func (p *actorPlayer) battleStartSiegePVN(req *pb.BattleReq, rsp *pb.BattleRsp) {
- // 批量构建进攻方战斗数据
- battleParamMap, ok := battle.GetServerBattleCampParams(req)
- if !ok {
- p.Error("battleStartSiegePVN GetServerBattleCampParams error")
- return
- }
- // 构建一个没有小队的敌方阵营战斗参数
- defender := &pb.BattleCampParam{
- Camp: enum.BattleCampType_Right,
- Squads: []*pb.BattleSquadParam{},
- }
- // 构建进攻方数据
- var (
- attackerTeamData = req.Attackers[0]
- attackerServerParam = battleParamMap[attackerTeamData.PlayerID]
- attacker = attackerServerParam.Param
- )
- // 战斗验证,走自动构建的战斗结果
- resultVerify, _ := p.battleVerify("", attacker, defender)
- // 构建战报
- reportGroup := p.buildReportGroup(req, attacker, defender, resultVerify, false, "", 0)
- p.reportAdd(reportGroup)
- // 建筑有归属也需要构建对方战报,互斥,优先判断归属是玩家
- if req.Defender.PlayerID > 0 || req.Defender.LeagueID > 0 {
- defenderReport := p.buildReportGroup(req, defender, attacker, resultVerify, true, "", 0)
- if req.Defender.PlayerID > 0 {
- mapCall.Player.BattleReportAdd(req.Defender.PlayerID, defenderReport)
- } else if req.Defender.LeagueID > 0 {
- // 联盟建筑,单独添加到对应联盟战报里去
- mapCall.League.BattleReportAdd(req.Defender.LeagueID, defenderReport)
- }
- }
- }
- // battleStartPlayer 玩家交战
- func (p *actorPlayer) battleStartPlayer(req *pb.BattleReq, rsp *pb.BattleRsp) {
- battleParamMap, ok := battle.GetServerBattleCampParams(req)
- if !ok {
- p.Error("battleStartPlayer GetServerBattleCampParams error")
- return
- }
- var (
- // 进攻方的战斗数据实时构建
- attackerTeamData = req.Attackers[0]
- attacker = battleParamMap[attackerTeamData.PlayerID]
- attackerBattleDamage = battle.NewTeamBattleDamage(attackerTeamData.TeamID, attackerTeamData.ObjectID)
- // 对方战斗数据从redis中获取
- defender = battleParamMap[req.Defender.PlayerID]
- defenderBattleDamage = battle.NewTeamBattleDamage(req.Defender.TeamID, req.Defender.ObjectID)
- )
- recordBattleTroops(attackerBattleDamage, attacker)
- recordBattleTroops(defenderBattleDamage, defender)
- // 录像ID
- recordID := cherryNUID.Next()
- // 战斗验证
- resultVerify, isVerify := p.battleVerify(recordID, attacker.Param, defender.Param)
- if resultVerify == nil {
- return
- }
- // 如果不是战斗验证的没有录像
- if !isVerify {
- recordID = ""
- }
- // 更新进攻方剩余兵力
- recordBattleSoldierNum(attackerBattleDamage, attacker.HeroTeamIndex, battle.GetBattleCampResult(resultVerify, enum.BattleCampType_Left))
- // 更新防守方剩余兵力
- recordBattleSoldierNum(defenderBattleDamage, defender.HeroTeamIndex, battle.GetBattleCampResult(resultVerify, enum.BattleCampType_Right))
- // 攻击方功勋
- attackerFeat := calAndSendBattleGetFeatNum(attacker, attackerBattleDamage)
- // 防守方功勋
- defenderFeat := calAndSendBattleGetFeatNum(defender, defenderBattleDamage)
- // 构建战报
- reportGroup := p.buildReportGroup(req, attacker.Param, defender.Param, resultVerify, false, recordID, attackerFeat)
- // 给进攻方发送战报
- p.reportAdd(reportGroup)
- // 构建对方战报
- defenderReport := p.buildReportGroup(req, defender.Param, attacker.Param, resultVerify, true, recordID, defenderFeat)
- // 给对方发送战报
- mapCall.Player.BattleReportAdd(req.Defender.PlayerID, defenderReport)
- // 更新进攻方兵力
- battle.UpdateBattleParam(attacker.Param, resultVerify)
- // 更新防守方兵力
- battle.UpdateBattleParam(defender.Param, resultVerify)
- // 通知更新进攻方兵力
- p.subTeamTroopsNum(attackerBattleDamage)
- // 通知更新防守兵力变化
- mapCall.Player.SubTeamTroopsNum(req.Defender.PlayerID, defenderBattleDamage)
- // 把战损扣除的兵力带回去
- rsp.MarchTroops = append(rsp.MarchTroops, convertMarchSyncTroops(attackerBattleDamage), convertMarchSyncTroops(defenderBattleDamage))
- if resultVerify.VictoriousCamp == enum.BattleCampType_Left {
- rsp.IsWin = true
- }
- // 重伤时间
- var injuresTime = ctime.Now().ToSecond() + data.Const.GetHeroInjureTime()
- if rsp.IsWin {
- // 胜利设置对方玩家重伤
- arg := &pb.I32I64{Key: req.Defender.TeamID, Value: injuresTime}
- targetPath := cfacade.NewChildPath("", nameActor.Map_Player, req.Defender.PlayerID)
- p.Call(targetPath, nameRemote.MapPlayer_SetTeamInjury, arg)
- } else {
- // 失败设置重伤
- arg := &pb.I32I64{Key: attackerTeamData.TeamID, Value: injuresTime}
- p.setTeamInjury(arg)
- }
- }
- // 单人和多人组队讨伐
- func (p *actorPlayer) battleStartMonster(req *pb.BattleReq, rsp *pb.BattleRsp) {
- if len(req.Tile.Monsters) == 0 {
- p.Warn("battle start monster failed, monster is empty. resID = %d", req.Tile.Id)
- return
- }
- // 批量构建进攻方战斗数据
- battleParamMap, ok := battle.GetServerBattleCampParams(req)
- if !ok {
- p.Error("battleStartMonster GetServerBattleCampParams error")
- return
- }
- // 构建进攻方数据
- teamBattleDamageMap := map[int64]*pb.TeamBattleDamage{}
- for _, attacker := range req.Attackers {
- attackerBattleParam, found := battleParamMap[attacker.PlayerID]
- if found {
- teamBattleDamage := battle.NewTeamBattleDamage(attacker.TeamID, attacker.ObjectID)
- // 记录战斗之前的兵力
- recordBattleTroops(teamBattleDamage, attackerBattleParam)
- // 记录所有玩家的部队战斗兵力数据,战前兵力和剩余兵力
- teamBattleDamageMap[attacker.PlayerID] = teamBattleDamage
- } else {
- p.Warn("battle start monster failed, player not found. playerID = %d", attacker.PlayerID)
- }
- }
- var (
- attackerIndex int = 0 // 按照顺序打,打完一个接着打,输了就给下一个继续打
- )
- for index, monsterGroupID := range req.Tile.Monsters {
- defender := data.BuildBattleCampParam(monsterGroupID, enum.BattleCampType_Right)
- if len(defender.Squads) == 0 {
- p.Warn("battle start monster failed. tileID = %d, monsterGroupID = %d", req.Tile.Id, monsterGroupID)
- return
- }
- for i := attackerIndex; i < len(req.Attackers); i++ {
- var (
- attacker = req.Attackers[i] // 进攻方请求数据
- attackerParam = battleParamMap[attacker.PlayerID] // 进攻方战斗数据
- attackerBattleDemage = teamBattleDamageMap[attacker.PlayerID] // 进攻方战损记录
- )
- isWin := p.onBattleMonster(req, attackerParam, attackerBattleDemage, defender, monsterGroupID)
- // 打赢了就跳出循环打下一个怪
- if isWin {
- // 全部打完了
- if index == len(req.Tile.Monsters)-1 {
- if isWin {
- rsp.IsWin = true
- }
- // 获取进攻方兵力
- if p.playerID == attacker.PlayerID {
- p.subTeamTroopsNum(attackerBattleDemage)
- } else {
- // 给对方发送兵力变化
- mapCall.Player.SubTeamTroopsNum(attacker.PlayerID, attackerBattleDemage)
- }
- }
- break
- } else {
- if p.playerID == attacker.PlayerID {
- p.subTeamTroopsNum(attackerBattleDemage)
- } else {
- // 给对方发送兵力变化
- mapCall.Player.SubTeamTroopsNum(attacker.PlayerID, attackerBattleDemage)
- }
- var (
- injuresTime = ctime.Now().ToSecond() + data.Const.GetHeroInjureTime()
- arg = &pb.I32I64{Key: attacker.TeamID, Value: injuresTime}
- )
- // 如果打输了,就设置重伤状态
- if p.playerID == attacker.PlayerID {
- p.setTeamInjury(arg)
- } else {
- targetPath := cfacade.NewChildPath("", nameActor.Map_Player, req.Defender.PlayerID)
- p.Call(targetPath, nameRemote.MapPlayer_SetTeamInjury, arg)
- }
- // 打输了就给下一个继续打
- attackerIndex++
- }
- }
- // 如果所有人都打完了,还没有打赢,就算输了
- if attackerIndex >= len(req.Attackers) {
- break
- }
- }
- // 把战损扣除的兵力带回去
- for _, marchSyncTroops := range teamBattleDamageMap {
- rsp.MarchTroops = append(rsp.MarchTroops, convertMarchSyncTroops(marchSyncTroops))
- }
- }
- func (p *actorPlayer) onBattleMonster(req *pb.BattleReq, attackerParam *pb.ServerBattleCampParam, attackerBattleDemage *pb.TeamBattleDamage, defender *pb.BattleCampParam, monsterGroupID int32) bool {
- // 进攻方战斗参数
- attacker := attackerParam.Param
- // 录像ID
- recordID := cherryNUID.Next()
- // 战斗验证
- resultVerify, isVerify := p.battleVerify(recordID, attacker, defender)
- if resultVerify == nil {
- p.Warn("onBattleMonster battle verify failed. tileID = %d, monsterGroupID = %d", req.Tile.Id, monsterGroupID)
- return false
- }
- // 如果不是战斗验证的没有录像
- if !isVerify {
- recordID = ""
- }
- // 构建战报
- reportGroup := p.buildReportGroup(req, attacker, defender, resultVerify, false, recordID, 0)
- if p.playerID == attacker.PlayerID {
- p.reportAdd(reportGroup)
- } else {
- mapCall.Player.BattleReportAdd(attacker.PlayerID, reportGroup)
- }
- // 记录进攻方剩余兵力
- recordBattleSoldierNum(attackerBattleDemage, attackerParam.HeroTeamIndex, battle.GetBattleCampResult(resultVerify, enum.BattleCampType_Left))
- // 更新进攻方兵力
- battle.UpdateBattleParam(attacker, resultVerify)
- // 更新防守方兵力
- troopLoss := battle.UpdateBattleParam(defender, resultVerify)
- if troopLoss > 0 {
- attackerBattleDemage.KillTroops += troopLoss
- }
- // 打赢了就跳出循环打下一个怪
- return resultVerify.VictoriousCamp == enum.BattleCampType_Left
- }
- // battleStartRes 资源守军战
- func (p *actorPlayer) battleStartRes(req *pb.BattleReq, rsp *pb.BattleRsp) {
- if len(req.Tile.Monsters) == 0 {
- p.Warn("battle start res failed, monster is empty. resID = %d", req.Tile.Id)
- return
- }
- // 批量构建进攻方战斗数据
- battleParamMap, ok := battle.GetServerBattleCampParams(req)
- if !ok {
- p.Error("battleStartRes GetServerBattleCampParams error")
- return
- }
- var (
- attackerTeamData = req.Attackers[0]
- attackerServerParam = battleParamMap[attackerTeamData.PlayerID]
- attackerTeamBattleDamage = battle.NewTeamBattleDamage(attackerTeamData.TeamID, attackerTeamData.ObjectID)
- )
- // 记录战斗之前的兵力
- recordBattleTroops(attackerTeamBattleDamage, attackerServerParam)
- var (
- isWin bool // 是否胜利
- recoverTime int64 // 资源恢复时间
- )
- for index, monsterGroupID := range req.Tile.Monsters {
- defender := data.BuildBattleCampParam(monsterGroupID, enum.BattleCampType_Right)
- if len(defender.Squads) == 0 {
- p.Warn("battleStartRes failed. tileID = %d, monsterGroupID = %d", req.Tile.Id, monsterGroupID)
- break
- }
- // 进入战斗
- retRecoverTime, retIsWin := p.onBattleDefend(req, attackerServerParam, attackerTeamBattleDamage, defender, int32(index))
- if retRecoverTime > 0 {
- recoverTime = retRecoverTime
- }
- if !retIsWin {
- break
- }
- // 全部打完才算赢
- if index == len(req.Tile.Monsters)-1 {
- isWin = true
- }
- }
- rsp.IsWin = isWin
- // 胜利就清空守军状态信息
- if rsp.IsWin {
- playerTable := db.GetMapPlayerTable(p.playerID)
- playerTable.Defends.CleanDefend(req.Tile.ObjectID)
- } else {
- // 失败则通知恢复时间
- if recoverTime > 0 {
- sessions.PushPlayer(p.playerID, nameRoute.PushMapPlayer_ResDefendRecover, &pb.I64I64{
- Key: req.Tile.ObjectID,
- Value: recoverTime,
- })
- }
- }
- // 把战损扣除的兵力带回去
- rsp.MarchTroops = append(rsp.MarchTroops, convertMarchSyncTroops(attackerTeamBattleDamage))
- // 兵力扣除和更新
- p.subTeamTroopsNum(attackerTeamBattleDamage)
- if !rsp.IsWin {
- var (
- injuresTime = ctime.Now().ToSecond() + data.Const.GetHeroInjureTime()
- arg = &pb.I32I64{Key: req.Attackers[0].TeamID, Value: injuresTime}
- )
- // 失败设置重伤
- p.setTeamInjury(arg)
- }
- }
- // 记录战斗之前的兵力
- func recordBattleTroops(teamBattleDamage *pb.TeamBattleDamage, serverParam *pb.ServerBattleCampParam) {
- for _, squad := range serverParam.Param.Squads {
- teamIndex := serverParam.HeroTeamIndex.Value[squad.Fighter.Id]
- teamBattleDamage.Members[teamIndex] = &pb.TeamMemberDamage{
- TeamIndex: teamIndex,
- TroopsNum: squad.TroopsNum,
- }
- }
- }
- // 记录剩余兵力
- func recordBattleSoldierNum(teamBattleDamage *pb.TeamBattleDamage, heroTeamIndex *pb.I64I32Map, battleCampResult *pb.BattleCampResult) {
- for _, marchTroops := range teamBattleDamage.Members {
- for _, squad := range battleCampResult.SquadResults {
- if heroTeamIndex.Value[squad.FighterResult.Id] == marchTroops.TeamIndex {
- marchTroops.SoldierNum = squad.SoldierNum
- break
- }
- }
- }
- }
- // 计算pvp战斗获得的功勋值
- func calAndSendBattleGetFeatNum(battle *pb.ServerBattleCampParam, damage *pb.TeamBattleDamage) int64 {
- playerID := battle.Param.PlayerID
- if playerID <= 0 {
- return 0
- }
- // 获得功勋值
- featNum := int64(0)
- for _, squad := range battle.Param.Squads {
- armTypeRow, found := data.ArmType.GetByID(squad.TroopsID)
- if !found {
- clog.Warnf("[CalBattleFeatNum] armType not found. playerID=%d, squadID=%d", battle.Param.PlayerID, squad.TroopsID)
- continue
- }
- armLevelRow, found := data.ArmLevel.GetByLevel(armTypeRow.Level)
- if !found {
- clog.Warnf("[CalBattleFeatNum] armLevel not found. playerID=%d, squadID=%d", battle.Param.PlayerID, squad.TroopsID)
- continue
- }
- // 基础值
- featNum += armLevelRow.BaseFeat
- // 计算出伤兵
- teamIndex := battle.HeroTeamIndex.Value[squad.Fighter.Id]
- memberGamage, found := damage.Members[teamIndex]
- if !found {
- clog.Warnf("[CalBattleFeatNum] memberGamage not found. playerID=%d, squadID=%d, teamIndex=%d", battle.Param.PlayerID, squad.TroopsID, teamIndex)
- continue
- }
- lossTroops := float64(memberGamage.TroopsNum - memberGamage.SoldierNum)
- // 万分比系数 向下取整
- featNum += math.Floor[float64, int64](lossTroops * (float64(armLevelRow.FeatRatio) / constant.FRatioBase))
- }
- if featNum <= 0 {
- return featNum
- }
- // 发送功勋奖励
- assets := types.Assets{}
- assets.Add(enum.ItemIDFeat, featNum)
- mapCall.Player.AddAssets(playerID, assets, ao.None)
- return featNum
- }
- // 转换成同步兵力结构
- func convertMarchSyncTroops(teamBattleDamage *pb.TeamBattleDamage) *pb.MarchSyncTroops {
- var troops []*pb.MarchTroops
- for _, member := range teamBattleDamage.Members {
- troops = append(troops, &pb.MarchTroops{
- TeamIndex: member.TeamIndex,
- TroopsNum: max(0, member.TroopsNum-member.SoldierNum),
- })
- }
- return &pb.MarchSyncTroops{
- TeamID: teamBattleDamage.TeamID,
- ObjectID: teamBattleDamage.ObjectID,
- Troops: troops,
- KillTroops: teamBattleDamage.KillTroops,
- }
- }
- // 设置守军战斗参数
- func setDefendBattleParam(playerTable *db.MapPlayerTable, objectID int64, monsterIndex int32, defender *pb.BattleCampParam) {
- var newSquads []*pb.BattleSquadParam // 新的守军列表
- for _, squad := range defender.Squads {
- defend, found := playerTable.Defends.GetDefend(objectID)
- if found {
- defendStatus, found := defend.GetDefendStatus(monsterIndex, squad.Fighter.Id)
- if found {
- // 剩余兵力
- squad.TroopsNum = defendStatus.RemainSoldier
- }
- }
- // 剩余兵力为0的就过滤掉
- if squad.TroopsNum > 0 {
- newSquads = append(newSquads, squad)
- }
- }
- defender.Squads = newSquads
- }
- // 检查守军剩余小兵数量是否为0
- func checkDefendSoldier(playerTable *db.MapPlayerTable, objectID int64, monsterIndex int32) bool {
- defend, found := playerTable.Defends.GetDefend(objectID)
- if !found {
- return false
- }
- // 记录是否存在
- var isExist bool
- for _, status := range defend.DefendStatusMap {
- if status.MonsterIndex == monsterIndex {
- isExist = true
- if status.RemainSoldier > 0 {
- return false
- }
- }
- }
- // 没有记录就返回false
- if !isExist {
- return false
- }
- return true
- }
- // 保存守军状态
- func saveDefendStatus(playerTable *db.MapPlayerTable, objectID int64, monsterIndex int32, battleResult *pb.BattleResult) int64 {
- var recoverTime int64
- for _, result := range battleResult.CampResult {
- if result.Camp == enum.BattleCampType_Right {
- for _, squad := range result.SquadResults {
- defend, isNew := playerTable.Defends.GetOrCreateDefend(objectID)
- if isNew {
- recoverTime = defend.RecoverTime
- }
- defend.UpdateDefendStatus(monsterIndex, squad.FighterResult.Id, squad.SoldierNum)
- }
- }
- }
- return recoverTime
- }
|