package mapPlayer import ( "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/times" nameEvent "f1-game/internal/name/event" 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" dbMapPlayer "f1-game/nodes/map/internal/db/data/player" mapFacade "f1-game/nodes/map/internal/facade" "f1-game/nodes/map/player/hero" "f1-game/nodes/map/player/team" 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) initPlayerTeam() { p.Local().Register(nameLocal.MapPlayer_TeamUp, p.teamUp) p.Local().Register(nameLocal.MapPlayer_TeamLeave, p.teamLeave) p.Local().Register(nameLocal.MapPlayer_TeamChange, p.teamChange) p.Local().Register(nameLocal.MapPlayer_TeamInnerChange, p.teamInnerChange) p.Local().Register(nameLocal.MapPlayer_TeamLineup, p.teamLineup) p.Local().Register(nameLocal.MapPlayer_TeamTroops, p.teamTroops) p.Local().Register(nameLocal.MapPlayer_TeamAutoTroops, p.teamAutoTroops) p.Local().Register(nameLocal.MapPlayer_TeamOutsideTroops, p.teamOutsideTroops) p.Local().Register(nameLocal.MapPlayer_TeamOutsideTroopsCancel, p.teamOutsideTroopsCancel) p.Local().Register(nameLocal.MapPlayer_TeamOutsideAutoTroopsSet, p.teamOutsideAutoTroopsSet) p.Remote().Register(nameRemote.MapPlayer_UseMedicine, p.useMedicine) p.Remote().Register(nameRemote.MapPlayer_SubTeamTroopsNum, p.subTeamTroopsNum) p.Remote().Register(nameRemote.MapPlayer_UpdateTeamState, p.updateTeamState) p.Remote().Register(nameRemote.MapPlayer_SetTeamInjury, p.setTeamInjury) p.Remote().Register(nameRemote.MapPlayer_MarchArrive, p.marchArrive) // TODO: 可以把上面的更新都合并到这里 p.Remote().Register(nameRemote.MapPlayer_UpdateTeam, p.updateTeam) //p.EventRegister(nameEvent.Map_MarchArrive, p.marchArrive) p.EventRegister(nameEvent.Lord_FacilityUp, p.onFacilityUpRefreshTeam) } // teamUp 英雄上阵 func (p *actorPlayer) teamUp(session *cproto.Session, req *pb.TeamUpRequest) { playerTable := db.GetMapPlayerTable(p.playerID) var ( heroGUID = req.HeroGUID teamID = req.TeamID teamIndex = req.TeamIndex index = req.Index ) // 部队位置是否合法 if !constant.ValidateTeamMemberTeamIndex(teamIndex) { p.ResponseCode(session, code.TeamIndexError) return } // 检测阵容位置是否正确 if !constant.ValidateTeamMemberIndex(index) { p.ResponseCode(session, code.TeamLineupIndexError) return } // 获取英雄数据 heroEntity, found := playerTable.GetHero(heroGUID) if !found { p.ResponseCode(session, code.HeroNotExist) return } if heroEntity.IsAlreadyTeamUp() { p.ResponseCode(session, code.TeamHeroAlreadyUp) return } if _, ok := data.HeroTeam.Get(teamID); !ok { p.ResponseCode(session, code.ConfigNotFound_HeroTeam) return } curTeam, ok := playerTable.Teams.GetTeam(teamID) if !ok { p.ResponseCode(session, code.TeamNotUnlock) return } if curTeam.IsNotStandby() { p.ResponseCode(session, code.TeamIsBusy) return } //检测是否存在相同英雄 过滤上阵位置英雄 if team.Service().CheckTeamSameHero(playerTable, heroEntity.HeroID, 0, 0, teamID, teamIndex) { p.ResponseCode(session, code.TeamAlreadySameHero) return } updateHeros := []*dbMapPlayer.Hero{} // 先下阵旧的英雄 如果存在 oldHero, errCode := team.Service().DoTeamLeave(playerTable, curTeam, teamIndex) if code.IsOK(errCode) && oldHero != nil { updateHeros = append(updateHeros, oldHero) } // 当前位置不存在英雄 判断上阵人数上限 if curTeam.IsTeamMemberLimit() { p.ResponseCode(session, code.TeamMemberLimit) return } // 检测阵容位置是否存在英雄 if curTeam.IsLineupMemberExist(index) { p.ResponseCode(session, code.TeamIndexHasHero) return } // 英雄上阵 curTeam.NewAndAddTeamMember(heroGUID, teamIndex, index, heroEntity.InjuriesEndTime) // 重新刷新上阵英雄阵容位置 team.Service().RefreshTeamLineup(playerTable, curTeam) // 更新队伍羁绊列表 p.updateTeamFetterList(curTeam) heroEntity.TeamID = teamID playerTable.Save2Queue() updateHeros = append(updateHeros, heroEntity) // 推送英雄变化 hero.Service().ChangePush(p.playerID, updateHeros...) proto := curTeam.ToProto() p.Response(session, &proto) // 同步到 redis 队伍信息 team.Service().UpdatePlayerTeams(p.playerID, curTeam) p.PostEvent(event.NewTeamUp(p.playerID, teamID)) } // teamLeave 英雄下阵 func (p *actorPlayer) teamLeave(session *cproto.Session, req *pb.I32I32) { var ( playerTable = db.GetMapPlayerTable(p.playerID) teamID, teamIndex = req.Key, req.Value ) if playerTable == nil { p.ResponseCode(session, code.PlayerNotFound) return } curTeam, ok := playerTable.Teams.GetTeam(teamID) if !ok { p.ResponseCode(session, code.TeamNotUnlock) return } if curTeam.IsNotStandby() { p.ResponseCode(session, code.TeamIsBusy) return } //执行英雄下阵 heroEntity, errCode := team.Service().DoTeamLeave(playerTable, curTeam, teamIndex) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } if heroEntity != nil { // 更新队伍羁绊列表 p.updateTeamFetterList(curTeam) playerTable.Save2Queue() // 推送英雄变化 hero.Service().ChangePush(p.playerID, heroEntity) // 同步到 redis 队伍信息 team.Service().UpdatePlayerTeams(p.playerID, curTeam) } proto := curTeam.ToProto() p.Response(session, &proto) } // teamChange 英雄换阵 func (p *actorPlayer) teamChange(session *cproto.Session, req *pb.TeamChangeRequest) { var ( playerTable = db.GetMapPlayerTable(p.playerID) changeHeroes []*dbMapPlayer.Hero srcTeamID = req.SrcTeamID dstTeamID = req.DstTeamID srcTeamIndex = req.SrcTeamIndex dstTeamIndex = req.DstTeamIndex dstIndex = req.DstIndex ) if srcTeamID == dstTeamID && srcTeamIndex == dstTeamIndex { p.ResponseCode(session, code.TeamIndexNotChange) return } //判断队伍位置是否合法 if !constant.ValidateTeamMemberTeamIndex(srcTeamIndex, dstTeamIndex) { p.ResponseCode(session, code.TeamIndexError) return } // 判断队伍阵容位置是否合法 if !constant.ValidateTeamMemberIndex(dstIndex) { p.ResponseCode(session, code.TeamLineupIndexError) return } srcTeam, ok := playerTable.Teams.GetTeam(srcTeamID) if !ok { p.ResponseCode(session, code.TeamNotUnlock) return } if srcTeam.IsNotStandby() { p.ResponseCode(session, code.TeamIsBusy) return } srcTeamMember, ok := srcTeam.GetTeamMember(srcTeamIndex) if !ok || srcTeamMember.HeroGUID == 0 { p.ResponseCode(session, code.HeroNotInTeam) return } srcHero, ok := playerTable.Heroes.Get(srcTeamMember.HeroGUID) if !ok { p.ResponseCode(session, code.HeroNotExist) return } dstTeam, ok := playerTable.Teams.GetTeam(dstTeamID) if !ok { p.ResponseCode(session, code.TeamNotUnlock) return } if dstTeam.IsNotStandby() { p.ResponseCode(session, code.TeamIsBusy) return } //不同队伍 检测是否上阵相同英雄 if team.Service().CheckTeamSameHero(playerTable, srcHero.HeroID, srcTeamID, srcTeamIndex, dstTeamID, dstTeamIndex) { p.ResponseCode(session, code.TeamAlreadySameHero) return } // 被替换位置检测英雄下阵 dstHero, errCode := team.Service().DoTeamLeave(playerTable, dstTeam, dstTeamIndex) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } if dstHero != nil { changeHeroes = append(changeHeroes, dstHero) } // 判断当前目标队伍是否达到队伍成员上限 if srcTeamID != dstTeamID && dstTeam.IsTeamMemberLimit() { p.ResponseCode(session, code.TeamMemberLimit) return } // 判断目标队伍阵容位置是否存在英雄 if dstTeam.IsLineupMemberExist(dstIndex) { p.ResponseCode(session, code.TeamIndexHasHero) return } srcTeam.DelTeamMember(srcTeamIndex) // 更新英雄所属队伍ID 换成目标队伍位置并添加到目标队伍中 删除原来队伍的位置数据 srcHero.TeamID = dstTeamID srcTeamMember.TeamIndex = dstTeamIndex srcTeamMember.Index = dstIndex if dstHero != nil { srcTeamMember.InjureEndTime = dstHero.InjuriesEndTime } dstTeam.AddTeamMember(srcTeamMember) // 重新刷新上阵英雄阵容位置 team.Service().RefreshTeamLineup(playerTable, dstTeam) // 更新源队伍&目标队伍羁绊列表 p.updateTeamFetterList(srcTeam, dstTeam) playerTable.Save2Queue() changeHeroes = append(changeHeroes, srcHero) // 推送英雄变化 hero.Service().ChangePush(p.playerID, changeHeroes...) // 同步队伍变更信息 team.Service().ChangePush(p.playerID, srcTeam, dstTeam) // 同步到 redis 队伍信息 team.Service().UpdatePlayerTeams(p.playerID, srcTeam, dstTeam) p.ResponseCode(session, code.OK) } // teamInnerChange 同队伍内换队伍位置 func (p *actorPlayer) teamInnerChange(session *cproto.Session, req *pb.TeamInnerChangeRequest) { var ( playerTable = db.GetMapPlayerTable(p.playerID) teamID = req.TeamID srcTeamIndex = req.SrcTeamIndex dstTeamIndex = req.DstTeamIndex ) // 位置无变化 if srcTeamIndex == dstTeamIndex { p.ResponseCode(session, code.TeamIndexNotChange) return } curTeam, found := playerTable.Teams.GetTeam(teamID) if !found { p.ResponseCode(session, code.TeamNotUnlock) return } if curTeam.IsNotStandby() { p.ResponseCode(session, code.TeamIsBusy) return } if !constant.ValidateTeamMemberTeamIndex(srcTeamIndex, dstTeamIndex) { p.ResponseCode(session, code.TeamIndexError) return } srcTeamMember, found := curTeam.GetTeamMember(srcTeamIndex) if !found { p.ResponseCode(session, code.HeroNotInTeam) return } srcHero, found := playerTable.Heroes.Get(srcTeamMember.HeroGUID) if !found { p.ResponseCode(session, code.HeroNotExist) return } changeHeroes := []*dbMapPlayer.Hero{srcHero} // 更换队伍位置 dstTeamMember, found := curTeam.GetTeamMember(dstTeamIndex) if !found { srcTeamMember.TeamIndex = dstTeamIndex } else { dstHero, found := playerTable.Heroes.Get(dstTeamMember.HeroGUID) if !found { p.ResponseCode(session, code.HeroNotExist) return } srcTeamMember.TeamIndex, dstTeamMember.TeamIndex = dstTeamMember.TeamIndex, srcTeamMember.TeamIndex // 如果被替换的位置原来是主将位置, 则需要检测是否需要返还溢出兵力 p.teamInnerChangeReturTroops(dstTeamMember, dstTeamIndex, srcTeamIndex) changeHeroes = append(changeHeroes, dstHero) } // 如果替换的位置原来是主将位置 则也需要返还溢出的兵力 p.teamInnerChangeReturTroops(srcTeamMember, srcTeamIndex, dstTeamIndex) // 重新刷新上阵英雄阵容位置 team.Service().RefreshTeamLineup(playerTable, curTeam) playerTable.Save2Queue() // 推送英雄变化 hero.Service().ChangePush(p.playerID, changeHeroes...) // 同步到 redis 队伍信息 team.Service().UpdatePlayerTeams(p.playerID, curTeam) proto := curTeam.ToProto() p.Response(session, &proto) } // 队伍内位置切换 如果原来位置是主将位置 当前位置不是主将位置 则返还溢出的兵力 func (p *actorPlayer) teamInnerChangeReturTroops(teamMember *dbMapPlayer.TeamMember, srcTeamIndex, dstTeamIndex int32) { if !constant.IsTeamMainIndex(srcTeamIndex) { return } playerTable := db.GetMapPlayerTable(p.playerID) heroEntity, found := playerTable.Heroes.Get(teamMember.HeroGUID) if !found { p.Warn("teamInnerChangeReturTroops: hero not found, heroGUID: %d", teamMember.HeroGUID) return } curTroopsNumLimit := team.Service().GetHeroTroopsNum(p.playerID, heroEntity.HeroID, dstTeamIndex) diffTroopsNum := teamMember.TroopsNum - curTroopsNumLimit if diffTroopsNum <= 0 { return } teamMember.TroopsNum = curTroopsNumLimit // 返还兵力 mapFacade.Storage.AssetAddOne(p.playerID, teamMember.TroopsID, int64(diffTroopsNum), ao.TeamInnerChangeReturn) } // teamLineup 英雄阵容设置 func (p *actorPlayer) teamLineup(session *cproto.Session, req *pb.TeamLineupRequest) { var ( playerTable = db.GetMapPlayerTable(p.playerID) teamID = req.TeamID index = req.Index toIndex = req.ToIndex ) curTeam, ok := playerTable.Teams.GetTeam(teamID) if !ok { p.ResponseCode(session, code.TeamNotUnlock) return } //检测部队位置是否合法 if !constant.ValidateTeamMemberIndex(index, toIndex) { p.ResponseCode(session, code.TeamIndexError) return } fromTeamMember, ok := curTeam.GetTeamMemberByIndex(index) if !ok || fromTeamMember.HeroGUID == 0 { p.ResponseCode(session, code.HeroNotInTeam) return } if fromTeamMember.Index == toIndex { p.ResponseCode(session, code.TeamIndexNotChange) return } //获取交换对象 如果原来位置存在英雄 则交换阵容位置 否则直接修改位置 toTeamMember, found := curTeam.GetTeamMemberByIndex(toIndex) if found { //交换 fromTeamMember.Index, toTeamMember.Index = toTeamMember.Index, fromTeamMember.Index } else { fromTeamMember.Index = toIndex } // 检测刷新阵容 team.Service().RefreshTeamLineup(playerTable, curTeam) playerTable.Save2Queue() proto := curTeam.ToProto() p.Response(session, &proto) // TODO 后面如果阵容有加成也需要同步到 redis // team.Service().UpdatePlayerTeams(p.playerID, curTeam) } // teamTroops 队伍补兵 func (p *actorPlayer) teamTroops(session *cproto.Session, req *pb.TeamTroopsRequest) { var ( playerTable = db.GetMapPlayerTable(p.playerID) memberTroops = req.MemberTroops ) if len(memberTroops) <= 0 { p.ResponseCode(session, code.IllegalArgument) return } curTeam, ok := playerTable.Teams.GetTeam(req.TeamID) if !ok { p.ResponseCode(session, code.TeamNotUnlock) return } if curTeam.IsNotStandby() { p.ResponseCode(session, code.TeamIsBusy) return } // 分兵等级分组 key : 士兵ID value: 成员队伍位置 value 分兵数量 groupMemberTroopMap, errCode := p.groupTroops(memberTroops) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } var ( // 最终统兵情况 key: 队伍位置 value: key: 士兵ID 士兵等级表ID value: 分兵数量 finalMemberTroops = map[int32]*pb.I32I32{} costAssets = types.Assets{} ) for troopsID, troopsMap := range groupMemberTroopMap { _, found := data.ArmLevel.GetByID(troopsID) if !found { p.ResponseCode(session, code.ConfigNotExist_Conscript) return } // 获取最终分兵情况&消耗士兵数量 costTroopsNum := p.GetFinalTeamTroopNum(curTeam, troopsID, troopsMap, finalMemberTroops) if costTroopsNum <= 0 { p.ResponseCode(session, code.TeamArmExceed) return } costAssets.Add(troopsID, int64(costTroopsNum)) } // 消耗士兵 _, errCode = mapFacade.Storage.AssetSubs(p.playerID, costAssets, ao.TeamTroopsCost) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } // 返还&重置英雄原带兵数量&更新英雄带兵ID p.returnAndResetTeamMemberTroopsNum(curTeam, groupMemberTroopMap) // 更新队伍上阵英雄带兵数量 curTeam.UpdateTeamMemberTroopsNum(finalMemberTroops) playerTable.Save2Queue() // 同步到 redis 队伍信息 team.Service().UpdatePlayerTeams(p.playerID, curTeam) proto := curTeam.ToProto() p.Response(session, &proto) // 发送分兵事件 p.PostEvent(event.NewTeamTroops(p.playerID, curTeam.TeamID)) } // teamAutoTroops 自动补兵设置 func (p *actorPlayer) teamAutoTroops(session *cproto.Session, req *pb.I32) { var ( playerTable = db.GetMapPlayerTable(p.playerID) teamID = req.Value ) team, ok := playerTable.Teams.GetTeam(teamID) if !ok { p.ResponseCode(session, code.TeamNotUnlock) return } team.AutoAddTroops = !team.AutoAddTroops playerTable.Save2Queue() p.ResponseCode(session, code.OK) } // 分兵分组 key: 士兵ID value: 队伍阵容位置 value 分兵数量 func (p *actorPlayer) groupTroops(memberTroops []*pb.TeamMemberTroops) (map[int32]map[int32]int32, int32) { memberTroopMap := map[int32]map[int32]int32{} for _, memberTroop := range memberTroops { // 检测队伍位置是否正确 if !constant.ValidateTeamMemberTeamIndex(memberTroop.TeamIndex) { return nil, code.TeamIndexError } if memberTroop.TroopsNum <= 0 { return nil, code.TeamTroopsNumError } troopsMap, exist := memberTroopMap[memberTroop.TroopsID] if !exist { troopsMap = map[int32]int32{} memberTroopMap[memberTroop.TroopsID] = troopsMap } troopsMap[memberTroop.TeamIndex] = memberTroop.TroopsNum } return memberTroopMap, code.OK } // 获取队伍最终分兵数 func (p *actorPlayer) GetFinalTeamTroopNum(curTeam *dbMapPlayer.Team, troopsID int32, memberTroops map[int32]int32, finalMemberTroops map[int32]*pb.I32I32) int32 { var ( playerTable = db.GetMapPlayerTable(p.playerID) costTroopsNum int32 curTroopNum int32 finalAddTroopsNum int32 ) for teamIndex, addTroopNum := range memberTroops { if addTroopNum < 1 { continue } member, ok := curTeam.GetTeamMember(teamIndex) if !ok { continue } // 当前带兵数 curTroopNum = member.TroopsNum finalAddTroopsNum = addTroopNum // 切换士兵等级 最终会返还英雄当前带兵数量 if troopsID != member.TroopsID { curTroopNum = 0 } heroEntity, found := playerTable.Heroes.Get(member.HeroGUID) if !found { p.Warn("GetFinalTeamTroopNum hero not found, heroGUID: %d", member.HeroGUID) continue } // 获取英雄带兵上限 heroArmsLimit := team.Service().GetHeroTroopsNum(p.playerID, heroEntity.HeroID, member.TeamIndex) if curTroopNum+finalAddTroopsNum > heroArmsLimit { finalAddTroopsNum = heroArmsLimit - curTroopNum } costTroopsNum += finalAddTroopsNum data := pb.I32I32{ Key: troopsID, Value: finalAddTroopsNum, } finalMemberTroops[teamIndex] = &data } return costTroopsNum } // 更新队伍士兵ID(士兵-等级表士兵ID) func (p *actorPlayer) updateTeamMemberTroopsID(teamMember *dbMapPlayer.TeamMember, level int32) { playerTable := db.GetMapPlayerTable(p.playerID) hero, found := playerTable.Heroes.Get(teamMember.HeroGUID) if !found { p.Warn("updateTeamMemberTroopsID hero not found, heroGUID: %d", teamMember.HeroGUID) return } heroRow, found := data.Hero.GetByID(hero.HeroID) if !found { p.Warn("updateTeamMemberTroopsID hero not found, heroID: %d", hero.HeroID) return } armLevelRow, found := data.ArmType.GetByTypeLevel(heroRow.Job, level) if !found { p.Warn("updateTeamMemberTroopsID hero not found, heroID: %d, job: %d, level: %d", hero.HeroID, heroRow.Job, level) return } teamMember.TroopTypeID = armLevelRow.ID } // 返还队伍兵力&重置英雄带兵数量&更新上阵英雄兵种ID func (p *actorPlayer) returnAndResetTeamMemberTroopsNum(team *dbMapPlayer.Team, groupMemberTroops map[int32]map[int32]int32) { if len(groupMemberTroops) <= 0 { return } returnAssets := types.Assets{} for troopsID, troopsMap := range groupMemberTroops { armLevelRow, exist := data.ArmLevel.GetByID(troopsID) for teamIndex := range troopsMap { teamMember, found := team.GetTeamMember(teamIndex) // 上阵英雄带兵ID改变 重置当前带兵数量&更新兵种ID if found && troopsID != teamMember.TroopsID { // 原来是否带兵 有兵返还 无兵不返还 if teamMember.TroopsID != 0 && teamMember.TroopsNum > 0 { returnAssets.Add(teamMember.TroopsID, int64(teamMember.TroopsNum)) teamMember.TroopsNum = 0 } // 更新英雄兵种ID if exist { p.updateTeamMemberTroopsID(teamMember, armLevelRow.Level) } } } } // 返还下阵士兵 if len(returnAssets) > 0 { _, errCode := mapFacade.Storage.AssetAdds(p.playerID, returnAssets, ao.TeamUpdateTroopsReturn) if code.IsFail(errCode) { p.Warn("returnAndResetTeamMemberTroopsNum error, teamID: %d, returnAssets: %v, errCode: %d", team.TeamID, returnAssets, errCode) } push := &pb.AssetList{ List: returnAssets.ToProto(), } // 推送返还兵力 sessions.PushPlayer(p.playerID, nameRoute.PushMapPlayer_TeamTroopReturn, push) } } func (p *actorPlayer) updateTeamState(req *pb.I32I32) { teamID := req.Key state := enum.TeamState(req.Value) playerTable := db.GetMapPlayerTable(p.playerID) if playerTable == nil { return } dbTeam, ok := playerTable.Teams.GetTeam(teamID) if !ok { return } // 更新队伍状态 team.Service().UpdateTeamState(playerTable, dbTeam, state) } // 战败设置部队重伤 func (p *actorPlayer) setTeamInjury(req *pb.I32I64) { var ( playerID = p.playerID playerTable = db.GetMapPlayerTable(playerID) teamID, injuriesEndTime = req.Key, req.Value ) p.Debug("[setTeamInjury] playerID = %d, teamID = %d, injuriesEndTime = %s", playerID, teamID, times.SecondToDatetimeFormat(injuriesEndTime)) team, ok := playerTable.Teams.GetTeam(teamID) if !ok { p.Warn("[setTeamInjury] team not exist: playerID = %d, teamID = %d", playerID, teamID) return } resp := &pb.HeroStateResponse{} for _, member := range team.Members { // 恢复受伤的士兵 if member.InjureTroops > 0 { member.TroopsNum += member.InjureTroops // 重置伤兵数 member.InjureTroops = 0 } hero, ok := playerTable.Heroes.Get(member.HeroGUID) if !ok { continue } hero.InjuriesEndTime = injuriesEndTime member.InjureEndTime = injuriesEndTime resp.HeroState = append(resp.HeroState, hero.ToHeroStateProto()) } playerTable.Save2Queue() // 同步到march mapCall.Logic.MarchSyncInjure(team.MarchObjectID, injuriesEndTime) // 推送给客户端 sessions.PushPlayer(playerID, nameRoute.PushMapPlayer_HeroState, resp) p.Debug("[setTeamInjury] teamID = %d, endTime = %s", teamID, times.MillisToDatetimeFormat(injuriesEndTime)) } // 更新队伍羁绊列表 func (p *actorPlayer) updateTeamFetterList(updateTeams ...*dbMapPlayer.Team) { if len(updateTeams) < 1 { return } playerTable := db.GetMapPlayerTable(p.playerID) for _, curTeam := range updateTeams { if len(curTeam.Members) < 1 { curTeam.FetterIDs.Clear() continue } // 获取英雄列表 heroIDSet := types.Set[int32]{} for _, member := range curTeam.Members { curHeroEntity, found := playerTable.Heroes.Get(member.HeroGUID) if found { heroIDSet.Add(curHeroEntity.HeroID) } } // 刷新队伍羁绊 fetterIDs := team.Service().GetFetterListByHeroList(p.playerID, heroIDSet) curTeam.FetterIDs = fetterIDs // 给部队的成员计算羁绊属性 team.Service().TeamFetterAttrs(curTeam, playerTable.Heroes) } } // 使用药品 func (p *actorPlayer) useMedicine(req *pb.I32I32) int32 { var ( playerTable = db.GetMapPlayerTable(p.playerID) teamID = req.Key medicineID = req.Value ) medicineRow, found := data.ItemMedicine.GetByMedicineID(medicineID) if !found { return code.ConfigNotFound_Medicine } curTeam, found := playerTable.Teams.GetTeam(teamID) if !found { return code.MapTeamNotFound } errCode := code.ItemUseTypeError switch medicineRow.UseType { case enum.MedicineType_Energy: // 使用体力药 errCode = p.useEnergyMedicine(playerTable, curTeam, medicineRow) case enum.MedicineType_Troops: // 使用补兵药 errCode = p.useTroopsMedicine(playerTable, curTeam, medicineRow) case enum.MedicineType_Injured: // 使用重伤药 errCode = p.useInjuredMedicine(playerTable, curTeam) } if code.IsFail(errCode) { return errCode } // 推送队伍数据变更 team.Service().ChangePush(p.playerID, curTeam) return code.OK } // 使用体力药 func (p *actorPlayer) useEnergyMedicine(playerTable *db.MapPlayerTable, team *dbMapPlayer.Team, medicineRow *data.ItemMedicineRow) int32 { var ( addEnergy = medicineRow.Value heroEnergyLimit = data.Const.HeroEnergy updateHeros = []*dbMapPlayer.Hero{} ) // 检测是否能添加体力 for _, member := range team.Members { dbHero, found := playerTable.Heroes.Get(member.HeroGUID) if !found { return code.HeroNotExist } if dbHero.Energy+addEnergy > heroEnergyLimit { return code.HeroEnergyOverflow } updateHeros = append(updateHeros, dbHero) } // 如果不存在可以恢复的英雄,则不进行恢复 if len(updateHeros) < 1 { return code.HeroNotNeedRecovery } // 增加体力 for _, dbHero := range updateHeros { hero.Service().AddEnergy(playerTable, dbHero, addEnergy) } // 保存英雄数据 playerTable.Save2Queue() return code.OK } // 使用补兵药 func (p *actorPlayer) useTroopsMedicine(playerTable *db.MapPlayerTable, curTeam *dbMapPlayer.Team, medicineRow *data.ItemMedicineRow) int32 { var ( addTroops = medicineRow.Value update = false marchTroops []*pb.MarchTroops ) // 城外征兵中 无法使用补兵药 if curTeam.IsOutsideTroops() { return code.TeamOutsideTroops } for _, member := range curTeam.Members { heroEntity, found := playerTable.Heroes.Get(member.HeroGUID) if !found { return code.HeroNotExist } // 当前英雄带兵上限 heroTroopsLimit := team.Service().GetHeroTroopsNum(p.playerID, heroEntity.HeroID, member.TeamIndex) // 超出上限跳过 if member.TroopsNum >= heroTroopsLimit { continue } // 执行补兵 超出上限直接销毁 // 计算实际可以补兵的数量 add := min(addTroops, heroTroopsLimit-member.TroopsNum) member.TroopsNum += add marchTroops = append(marchTroops, &pb.MarchTroops{ TeamIndex: member.TeamIndex, TroopsNum: add, }) update = true } // 不需要补兵 if !update { return code.TeamNotNeedAddTroops } playerTable.Save2Queue() // 更新地图队伍兵力数据 mapCall.Logic.MarchSyncTroops(curTeam.TeamID, curTeam.MarchObjectID, marchTroops) // 同步队伍兵力 team.Service().UpdatePlayerTeams(p.playerID, curTeam) // 推送队伍信息变更 team.Service().ChangePush(p.playerID, curTeam) return code.OK } // 使用重伤药 func (p *actorPlayer) useInjuredMedicine(playerTable *db.MapPlayerTable, curTeam *dbMapPlayer.Team) int32 { // 判断队伍当前状态 if curTeam.IsNotStandby() { return code.TeamIsBusy } var ( curTime = ctime.Now().ToSecond() updateHeros = []*dbMapPlayer.Hero{} ) for _, member := range curTeam.Members { hero, found := playerTable.Heroes.Get(member.HeroGUID) if !found { return code.HeroNotExist } if curTime < hero.InjuriesEndTime { updateHeros = append(updateHeros, hero) } } if len(updateHeros) < 1 { return code.HeroNotNeedRecovery } for _, hero := range updateHeros { hero.InjuriesEndTime = 0 } // 保存英雄数据 playerTable.Save2Queue() if len(playerTable.NodeID) > 0 { // 同步地图队伍数据 mapCall.Logic.MarchSyncInjure(curTeam.MarchObjectID, 0) } // 通知客户端更新 team.Service().HeroStateChangePush(p.playerID, updateHeros...) return code.OK } // 战斗后执行扣除的兵力 增量扣除 func (p *actorPlayer) subTeamTroopsNum(req *pb.TeamBattleDamage) { playerTable := db.GetMapPlayerTable(p.playerID) dbTeam, found := playerTable.Teams.GetTeam(req.TeamID) if !found { return } for _, battleTeamMember := range req.Members { teamMember, found := dbTeam.GetTeamMember(battleTeamMember.TeamIndex) if !found { p.Warn("subTeamTroopsNum teamMember not found. teamIndex: %d, troopsNum: %d, soldierNum: %d, teamID: %d", battleTeamMember.TeamIndex, battleTeamMember.TroopsNum, battleTeamMember.SoldierNum, req.TeamID) continue } // 战损兵力 troopsDamage := max(0, battleTeamMember.TroopsNum-battleTeamMember.SoldierNum) teamMember.TroopsNum = max(0, teamMember.TroopsNum-troopsDamage) // 根据战损计算伤兵,回城\调度点\营帐再恢复伤兵 diedNum := troopsDamage * data.Const.MapBattleLossTroops / constant.RatioBase injureNum := max(0, troopsDamage-diedNum) teamMember.InjureTroops += injureNum } playerTable.Save2Queue() // 兵力同步到redis team.Service().UpdatePlayerTeams(p.playerID, dbTeam) // 同步兵力给客户端 team.Service().ChangePush(p.playerID, dbTeam) } func (p *actorPlayer) GetHero(playerTable *db.MapPlayerTable, heroGUID int64) (*dbMapPlayer.Hero, int32) { hero, ok := playerTable.Heroes.Get(heroGUID) if ok { return hero, code.OK } heroMap := redis.Game.GetPlayerHeros(p.playerID, heroGUID) if len(heroMap) > 0 { hero, found := heroMap[heroGUID] if !found { return nil, code.HeroNotExist } newHero := &dbMapPlayer.Hero{ GUID: hero.Id, HeroID: hero.ConfigID, } playerTable.Heroes.Add(newHero) return newHero, code.OK } return nil, code.HeroNotExist } // 城外征兵 func (p *actorPlayer) teamOutsideTroops(session *cproto.Session, req *pb.TeamOutsideTroops) { var ( teamID = req.TeamID troopNums = req.TroopsNums playerTable = db.GetMapPlayerTable(p.playerID) ) curTeam, found := playerTable.Teams.GetTeam(teamID) if !found { p.ResponseCode(session, code.TeamNotUnlock) return } // 不可以征兵 if !curTeam.CanOutsideTroops { p.ResponseCode(session, code.TeamIsBusy) return } // 执行城外征兵 errCode := team.Service().DoTeamOutsideTroops(p.playerID, curTeam, troopNums) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } playerTable.Save2Queue() resp := curTeam.ToOutsideTroopsProto() p.Response(session, resp) } // 城外取消征兵 func (p *actorPlayer) teamOutsideTroopsCancel(session *cproto.Session, req *pb.TeamOutsideTroopsCancel) { var ( teamID = req.TeamID teamIndexs = req.TeamIndexs playerTable = db.GetMapPlayerTable(p.playerID) ) if len(teamIndexs) <= 0 { p.ResponseCode(session, code.IllegalArgument) return } curTeam, found := playerTable.Teams.GetTeam(teamID) if !found { p.ResponseCode(session, code.TeamNotUnlock) return } // 取消城外征兵 errCode := team.Service().TeamOutsideTroopsCancel(playerTable, curTeam, teamIndexs) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } playerTable.Save2Queue() resp := curTeam.ToOutsideTroopsProto() p.Response(session, resp) } // 设置城外自动征兵 func (p *actorPlayer) teamOutsideAutoTroopsSet(session *cproto.Session, req *pb.I32) { teamID := req.Value playerTable := db.GetMapPlayerTable(p.playerID) team, found := playerTable.Teams.GetTeam(teamID) if !found { p.ResponseCode(session, code.TeamNotUnlock) return } team.IsAutoTroops = !team.IsAutoTroops playerTable.Save2Queue() resp := &pb.I32Bool{Key: teamID, Value: team.IsAutoTroops} p.Response(session, resp) } // 行军取消城外征兵 func (p *actorPlayer) marchOutsideTroopsCancel(playerTable *db.MapPlayerTable, curTeam *dbMapPlayer.Team) { // 取消城外征兵 errCode := team.Service().TeamOutsideTroopsCancel(playerTable, curTeam, curTeam.GetTeamIndexs()) if code.IsFail(errCode) { return } // 去掉可征兵标识 curTeam.CanOutsideTroops = false playerTable.Save2Queue() // 通知客户端取消城外征兵 team.Service().TeamOutsideTroopsChangePush(playerTable.PlayerID, curTeam) } func (p *actorPlayer) marchArrive(eventData cfacade.IEventData) { e, ok := eventData.(*event.MarchArrive) if !ok { return } d := e.Data() playerTable := db.GetMapPlayerTable(p.playerID) if playerTable == nil { p.Warn("[marchArrive] fail, playerTable not found. playerID:%d, eventData: %v", p.playerID, eventData) return } dbTeam, found := playerTable.Teams.GetTeam(d.TeamID) if !found { p.Warn("[marchArrive] fail, team not found. playerID:%d, eventData: %v", p.playerID, eventData) return } // 如果部队是调动|待命,回复伤兵 if d.MarchState == enum.MarchState_Redeploy || d.MarchState == enum.MarchState_Standby { // 回复伤兵 team.Service().RecoveryInjureTroops(playerTable, dbTeam) } // 如果是调动,检查是否可以自动征兵 if d.MarchState == enum.MarchState_Redeploy { // 检查调动的建筑是否可以自动征兵 canOutsideConscript := team.Service().CheckCanOusideConscript(playerTable.PlayerID, d.TargetConfigID) if !canOutsideConscript { return } // 设置当前可以自动征兵检测 dbTeam.CanOutsideTroops = true // 开启自动征兵状态 if dbTeam.IsAutoTroops { team.Service().OutsideAutoTroops(playerTable, dbTeam) } playerTable.Save2Queue() } } // 刷新队伍 func (p *actorPlayer) onFacilityUpRefreshTeam(c cfacade.IEventData) { var ( playerTable = db.GetMapPlayerTable(p.playerID) updateTeams = []*dbMapPlayer.Team{} ) teamCount := playerTable.Facilities.Attrs.GetI32(enum.AttrTeamCount) for i := int32(1); i <= teamCount; i++ { team, success := playerTable.Teams.AddTeam(i) if success { updateTeams = append(updateTeams, team) playerTable.SetChangeData() } } if len(updateTeams) > 0 { team.Service().ChangePush(p.playerID, updateTeams...) } } func (p *actorPlayer) updateTeam(req *pb.UpdateTeam) { playerTable := db.GetMapPlayerTable(p.playerID) dbTeam, ok := playerTable.Teams.GetTeam(req.TeamID) if !ok { p.Warn("[updateTeam] fail, team not found. playerID:%d, req: %+v", p.playerID, req) return } p.Debug("[updateTeam] req: %+v", req) switch enum.TeamUpdateType(req.TeamUpdateType) { case enum.TeamUpdate_Redeploy: { dbTeam.RedeployObject.Set(req.RedeployObjectID, enum.ObjectType(req.RedeployObjectType)) playerTable.SetChangeData() } } }