| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- package player
- import (
- "f1-game/internal/code"
- "f1-game/internal/constant"
- "f1-game/internal/data"
- "f1-game/internal/enum"
- "f1-game/internal/event"
- nameEvent "f1-game/internal/name/event"
- nameLocal "f1-game/internal/name/local"
- nameRemote "f1-game/internal/name/remote"
- "f1-game/internal/pb"
- "f1-game/internal/types"
- "f1-game/nodes/game/internal/db"
- dbEquip "f1-game/nodes/game/internal/db/data/equip"
- dbHero "f1-game/nodes/game/internal/db/data/hero"
- gameFacade "f1-game/nodes/game/internal/facade"
- "slices"
- "f1-game/nodes/game/player/asset"
- ao "f1-game/nodes/game/player/asset/origin"
- "f1-game/nodes/game/player/equip"
- "f1-game/nodes/game/player/hero"
- cfacade "github.com/cherry-game/cherry/facade"
- cproto "github.com/cherry-game/cherry/net/proto"
- )
- func (p *actorPlayer) initHero() {
- p.Local().Register(nameLocal.Player_HeroStar, p.heroStar)
- p.Local().Register(nameLocal.Player_HeroSkillUp, p.heroSkillUp)
- p.Local().Register(nameLocal.Player_HeroWearEquip, p.heroWearEquip)
- p.Local().Register(nameLocal.Player_HeroTakeOffEquip, p.heroTakeOffEquip)
- p.EventRegister(nameEvent.Lord_LevelUp, p.heroLordLevelUp)
- }
- // heroStar 英雄升星
- func (p *actorPlayer) heroStar(session *cproto.Session, req *pb.HeroStarRequest) {
- if len(req.RemoveHeroGUIDs) < 1 {
- p.ResponseCode(session, code.HeroStarNotEnough)
- return
- }
- heroTable := p.HeroTable()
- starHero, ok := heroTable.Heroes.Get(req.HeroGUID)
- if !ok {
- p.ResponseCode(session, code.HeroNotExist)
- return
- }
- // 检查英雄是否可以升星
- if errCode := p.isHeroStarViable(starHero); code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- var (
- curStar = starHero.Star
- oldStar = curStar
- curStarExp = starHero.StarExp
- )
- // 检查材料
- for _, removeGUID := range req.RemoveHeroGUIDs {
- removeHero, ok := heroTable.Heroes.Get(removeGUID)
- if !ok {
- p.ResponseCode(session, code.HeroNotExist)
- return
- }
- // 判断英雄是否可以作为升星材料
- if errCode := p.isHeroStarMatch(starHero, removeHero); code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 计算星级经验
- starRow, ok := data.HeroStar.GetByStar(removeHero.Star)
- if !ok {
- p.Warn("[HeroStar] config not exists, star=%d", removeHero.Star)
- p.ResponseCode(session, code.ConfigNotFound_HeroStar)
- return
- }
- curStarExp += starRow.OfferExp
- }
- // 检查是否可以升星 (最多循环最大星级的次数)
- for range data.Const.HeroMaxStar {
- starRow, ok := data.HeroStar.GetByStar(curStar)
- if !ok {
- p.Warn("[HeroStar] config not exists, star=%d", curStar)
- p.ResponseCode(session, code.ConfigNotFound_HeroStar)
- return
- }
- if curStarExp < starRow.UpgradeExp {
- break
- }
- curStar++
- curStarExp -= starRow.UpgradeExp
- if curStar >= data.Const.HeroMaxStar {
- break
- }
- }
- // 地图队伍信息判断是否能删除英雄
- playerTable := p.PlayerTable()
- if len(playerTable.Map.MapNodeID) > 0 {
- req := &pb.I64List{
- List: req.RemoveHeroGUIDs,
- }
- errCode := p.mapPlayerCallWait(playerTable.Map.MapNodeID, nameRemote.MapPlayer_HeroDelete, req)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- }
- // 移除材料英雄
- hero.Service().RemoveHeros(p.playerID, req.RemoveHeroGUIDs...)
- starHero.StarExp = curStarExp
- if starHero.Star != curStar {
- starHero.Star = curStar
- //检测英雄技能激活
- hero.Service().CheckActiveHeroSkill(starHero)
- // 刷新英雄属性
- hero.Service().UpdateAttrs(p.playerID, starHero)
- // 更新英雄星级数量
- for addStar := oldStar + 1; addStar <= starHero.Star; addStar++ {
- heroTable.HeroExtend.IncrStar(addStar)
- }
- // 发送英雄升星事件
- p.PostEvent(event.NewHeroStar(p.playerID, oldStar, starHero.Star))
- }
- heroTable.Save2Queue()
- p.Response(session, starHero.ToProto())
- // 同步更新到redis
- hero.Service().SyncUpdateHeroToRedis(p.playerID, starHero)
- // 推送变更信息
- hero.Service().ChangePush(p.playerID, req.RemoveHeroGUIDs, starHero)
- }
- // isHeroStarViable 判断是否可以升星
- func (p *actorPlayer) isHeroStarViable(hero *dbHero.Hero) int32 {
- // 已经最大星级
- if hero.Star >= data.Const.HeroMaxStar {
- return code.HeroStarLimit
- }
- // TODO 其它条件: 如果是否在队伍中, 是否锁定....
- return code.OK
- }
- // isHeroStarMatch 判断升星材料是否匹配
- func (p *actorPlayer) isHeroStarMatch(starHero, removeHero *dbHero.Hero) int32 {
- // 不能吃自己
- if starHero.GUID == removeHero.GUID {
- return code.HeroStarMismatch
- }
- // 升星需要同样的英雄
- if removeHero.HeroID != starHero.HeroID {
- return code.HeroStarMismatch
- }
- // TODO 其它条件: 如果是否在队伍中, 是否锁定....
- // TODO 暂时屏蔽 后面callwait去map判断或者在redis中判断
- // if removeHero.IsAlreadyTeamUp() {
- // return code.TeamHeroAlreadyUp
- // }
- return code.OK
- }
- func (*actorPlayer) heroLordLevelUp(eventData cfacade.IEventData) {
- e, ok := eventData.(*event.LordLevelUp)
- if !ok {
- return
- }
- var (
- playerID = e.UniqueID()
- playerTable, _ = db.GetPlayerTable(playerID)
- heroTable = db.GetHeroTable(playerID)
- )
- for _, hero := range heroTable.Heroes {
- // 更新英雄等级(冗余)
- hero.Level = playerTable.Lord.Level
- // 更新英雄属性
- gameFacade.Hero.UpdateAttrs(playerID, hero)
- }
- heroTable.Save2Queue()
- // 同步更新到redis
- // TODO 全量更新优化
- hero.Service().SyncUpdateHeroToRedis(playerID, heroTable.Heroes.GetAll()...)
- // TODO FIXME 英雄太多全部推送数据太大
- // TODO
- // TODO
- // gameFacade.Hero.Push(playerID)
- }
- // heroSkillUp 英雄技能升级
- func (p *actorPlayer) heroSkillUp(session *cproto.Session, req *pb.I64I32) {
- var (
- heroTable = p.HeroTable()
- heroGUID = req.Key
- skillID = req.Value
- )
- heroEntity, found := heroTable.Heroes.Get(heroGUID)
- if !found {
- p.ResponseCode(session, code.HeroNotExist)
- return
- }
- // 判断当前技能是否已解锁
- skillLevel := heroEntity.GetSkillLevel(skillID)
- if skillLevel < 1 {
- p.ResponseCode(session, code.SkillNotUnlock)
- return
- }
- skillRow, found := data.Skill.GetByID(skillID)
- if !found {
- p.ResponseCode(session, code.SkillNotExists)
- return
- }
- // 判断是否达到最大等级
- if skillLevel >= skillRow.MaxLv {
- p.ResponseCode(session, code.SkillLevelMax)
- return
- }
- // 获取当前技能等级配置
- skillLevelRow, found := data.SkillLevel.GetBySkillIDLevel(skillID, skillLevel)
- if !found {
- p.ResponseCode(session, code.ConfigNotExist_SkillLevel)
- return
- }
- // 消耗为空表示升到了最高级
- if skillLevelRow.UpgradeCost.IsEmpty() {
- p.ResponseCode(session, code.SkillUpCostError)
- return
- }
- // 判断下一级配置是否存在
- nextSkillLevelRow, found := data.SkillLevel.GetBySkillIDLevel(skillID, skillLevel+1)
- if !found {
- p.ResponseCode(session, code.ConfigNotExist_SkillLevel)
- return
- }
- // 升级星级不足
- if heroEntity.Star < nextSkillLevelRow.UnlockStar {
- p.ResponseCode(session, code.SkillLevelLimit)
- return
- }
- // 消耗资源
- _, errCode := asset.Service().Subs(p.playerID, skillLevelRow.UpgradeCost, ao.HeroSkillLevelUpCost)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 升级
- skillLevel++
- heroEntity.SetSkillLevel(skillID, skillLevel)
- heroTable.Save2Queue()
- rsp := &pb.HeroSkillResponse{
- HeroGUID: heroGUID,
- HeroSkillID: skillID,
- HeroSkillLevel: skillLevel,
- }
- p.Response(session, rsp)
- // 同步更新到redis
- hero.Service().SyncUpdateHeroToRedis(p.playerID, heroEntity)
- }
- // 英雄穿戴装备
- func (p *actorPlayer) heroWearEquip(session *cproto.Session, req *pb.HeroEquip) {
- var (
- heroTable = p.HeroTable()
- equipTable = p.EquipTable()
- heroGUID = req.HeroGUID // 英雄GUID
- equipGUIDList = req.EquipGUIDList // 装备GUID列表
- )
- if heroGUID < 1 ||
- len(equipGUIDList) > constant.HeroEquipSlotMax ||
- len(equipGUIDList) < constant.HeroEquipSlotMin {
- p.ResponseCode(session, code.IllegalArgument)
- return
- }
- // 穿戴装备的英雄非待命状态
- errCode := p.checkHeroCanUpdateEquip(heroGUID)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- weHero, found := heroTable.Heroes.Get(heroGUID)
- if !found {
- p.ResponseCode(session, code.HeroNotExist)
- return
- }
- var (
- validEquipList []*dbEquip.Equip // 过滤可穿戴装备
- replaceEquipList []*dbEquip.Equip // 需要先脱下的装备,包括当前英雄和被其他英雄穿戴的装备
- equipTypeList []enum.EquipType // 可穿戴的装备类型
- )
- for _, equipGUID := range equipGUIDList {
- equip, found := equipTable.Equips.Get(equipGUID)
- // 装备不存在
- if !found {
- continue
- }
- // 装备已穿戴当前英雄身上
- if weHero.EquipGUIDList.Contains(equipGUID) {
- continue
- }
- equipType := equip.GetEquipType()
- // 装备类型重复
- if slices.Contains(equipTypeList, equipType) {
- continue
- }
- // 记录需要脱掉装备在其他英雄身上的装备
- if equip.WearHeroGUID > 0 {
- // 卸下装备的英雄非待命状态
- errCode := p.checkHeroCanUpdateEquip(equip.WearHeroGUID)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- replaceEquipList = append(replaceEquipList, equip)
- }
- validEquipList = append(validEquipList, equip)
- equipTypeList = append(equipTypeList, equipType)
- }
- // 没有可穿戴的装备
- if len(validEquipList) < 1 {
- p.ResponseCode(session, code.OK)
- return
- }
- // 检查当前英雄身上需要被替换的装备
- for _, equipGUID := range weHero.EquipGUIDList {
- equip, _ := equipTable.Equips.Get(equipGUID)
- // 需要替换的装备先脱下
- if slices.Contains(equipTypeList, equip.GetEquipType()) {
- replaceEquipList = append(replaceEquipList, equip)
- }
- }
- // 先一键脱下装备
- changeHeroList := p.doTakeOffEquipList(heroTable, replaceEquipList)
- // 变更的装备
- var changeEquipList = types.NewList(replaceEquipList...)
- // 穿戴装备,双向绑定关系
- for _, equip := range validEquipList {
- weHero.EquipGUIDList.Add(equip.GUID)
- equip.WearHeroGUID = heroGUID
- // 记录变更的装备列表
- if !changeEquipList.Contains(equip) {
- changeEquipList.Add(equip)
- }
- }
- // 更新英雄属性
- gameFacade.Hero.UpdateAttrs(p.playerID, weHero)
- heroTable.Save2Queue()
- equipTable.Save2Queue()
- // 当前英雄也加入推送列表
- if !slices.Contains(changeHeroList, weHero) {
- changeHeroList = append(changeHeroList, weHero)
- }
- // 同步更新到redis
- hero.Service().SyncUpdateHeroToRedis(p.playerID, changeHeroList...)
- // 推送英雄变更
- hero.Service().ChangePush(p.playerID, nil, changeHeroList...)
- // 推送装备变更
- equip.Service().ChangePush(p.playerID, nil, changeEquipList...)
- p.ResponseCode(session, code.OK)
- // 发送英雄穿戴装备事件
- p.PostEvent(event.NewHeroWearEquip(p.playerID))
- }
- // 英雄脱下装备
- func (p *actorPlayer) heroTakeOffEquip(session *cproto.Session, req *pb.I64I64) {
- var (
- heroTable = p.HeroTable()
- equipTable = p.EquipTable()
- heroGUID = req.Key // 英雄GUID
- equipGUID = req.Value // 装备GUID
- )
- if heroGUID < 1 {
- p.ResponseCode(session, code.IllegalArgument)
- }
- // 检测英雄是否是出战状态
- errCode := p.checkHeroCanUpdateEquip(heroGUID)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- toeHero, found := heroTable.Heroes.Get(heroGUID)
- if !found {
- p.ResponseCode(session, code.HeroNotExist)
- return
- }
- if toeHero.EquipGUIDList.IsEmpty() {
- p.ResponseCode(session, code.HeroEquipNotWear)
- return
- }
- var validEquipList []*dbEquip.Equip // 可脱下的装备
- if equipGUID > 0 {
- equip, found := equipTable.Equips.Get(equipGUID)
- if !found {
- p.ResponseCode(session, code.EquipNotFound)
- return
- }
- // 装备是否穿戴在当前英雄身上
- if !toeHero.EquipGUIDList.Contains(equipGUID) {
- p.ResponseCode(session, code.HeroNotWearThisEquip)
- return
- }
- validEquipList = append(validEquipList, equip)
- } else {
- // 传0 一键脱下所有穿戴的装备
- for _, eguid := range toeHero.EquipGUIDList {
- equip, _ := equipTable.Equips.Get(eguid)
- validEquipList = append(validEquipList, equip)
- }
- }
- if len(validEquipList) < 1 {
- p.ResponseCode(session, code.HeroEquipNotWear)
- return
- }
- changeHeroList := p.doTakeOffEquipList(heroTable, validEquipList)
- heroTable.Save2Queue()
- equipTable.Save2Queue()
- // 同步更新到redis
- hero.Service().SyncUpdateHeroToRedis(p.playerID, changeHeroList...)
- // 推送英雄变更
- hero.Service().ChangePush(p.playerID, nil, changeHeroList...)
- // 推送装备变更
- equip.Service().ChangePush(p.playerID, nil, validEquipList...)
- p.ResponseCode(session, code.OK)
- }
- // 一键脱下装备,解除英雄与装备的穿戴关系。需要在上层保存
- //
- // wearEquipList 需要脱下的装备列表,上层过滤没有穿戴的装备
- func (p *actorPlayer) doTakeOffEquipList(heroTable *db.HeroTable, wearEquipList []*dbEquip.Equip) []*dbHero.Hero {
- var changeHeroList []*dbHero.Hero
- for _, equip := range wearEquipList {
- hero, _ := heroTable.Heroes.Get(equip.WearHeroGUID)
- /// 双向解除装备穿戴关系
- hero.RemoveEquip(equip.GUID)
- equip.WearHeroGUID = 0
- // 更新英雄属性
- gameFacade.Hero.UpdateAttrs(p.playerID, hero)
- // 记录需要推送变更的英雄列表
- changeHeroList = append(changeHeroList, hero)
- }
- return changeHeroList
- }
- // 检测英雄是否能穿戴装备 如果英雄处于出征状态是不能穿戴装备的
- func (p *actorPlayer) checkHeroCanUpdateEquip(heroGUIDs ...int64) int32 {
- if len(heroGUIDs) < 1 {
- return code.HeroNotExist
- }
- playerTable := p.PlayerTable()
- // 没有地图节点
- if len(playerTable.Map.MapNodeID) <= 0 {
- return code.OK
- }
- req := &pb.I64List{
- List: heroGUIDs,
- }
- // map检测英雄是否出征 如果出征中不能穿戴装备
- return p.mapPlayerCallWait(playerTable.Map.MapNodeID, nameRemote.MapPlayer_HeroCheckBusy, req)
- }
|