GCG流程至游戏主界面

This commit is contained in:
UnKownOwO
2023-01-07 20:02:59 +08:00
parent 8e11ec5f9f
commit dee9fea310
4 changed files with 368 additions and 181 deletions

View File

@@ -3,7 +3,6 @@ package game
import ( import (
"hk4e/pkg/logger" "hk4e/pkg/logger"
"hk4e/protocol/proto" "hk4e/protocol/proto"
"time"
) )
type GCGAi struct { type GCGAi struct {
@@ -29,13 +28,23 @@ func (g *GCGAi) ReceiveGCGMessagePackNotify(notify *proto.GCGMessagePackNotify)
switch msg.AfterPhase { switch msg.AfterPhase {
case proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE: case proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE:
logger.Error("请选择你的英雄 hhh") logger.Error("请选择你的英雄 hhh")
go func() { // 默认选第一张牌
time.Sleep(1000 * 3) cardInfo := gameController.cardList[0]
// 默认选第一张 // 操控者选择角色
cardInfo := gameController.cardList[0] g.game.ControllerSelectChar(gameController, cardInfo, []uint32{})
// 操控者选择角色牌 }
g.game.ControllerSelectChar(gameController, cardInfo, []uint32{}) case *proto.GCGMessage_DiceRoll:
}() // 摇完骰子
msg := message.GetPhaseChange()
switch msg.AfterPhase {
case proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE:
logger.Error("战斗意识?!")
cardInfo1 := g.game.controllerMap[g.controllerId].cardList[0]
cardInfo2 := g.game.controllerMap[g.controllerId].cardList[1]
g.game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.game.GCGMsgPVEIntention(&proto.GCGMsgPVEIntention{CardGuid: cardInfo1.guid, SkillIdList: []uint32{cardInfo1.skillIdList[1]}}, &proto.GCGMsgPVEIntention{CardGuid: cardInfo2.guid, SkillIdList: []uint32{cardInfo2.skillIdList[0]}}))
g.game.SendAllMsgPack()
g.game.SetControllerAllow(g.game.controllerMap[g.controllerId], false, true)
g.game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, g.game.GCGMsgPhaseContinue())
} }
} }
} }

View File

@@ -24,6 +24,7 @@ const (
type GCGCardInfo struct { type GCGCardInfo struct {
cardId uint32 // 卡牌Id cardId uint32 // 卡牌Id
guid uint32 // 唯一Id guid uint32 // 唯一Id
controllerId uint32 // 拥有它的操控者
faceType uint32 // 卡面类型 faceType uint32 // 卡面类型
tagList []uint32 // Tag tagList []uint32 // Tag
tokenMap map[uint32]uint32 // Token tokenMap map[uint32]uint32 // Token
@@ -32,6 +33,35 @@ type GCGCardInfo struct {
isShow bool // 是否展示 isShow bool // 是否展示
} }
func (g *GCGCardInfo) ToProto() *proto.GCGCard {
gcgCard := &proto.GCGCard{
TagList: g.tagList,
Guid: g.guid,
IsShow: g.isShow,
TokenList: make([]*proto.GCGToken, 0, len(g.tokenMap)),
FaceType: g.faceType,
SkillIdList: g.skillIdList,
SkillLimitsList: make([]*proto.GCGSkillLimitsInfo, 0, len(g.skillLimitList)),
Id: g.cardId,
ControllerId: g.controllerId,
}
// Token
for k, v := range g.tokenMap {
gcgCard.TokenList = append(gcgCard.TokenList, &proto.GCGToken{
Value: v,
Key: k,
})
}
// TODO SkillLimitsList
for _, skillId := range g.skillLimitList {
gcgCard.SkillLimitsList = append(gcgCard.SkillLimitsList, &proto.GCGSkillLimitsInfo{
SkillId: skillId,
LimitsList: nil, // TODO 技能限制列表
})
}
return gcgCard
}
type ControllerLoadState uint8 type ControllerLoadState uint8
const ( const (
@@ -64,12 +94,20 @@ func (g *GCGController) GetCardByGuid(cardGuid uint32) *GCGCardInfo {
// GCGManager 七圣召唤管理器 // GCGManager 七圣召唤管理器
type GCGManager struct { type GCGManager struct {
gameMap map[uint32]*GCGGame // 游戏列表 uint32 -> guid phaseFuncMap map[proto.GCGPhaseType]func(game *GCGGame) // 游戏阶段处理
gameGuidCounter uint32 // 游戏guid生成计数器 gameMap map[uint32]*GCGGame // 游戏列表 uint32 -> guid
gameGuidCounter uint32 // 游戏guid生成计数器
} }
func NewGCGManager() *GCGManager { func NewGCGManager() *GCGManager {
gcgManager := new(GCGManager) gcgManager := new(GCGManager)
gcgManager.phaseFuncMap = map[proto.GCGPhaseType]func(game *GCGGame){
proto.GCGPhaseType_GCG_PHASE_TYPE_START: gcgManager.PhaseStart,
proto.GCGPhaseType_GCG_PHASE_TYPE_DRAW: gcgManager.PhaseDraw,
proto.GCGPhaseType_GCG_PHASE_TYPE_DICE: gcgManager.PhaseRollDice,
proto.GCGPhaseType_GCG_PHASE_TYPE_PRE_MAIN: gcgManager.PhasePreMain,
proto.GCGPhaseType_GCG_PHASE_TYPE_MAIN: gcgManager.PhaseMain,
}
gcgManager.gameMap = make(map[uint32]*GCGGame) gcgManager.gameMap = make(map[uint32]*GCGGame)
return gcgManager return gcgManager
} }
@@ -97,52 +135,24 @@ func (g *GCGManager) CreateGame(gameId uint32, playerList []*model.Player) *GCGG
return game return game
} }
type GCGGameState uint8 // PhaseStart 阶段开始
func (g *GCGManager) PhaseStart(game *GCGGame) {
const ( // 设置除了先手的玩家不允许操控
GCGGameState_None GCGGameState = iota game.SetExceptControllerAllow(game.roundInfo.firstController, false, true)
GCGGameState_Waiting // 等待玩家加载 // 游戏跳过阶段消息包
GCGGameState_Running // 游戏运行中 game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, game.GCGMsgPhaseContinue())
GCGGameState_Stoped // 游戏已结束 // 等待玩家进入
)
// 阶段对应的处理函数
var phaseFuncMap = map[proto.GCGPhaseType]func(game *GCGGame){
proto.GCGPhaseType_GCG_PHASE_TYPE_START: PhaseStartReady,
proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE: PhaseSelectChar,
proto.GCGPhaseType_GCG_PHASE_TYPE_DICE: PhaseRollDice,
proto.GCGPhaseType_GCG_PHASE_TYPE_PRE_MAIN: PhasePreMain,
} }
// PhaseStartReady 阶段开局准备 // PhaseDraw 阶段抽取手牌
func PhaseStartReady(game *GCGGame) { func (g *GCGManager) PhaseDraw(game *GCGGame) {
// 客户端更新操控者 // TODO 新手教程关不抽手牌
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, game.GCGMsgUpdateController())
// 分配先手
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_PHASE_EXIT, game.GCGMsgClientPerform(proto.GCGClientPerformType_GCG_CLIENT_PERFORM_TYPE_FIRST_HAND, []uint32{game.roundInfo.firstController}))
// 游戏绘制卡牌阶段 应该
game.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_DRAW)
// 游戏选择角色卡牌阶段 // 游戏选择角色卡牌阶段
game.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE) game.ChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE)
}
// PhaseSelectChar 阶段选择角色卡牌
func PhaseSelectChar(game *GCGGame) {
// 该阶段确保每位玩家都选择了角色
for _, controller := range game.controllerMap {
if controller.selectedCharCard == nil {
// 如果有没选择角色卡牌的则不执行后面
return
}
}
// 回合信息
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, game.GCGMsgDuelDataChange())
// 游戏投掷骰子阶段
game.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_DICE)
} }
// PhaseRollDice 阶段投掷骰子 // PhaseRollDice 阶段投掷骰子
func PhaseRollDice(game *GCGGame) { func (g *GCGManager) PhaseRollDice(game *GCGGame) {
// 给每位玩家投掷骰子 // 给每位玩家投掷骰子
for _, controller := range game.controllerMap { for _, controller := range game.controllerMap {
diceSideList := make([]proto.GCGDiceSideType, 0, 8) diceSideList := make([]proto.GCGDiceSideType, 0, 8)
@@ -156,23 +166,38 @@ func PhaseRollDice(game *GCGGame) {
game.roundInfo.diceSideMap[controller.controllerId] = diceSideList game.roundInfo.diceSideMap[controller.controllerId] = diceSideList
game.AddMsgPack(controller.controllerId, proto.GCGActionType_GCG_ACTION_TYPE_ROLL, game.GCGMsgDiceRoll(controller.controllerId, uint32(len(diceSideList)), diceSideList)) game.AddMsgPack(controller.controllerId, proto.GCGActionType_GCG_ACTION_TYPE_ROLL, game.GCGMsgDiceRoll(controller.controllerId, uint32(len(diceSideList)), diceSideList))
} }
game.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_REROLL) // 等待玩家确认重投骰子
// g.controllerMap[1].allow = 1
// g.controllerMap[2].allow = 0
// msgPackInfo := g.CreateMsgPackInfo()
// msgPackInfo.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.GCGMsgPVEIntention(&proto.GCGMsgPVEIntention{CardGuid: g.controllerMap[2].cardList[0].guid, SkillIdList: []uint32{g.controllerMap[2].cardList[0].skillIdList[1]}}, &proto.GCGMsgPVEIntention{CardGuid: g.controllerMap[2].cardList[1].guid, SkillIdList: []uint32{g.controllerMap[2].cardList[1].skillIdList[0]}}))
// g.BroadcastMsgPackInfo(msgPackInfo, false)
// msgPackInfo1 := g.CreateMsgPackInfo()
// msgPackInfo1.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.GCGMsgUpdateController())
// msgPackInfo1.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, g.GCGMsgPhaseContinue())
// g.BroadcastMsgPackInfo(msgPackInfo1, false)
} }
// PhasePreMain 阶段战斗开始 // PhasePreMain 阶段战斗开始
func PhasePreMain(game *GCGGame) { func (g *GCGManager) PhasePreMain(game *GCGGame) {
// TODO 使用技能完善
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_TRIGGER_SKILL, game.GCGMsgUseSkill(195, 33024), game.GCGMsgUseSkillEnd(195, 33024)) game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_TRIGGER_SKILL, game.GCGMsgUseSkill(195, 33024), game.GCGMsgUseSkillEnd(195, 33024))
// 游戏行动阶段
game.ChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_MAIN)
} }
// PhaseMain 阶段行动
func (g *GCGManager) PhaseMain(game *GCGGame) {
// 消耗费用信息
for _, controller := range game.controllerMap {
if controller.player == nil {
continue
}
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NOTIFY_COST, game.GCGMsgCostRevise(controller))
GAME_MANAGER.SendMsg(cmd.GCGSkillPreviewNotify, controller.player.PlayerID, controller.player.ClientSeq, GAME_MANAGER.PacketGCGSkillPreviewNotify(controller))
}
}
type GCGGameState uint8
const (
GCGGameState_None GCGGameState = iota
GCGGameState_Waiting // 等待玩家加载
GCGGameState_Running // 游戏运行中
GCGGameState_Stoped // 游戏已结束
)
// GCGRoundInfo 游戏对局回合信息 // GCGRoundInfo 游戏对局回合信息
type GCGRoundInfo struct { type GCGRoundInfo struct {
roundNum uint32 // 游戏当前回合数 roundNum uint32 // 游戏当前回合数
@@ -193,6 +218,7 @@ type GCGGame struct {
roundInfo *GCGRoundInfo // 游戏回合信息 roundInfo *GCGRoundInfo // 游戏回合信息
controllerMap map[uint32]*GCGController // 操控者列表 uint32 -> controllerId controllerMap map[uint32]*GCGController // 操控者列表 uint32 -> controllerId
msgPackList []*proto.GCGMessagePack // 消息包待发送区 msgPackList []*proto.GCGMessagePack // 消息包待发送区
isLastMsgPack bool // 是否为阶段切换的最后一个消息包 用于粘包模拟官服效果
historyMsgPackList []*proto.GCGMessagePack // 历史消息包列表 historyMsgPackList []*proto.GCGMessagePack // 历史消息包列表
historyCardList []*GCGCardInfo // 历史卡牌列表 historyCardList []*GCGCardInfo // 历史卡牌列表
} }
@@ -205,6 +231,7 @@ func (g *GCGGame) AddPlayer(player *model.Player) {
controllerId: g.controllerIdCounter, controllerId: g.controllerIdCounter,
cardList: make([]*GCGCardInfo, 0, 50), cardList: make([]*GCGCardInfo, 0, 50),
loadState: ControllerLoadState_None, loadState: ControllerLoadState_None,
allow: 1,
controllerType: ControllerType_Player, controllerType: ControllerType_Player,
player: player, player: player,
} }
@@ -224,6 +251,7 @@ func (g *GCGGame) AddAI() {
controllerId: g.controllerIdCounter, controllerId: g.controllerIdCounter,
cardList: make([]*GCGCardInfo, 0, 50), cardList: make([]*GCGCardInfo, 0, 50),
loadState: ControllerLoadState_InitFinish, loadState: ControllerLoadState_InitFinish,
allow: 1,
controllerType: ControllerType_AI, controllerType: ControllerType_AI,
ai: &GCGAi{ ai: &GCGAi{
game: g, game: g,
@@ -237,26 +265,6 @@ func (g *GCGGame) AddAI() {
g.controllerMap[g.controllerIdCounter] = controller g.controllerMap[g.controllerIdCounter] = controller
} }
// GameChangePhase 游戏更改阶段
func (g *GCGGame) GameChangePhase(phase proto.GCGPhaseType) {
beforePhase := g.roundInfo.phaseType
// 修改游戏的阶段
g.roundInfo.phaseType = phase
switch phase {
case proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE, proto.GCGPhaseType_GCG_PHASE_TYPE_DICE:
// 该阶段允许所有玩家行动
for _, controller := range g.controllerMap {
controller.allow = 1
}
case proto.GCGPhaseType_GCG_PHASE_TYPE_PRE_MAIN:
// 该阶段不允许所有玩家行动
for _, controller := range g.controllerMap {
controller.allow = 0
}
}
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NEXT_PHASE, g.GCGMsgPhaseChange(beforePhase, phase))
}
// GiveCharCard 给予操控者角色卡牌 // GiveCharCard 给予操控者角色卡牌
func (g *GCGGame) GiveCharCard(controller *GCGController, charId uint32) { func (g *GCGGame) GiveCharCard(controller *GCGController, charId uint32) {
// 读取角色卡牌配置表 // 读取角色卡牌配置表
@@ -267,11 +275,12 @@ func (g *GCGGame) GiveCharCard(controller *GCGController, charId uint32) {
} }
// 生成卡牌信息 // 生成卡牌信息
g.cardGuidCounter++ g.cardGuidCounter++
controller.cardList = append(controller.cardList, &GCGCardInfo{ cardInfo := &GCGCardInfo{
cardId: charId, cardId: charId,
guid: g.cardGuidCounter, guid: g.cardGuidCounter,
faceType: 0, // 1为金卡 controllerId: controller.controllerId,
tagList: gcgCharConfig.TagList, faceType: 0, // 1为金卡
tagList: gcgCharConfig.TagList,
tokenMap: map[uint32]uint32{ tokenMap: map[uint32]uint32{
1: uint32(gcgCharConfig.HPBase), // 血量 1: uint32(gcgCharConfig.HPBase), // 血量
2: uint32(gcgCharConfig.HPBase), // 最大血量(不确定) 2: uint32(gcgCharConfig.HPBase), // 最大血量(不确定)
@@ -281,7 +290,114 @@ func (g *GCGGame) GiveCharCard(controller *GCGController, charId uint32) {
skillIdList: gcgCharConfig.SkillList, skillIdList: gcgCharConfig.SkillList,
skillLimitList: []uint32{}, skillLimitList: []uint32{},
isShow: true, isShow: true,
}) }
controller.cardList = append(controller.cardList, cardInfo)
// 添加历史卡牌
g.historyCardList = append(g.historyCardList, cardInfo)
}
// ChangePhase 游戏更改阶段
func (g *GCGGame) ChangePhase(phase proto.GCGPhaseType) {
beforePhase := g.roundInfo.phaseType
// 修改游戏的阶段
g.roundInfo.phaseType = phase
// 改变阶段覆盖掉上层可能有的true
g.isLastMsgPack = false
// 操控者允许操作列表
allowControllerMap := make([]*proto.Uint32Pair, 0, len(g.controllerMap))
// 根据阶段改变操控者允许状态
switch phase {
case proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE, proto.GCGPhaseType_GCG_PHASE_TYPE_DICE:
// 该阶段允许所有操控者操作
g.SetAllControllerAllow(true, false)
for _, controller := range g.controllerMap {
pair := &proto.Uint32Pair{
Key: controller.controllerId,
Value: controller.allow,
}
allowControllerMap = append(allowControllerMap, pair)
}
case proto.GCGPhaseType_GCG_PHASE_TYPE_MAIN:
// 行动阶段仅允许先手者操作
for _, controller := range g.controllerMap {
// 跳过不是先手的操控者
if controller.controllerId != g.roundInfo.firstController {
continue
}
g.SetControllerAllow(controller, true, false)
pair := &proto.Uint32Pair{
Key: controller.controllerId,
Value: controller.allow,
}
allowControllerMap = append(allowControllerMap, pair)
}
}
// 游戏下一阶段切换消息包
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NEXT_PHASE, g.GCGMsgPhaseChange(beforePhase, phase, allowControllerMap))
// 执行阶段处理前假装现在是最后一个阶段处理
g.isLastMsgPack = true
// 执行下一阶段
phaseFunc, ok := GCG_MANAGER.phaseFuncMap[g.roundInfo.phaseType]
// 确保该阶段有进行处理的函数
if ok {
phaseFunc(g) // 进行该阶段的处理
}
// 如果阶段里不嵌套处理别的阶段了就在此发送消息包
// 总之就是确保发送的时候为最后一个阶段变更
if g.isLastMsgPack {
// 发送阶段处理后的消息包
g.SendAllMsgPack()
}
}
// SetExceptControllerAllow 设置除了指定的操控者以外的是否允许操作
func (g *GCGGame) SetExceptControllerAllow(controllerId uint32, isAllow bool, isAddMsg bool) {
for _, controller := range g.controllerMap {
if controller.controllerId == controllerId {
continue
}
g.SetControllerAllow(controller, isAllow, false)
}
// 是否添加消息包
if isAddMsg {
// 更新客户端操控者允许状态消息包
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.GCGMsgUpdateController())
}
}
// SetAllControllerAllow 设置全部操控者是否允许操作
func (g *GCGGame) SetAllControllerAllow(isAllow bool, isAddMsg bool) {
for _, controller := range g.controllerMap {
g.SetControllerAllow(controller, isAllow, false)
}
// 是否添加消息包
if isAddMsg {
// 更新客户端操控者允许状态消息包
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.GCGMsgUpdateController())
}
}
// SetControllerAllow 设置操控者是否允许操作
func (g *GCGGame) SetControllerAllow(controller *GCGController, isAllow bool, isAddMsg bool) {
// allow 0 -> 不允许 1 -> 允许
// 当然这是我个人理解 可能有出入
if isAllow {
controller.allow = 1
} else {
controller.allow = 0
}
// 是否添加消息包
if isAddMsg {
// 更新客户端操控者允许状态消息包
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.GCGMsgUpdateController())
}
} }
// ControllerSelectChar 操控者选择角色卡牌 // ControllerSelectChar 操控者选择角色卡牌
@@ -294,11 +410,41 @@ func (g *GCGGame) ControllerSelectChar(controller *GCGController, cardInfo *GCGC
// TODO 消耗骰子点数 // TODO 消耗骰子点数
// 设置角色卡牌 // 设置角色卡牌
controller.selectedCharCard = cardInfo controller.selectedCharCard = cardInfo
// 设置操控者禁止操作
controller.allow = 0 // 设置玩家禁止操作
g.SetControllerAllow(controller, false, true)
// 广播选择的角色卡牌消息包 // 广播选择的角色卡牌消息包
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.GCGMsgUpdateController())
g.AddMsgPack(controller.controllerId, proto.GCGActionType_GCG_ACTION_TYPE_SELECT_ONSTAGE, g.GCGMsgSelectOnStage(controller.controllerId, cardInfo.guid, proto.GCGReason_GCG_REASON_DEFAULT)) g.AddMsgPack(controller.controllerId, proto.GCGActionType_GCG_ACTION_TYPE_SELECT_ONSTAGE, g.GCGMsgSelectOnStage(controller.controllerId, cardInfo.guid, proto.GCGReason_GCG_REASON_DEFAULT))
// 该阶段确保每位玩家都选择了角色牌
isAllSelectedChar := true
for _, controller := range g.controllerMap {
if controller.selectedCharCard == nil {
isAllSelectedChar = false
}
}
// 如果有玩家未选择角色牌不同处理
if isAllSelectedChar {
// 回合信息
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, g.GCGMsgDuelDataChange())
// 游戏投掷骰子阶段
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_DICE)
} else {
// 跳过该阶段 官服是这样的我也不知道为什么
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, g.GCGMsgPhaseContinue())
// 立刻发送消息包 模仿官服效果
g.SendAllMsgPack()
}
}
// ControllerReRollDice 操控者确认重投骰子
func (g *GCGGame) ControllerReRollDice(controller *GCGController, diceIndexList []uint32) {
// 玩家禁止操作
g.SetAllControllerAllow(false, true)
// 游戏战斗开始阶段
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_PRE_MAIN)
} }
// onTick 游戏的Tick // onTick 游戏的Tick
@@ -321,16 +467,6 @@ func (g *GCGGame) onTick() {
GAME_MANAGER.SendMsg(cmd.GCGHeartBeatNotify, controller.player.PlayerID, controller.player.ClientSeq, gcgHeartBeatNotify) GAME_MANAGER.SendMsg(cmd.GCGHeartBeatNotify, controller.player.PlayerID, controller.player.ClientSeq, gcgHeartBeatNotify)
} }
} }
// 仅在游戏处于运行状态时执行阶段处理
if g.gameState == GCGGameState_Running {
phaseFunc, ok := phaseFuncMap[g.roundInfo.phaseType]
// 确保该阶段有进行处理的函数
if ok {
phaseFunc(g) // 进行该阶段的处理
// 发送阶段处理后的消息包
g.SendAllMsgPack(false)
}
}
g.gameTick++ g.gameTick++
} }
@@ -343,34 +479,27 @@ func (g *GCGGame) InitGame(playerList []*model.Player) {
// 添加AI // 添加AI
g.AddAI() g.AddAI()
// // 先手允许操作
// controller, ok := g.controllerMap[g.roundInfo.firstController]
// if !ok {
// logger.Error("controller is nil, controllerId: %v", g.roundInfo.firstController)
// return
// }
// controller.allow = 1
// TODO 验证玩家人数是否符合
// 预开始游戏
g.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_START)
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, g.GCGMsgUpdateController())
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, g.GCGMsgPhaseContinue())
g.SendAllMsgPack(true)
// 游戏状态更改为等待玩家加载 // 游戏状态更改为等待玩家加载
g.gameState = GCGGameState_Waiting g.gameState = GCGGameState_Waiting
// TODO 验证玩家人数是否符合
// 游戏开始阶段
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_START)
} }
// StartGame 开始GCG游戏 // StartGame 开始GCG游戏
func (g *GCGGame) StartGame() { func (g *GCGGame) StartGame() {
// 游戏开始设置所有玩家不允许操作
// for _, c := range g.controllerMap {
// c.allow = 0
// }
// 游戏状态更改为游戏运行中 // 游戏状态更改为游戏运行中
g.gameState = GCGGameState_Running g.gameState = GCGGameState_Running
logger.Error("game running")
// 游戏开始设置所有玩家不允许操作
g.SetAllControllerAllow(false, true)
// 分配先手
g.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_PHASE_EXIT, g.GCGMsgClientPerform(proto.GCGClientPerformType_GCG_CLIENT_PERFORM_TYPE_FIRST_HAND, []uint32{g.roundInfo.firstController}))
// 游戏抽取手牌阶段
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_DRAW)
} }
// CheckAllInitFinish 检查所有玩家是否加载完成 // CheckAllInitFinish 检查所有玩家是否加载完成
@@ -407,13 +536,13 @@ func (g *GCGGame) AddMsgPack(controllerId uint32, actionType proto.GCGActionType
} }
// SendAllMsgPack 发送所有待发送区的消息包 // SendAllMsgPack 发送所有待发送区的消息包
func (g *GCGGame) SendAllMsgPack(recordOnly bool) { func (g *GCGGame) SendAllMsgPack() {
// 不发送空的消息包 // 不发送空的消息包
if len(g.msgPackList) == 0 { if len(g.msgPackList) == 0 {
return return
} }
// 是否仅记录历史消息包 // 游戏不处于运行状态仅记录历史消息包
if !recordOnly { if g.gameState == GCGGameState_Running {
g.serverSeqCounter++ g.serverSeqCounter++
for _, controller := range g.controllerMap { for _, controller := range g.controllerMap {
GAME_MANAGER.SendGCGMessagePackNotify(controller, g.serverSeqCounter, g.msgPackList) GAME_MANAGER.SendGCGMessagePackNotify(controller, g.serverSeqCounter, g.msgPackList)
@@ -428,21 +557,11 @@ func (g *GCGGame) SendAllMsgPack(recordOnly bool) {
} }
// GCGMsgPhaseChange GCG消息阶段改变 // GCGMsgPhaseChange GCG消息阶段改变
func (g *GCGGame) GCGMsgPhaseChange(beforePhase proto.GCGPhaseType, afterPhase proto.GCGPhaseType) *proto.GCGMessage { func (g *GCGGame) GCGMsgPhaseChange(beforePhase proto.GCGPhaseType, afterPhase proto.GCGPhaseType, allowControllerMap []*proto.Uint32Pair) *proto.GCGMessage {
gcgMsgPhaseChange := &proto.GCGMsgPhaseChange{ gcgMsgPhaseChange := &proto.GCGMsgPhaseChange{
BeforePhase: beforePhase, BeforePhase: beforePhase,
AfterPhase: afterPhase, AfterPhase: afterPhase,
AllowControllerMap: make([]*proto.Uint32Pair, 0, len(g.controllerMap)), AllowControllerMap: allowControllerMap,
}
if gcgMsgPhaseChange.AfterPhase != proto.GCGPhaseType_GCG_PHASE_TYPE_DRAW && gcgMsgPhaseChange.AfterPhase != proto.GCGPhaseType_GCG_PHASE_TYPE_PRE_MAIN {
// 操控者的是否允许操作
for _, controller := range g.controllerMap {
pair := &proto.Uint32Pair{
Key: controller.controllerId,
Value: controller.allow,
}
gcgMsgPhaseChange.AllowControllerMap = append(gcgMsgPhaseChange.AllowControllerMap, pair)
}
} }
gcgMessage := &proto.GCGMessage{ gcgMessage := &proto.GCGMessage{
Message: &proto.GCGMessage_PhaseChange{ Message: &proto.GCGMessage_PhaseChange{
@@ -559,13 +678,13 @@ func (g *GCGGame) GCGMsgDiceRoll(controllerId uint32, diceNum uint32, diceSideLi
// GCGMsgUseSkill GCG消息使用技能 // GCGMsgUseSkill GCG消息使用技能
func (g *GCGGame) GCGMsgUseSkill(cardGuid uint32, skillId uint32) *proto.GCGMessage { func (g *GCGGame) GCGMsgUseSkill(cardGuid uint32, skillId uint32) *proto.GCGMessage {
gcgMsgMsgUseSkill := &proto.GCGMsgUseSkill{ gcgMsgUseSkill := &proto.GCGMsgUseSkill{
SkillId: skillId, SkillId: skillId,
CardGuid: cardGuid, CardGuid: cardGuid,
} }
gcgMessage := &proto.GCGMessage{ gcgMessage := &proto.GCGMessage{
Message: &proto.GCGMessage_UseSkill{ Message: &proto.GCGMessage_UseSkill{
UseSkill: gcgMsgMsgUseSkill, UseSkill: gcgMsgUseSkill,
}, },
} }
return gcgMessage return gcgMessage
@@ -573,13 +692,64 @@ func (g *GCGGame) GCGMsgUseSkill(cardGuid uint32, skillId uint32) *proto.GCGMess
// GCGMsgUseSkillEnd GCG消息使用技能结束 // GCGMsgUseSkillEnd GCG消息使用技能结束
func (g *GCGGame) GCGMsgUseSkillEnd(cardGuid uint32, skillId uint32) *proto.GCGMessage { func (g *GCGGame) GCGMsgUseSkillEnd(cardGuid uint32, skillId uint32) *proto.GCGMessage {
gcgMsgMsgUseSkillEnd := &proto.GCGMsgUseSkillEnd{ gcgMsgUseSkillEnd := &proto.GCGMsgUseSkillEnd{
SkillId: skillId, SkillId: skillId,
CardGuid: cardGuid, CardGuid: cardGuid,
} }
gcgMessage := &proto.GCGMessage{ gcgMessage := &proto.GCGMessage{
Message: &proto.GCGMessage_UseSkillEnd{ Message: &proto.GCGMessage_UseSkillEnd{
UseSkillEnd: gcgMsgMsgUseSkillEnd, UseSkillEnd: gcgMsgUseSkillEnd,
},
}
return gcgMessage
}
// GCGMsgCostRevise GCG消息消耗信息修改
func (g *GCGGame) GCGMsgCostRevise(controller *GCGController) *proto.GCGMessage {
gcgMsgCostRevise := &proto.GCGMsgCostRevise{
CostRevise: &proto.GCGCostReviseInfo{
CanUseHandCardIdList: nil,
SelectOnStageCostList: make([]*proto.GCGSelectOnStageCostInfo, 0, 1),
PlayCardCostList: nil,
// 技能攻击消耗
AttackCostList: make([]*proto.GCGAttackCostInfo, 0, len(controller.selectedCharCard.skillIdList)),
IsCanAttack: true,
},
ControllerId: controller.controllerId,
}
for _, skillId := range controller.selectedCharCard.skillIdList {
gcgAttackCostInfo := &proto.GCGAttackCostInfo{
CostMap: []*proto.Uint32Pair{
{
Key: 10,
Value: 2,
},
{
Key: 13,
Value: 1,
},
},
SkillId: skillId,
}
gcgMsgCostRevise.CostRevise.AttackCostList = append(gcgMsgCostRevise.CostRevise.AttackCostList, gcgAttackCostInfo)
}
for _, info := range controller.cardList {
if info.guid != controller.selectedCharCard.guid {
gcgSelectOnStageCostInfo := &proto.GCGSelectOnStageCostInfo{
CardGuid: info.guid,
CostMap: []*proto.Uint32Pair{
{
Key: 10,
Value: 1,
},
},
}
gcgMsgCostRevise.CostRevise.SelectOnStageCostList = append(gcgMsgCostRevise.CostRevise.SelectOnStageCostList, gcgSelectOnStageCostInfo)
}
}
gcgMessage := &proto.GCGMessage{
Message: &proto.GCGMessage_CostRevise{
CostRevise: gcgMsgCostRevise,
}, },
} }
return gcgMessage return gcgMessage

View File

@@ -147,8 +147,7 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
TotalProgress: 0, TotalProgress: 0,
}, },
}, },
// TODO 创建完卡牌都记录到历史卡牌内 HistoryCardList: make([]*proto.GCGCard, 0, len(game.historyCardList)),
HistoryCardList: nil,
Round: game.roundInfo.roundNum, Round: game.roundInfo.roundNum,
ControllerId: gameController.controllerId, ControllerId: gameController.controllerId,
HistoryMsgPackList: game.historyMsgPackList, HistoryMsgPackList: game.historyMsgPackList,
@@ -163,8 +162,8 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
}, },
}, },
} }
// 玩家信息列表
for _, controller := range game.controllerMap { for _, controller := range game.controllerMap {
// 玩家信息列表
gcgControllerShowInfo := &proto.GCGControllerShowInfo{ gcgControllerShowInfo := &proto.GCGControllerShowInfo{
ControllerId: controller.controllerId, ControllerId: controller.controllerId,
ProfilePicture: &proto.ProfilePicture{}, ProfilePicture: &proto.ProfilePicture{},
@@ -175,6 +174,9 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
gcgControllerShowInfo.ProfilePicture.AvatarId = player.AvatarMap[player.HeadImage].Costume gcgControllerShowInfo.ProfilePicture.AvatarId = player.AvatarMap[player.HeadImage].Costume
} }
gcgAskDuelRsp.Duel.ShowInfoList = append(gcgAskDuelRsp.Duel.ShowInfoList) gcgAskDuelRsp.Duel.ShowInfoList = append(gcgAskDuelRsp.Duel.ShowInfoList)
}
// 玩家牌盒信息 卡牌显示相关
for _, controller := range game.controllerMap {
// FieldList 玩家牌盒信息 卡牌显示相关 // FieldList 玩家牌盒信息 卡牌显示相关
playerField := &proto.GCGPlayerField{ playerField := &proto.GCGPlayerField{
Unk3300_IKJMGAHCFPM: 0, Unk3300_IKJMGAHCFPM: 0,
@@ -208,50 +210,38 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
DeckCardNum: 0, DeckCardNum: 0,
Unk3300_GLNIFLOKBPM: 0, Unk3300_GLNIFLOKBPM: 0,
} }
// 卡牌信息
for _, info := range controller.cardList { for _, info := range controller.cardList {
gcgCard := &proto.GCGCard{
TagList: info.tagList,
Guid: info.guid,
IsShow: info.isShow,
TokenList: make([]*proto.GCGToken, 0, 0),
FaceType: info.faceType,
SkillIdList: info.skillIdList,
SkillLimitsList: make([]*proto.GCGSkillLimitsInfo, 0, 0),
Id: info.cardId,
ControllerId: controller.controllerId,
}
// Token
for k, v := range info.tokenMap {
gcgCard.TokenList = append(gcgCard.TokenList, &proto.GCGToken{
Value: v,
Key: k,
})
}
// TODO SkillLimitsList
for _, skillId := range info.skillLimitList {
gcgCard.SkillLimitsList = append(gcgCard.SkillLimitsList, &proto.GCGSkillLimitsInfo{
SkillId: skillId,
LimitsList: nil, // TODO 技能限制列表
})
}
gcgAskDuelRsp.Duel.CardList = append(gcgAskDuelRsp.Duel.CardList, gcgCard)
gcgAskDuelRsp.Duel.CardIdList = append(gcgAskDuelRsp.Duel.CardIdList, info.cardId)
// Field
playerField.ModifyZoneMap[info.guid] = &proto.GCGZone{CardList: []uint32{}} playerField.ModifyZoneMap[info.guid] = &proto.GCGZone{CardList: []uint32{}}
playerField.Unk3300_INDJNJJJNKL.CardList = append(playerField.Unk3300_INDJNJJJNKL.CardList, info.guid) playerField.Unk3300_INDJNJJJNKL.CardList = append(playerField.Unk3300_INDJNJJJNKL.CardList, info.guid)
// Phase
gcgAskDuelRsp.Duel.Phase.AllowControllerMap[controller.controllerId] = controller.allow
} }
// 添加完所有卡牌的位置之类的信息 添加这个牌盒 // 添加完所有卡牌的位置之类的信息添加这个牌盒
gcgAskDuelRsp.Duel.FieldList = append(gcgAskDuelRsp.Duel.FieldList, playerField) gcgAskDuelRsp.Duel.FieldList = append(gcgAskDuelRsp.Duel.FieldList, playerField)
// Unk3300_CDCMBOKBLAK }
// 历史卡牌信息
for _, cardInfo := range game.historyCardList {
gcgAskDuelRsp.Duel.HistoryCardList = append(gcgAskDuelRsp.Duel.HistoryCardList, cardInfo.ToProto())
}
// 卡牌信息
for _, controller := range game.controllerMap {
for _, cardInfo := range controller.cardList {
gcgAskDuelRsp.Duel.CardList = append(gcgAskDuelRsp.Duel.CardList, cardInfo.ToProto())
gcgAskDuelRsp.Duel.CardIdList = append(gcgAskDuelRsp.Duel.CardIdList, cardInfo.cardId)
}
}
// 阶段信息
for _, controller := range game.controllerMap {
// 操控者是否允许操作
gcgAskDuelRsp.Duel.Phase.AllowControllerMap[controller.controllerId] = controller.allow
}
// Unk3300_CDCMBOKBLAK 你问我这是啥? 我也不知道
for _, controller := range game.controllerMap {
gcgAskDuelRsp.Duel.Unk3300_CDCMBOKBLAK = append(gcgAskDuelRsp.Duel.Unk3300_CDCMBOKBLAK, &proto.Unk3300_ADHENCIFKNI{ gcgAskDuelRsp.Duel.Unk3300_CDCMBOKBLAK = append(gcgAskDuelRsp.Duel.Unk3300_CDCMBOKBLAK, &proto.Unk3300_ADHENCIFKNI{
BeginTime: 0, BeginTime: 0,
TimeStamp: 0, TimeStamp: 0,
ControllerId: controller.controllerId, ControllerId: controller.controllerId,
}) })
} }
GAME_MANAGER.SendMsg(cmd.GCGAskDuelRsp, player.PlayerID, player.ClientSeq, gcgAskDuelRsp) GAME_MANAGER.SendMsg(cmd.GCGAskDuelRsp, player.PlayerID, player.ClientSeq, gcgAskDuelRsp)
} }
@@ -323,16 +313,12 @@ func (g *GameManager) GCGOperationReq(player *model.Player, payloadMsg pb.Messag
return return
} }
} }
// 客户端更新操控者 // 操控者确认重投骰子
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, game.GCGMsgUpdateController()) game.ControllerReRollDice(gameController, op.DiceIndexList)
// 游戏行动阶段
game.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_PRE_MAIN)
default: default:
logger.Error("gcg op is not handle, op: %T", req.Op.Op) logger.Error("gcg op is not handle, op: %T", req.Op.Op)
g.CommonRetError(cmd.GCGOperationRsp, player, &proto.GCGOperationRsp{}, proto.Retcode_RET_GCG_OPERATION_PARAM_ERROR)
return return
} }
// PacketGCGOperationRsp // PacketGCGOperationRsp
gcgOperationRsp := &proto.GCGOperationRsp{ gcgOperationRsp := &proto.GCGOperationRsp{
OpSeq: req.OpSeq, OpSeq: req.OpSeq,
@@ -340,6 +326,27 @@ func (g *GameManager) GCGOperationReq(player *model.Player, payloadMsg pb.Messag
GAME_MANAGER.SendMsg(cmd.GCGOperationRsp, player.PlayerID, player.ClientSeq, gcgOperationRsp) GAME_MANAGER.SendMsg(cmd.GCGOperationRsp, player.PlayerID, player.ClientSeq, gcgOperationRsp)
} }
// PacketGCGSkillPreviewNotify GCG游戏技能栏展示通知
func (g *GameManager) PacketGCGSkillPreviewNotify(controller *GCGController) *proto.GCGSkillPreviewNotify {
// 确保玩家选择了角色牌
if controller.selectedCharCard == nil {
logger.Error("selected char is nil, controllerId: %v", controller.controllerId)
return new(proto.GCGSkillPreviewNotify)
}
// PacketGCGSkillPreviewNotify
gcgSkillPreviewNotify := &proto.GCGSkillPreviewNotify{
ControllerId: controller.controllerId,
// 当前角色牌拥有的技能信息
SkillPreviewList: make([]*proto.GCGSkillPreviewInfo, 0, len(controller.selectedCharCard.skillIdList)),
// 切换到其他角色牌的所需消耗信息
ChangeOnstagePreviewList: make([]*proto.GCGChangeOnstageInfo, 0, 2), // 暂时写死
PlayCardList: make([]*proto.GCGSkillPreviewPlayCardInfo, 0, 0),
OnstageCardGuid: controller.selectedCharCard.guid, // 当前被选择的角色牌guid
}
return gcgSkillPreviewNotify
}
// SendGCGMessagePackNotify 发送GCG游戏消息包通知
func (g *GameManager) SendGCGMessagePackNotify(controller *GCGController, serverSeq uint32, msgPackList []*proto.GCGMessagePack) { func (g *GameManager) SendGCGMessagePackNotify(controller *GCGController, serverSeq uint32, msgPackList []*proto.GCGMessagePack) {
// 确保加载完成 // 确保加载完成
if controller.loadState != ControllerLoadState_InitFinish { if controller.loadState != ControllerLoadState_InitFinish {

View File

@@ -268,6 +268,7 @@ func (c *CmdProtoMap) registerAllMessage() {
c.registerMessage(GCGHeartBeatNotify, &proto.GCGHeartBeatNotify{}) // GCG游戏心跳包通知 c.registerMessage(GCGHeartBeatNotify, &proto.GCGHeartBeatNotify{}) // GCG游戏心跳包通知
c.registerMessage(GCGOperationReq, &proto.GCGOperationReq{}) // GCG游戏客户端操作请求 c.registerMessage(GCGOperationReq, &proto.GCGOperationReq{}) // GCG游戏客户端操作请求
c.registerMessage(GCGOperationRsp, &proto.GCGOperationRsp{}) // GCG游戏客户端操作响应 c.registerMessage(GCGOperationRsp, &proto.GCGOperationRsp{}) // GCG游戏客户端操作响应
c.registerMessage(GCGSkillPreviewNotify, &proto.GCGSkillPreviewNotify{}) // GCG游戏技能栏展示通知
// // TODO 客户端开始GCG游戏 // // TODO 客户端开始GCG游戏
// c.registerMessage(GCGStartChallengeByCheckRewardReq, &proto.GCGStartChallengeByCheckRewardReq{}) // GCG开始挑战来自检测奖励请求 // c.registerMessage(GCGStartChallengeByCheckRewardReq, &proto.GCGStartChallengeByCheckRewardReq{}) // GCG开始挑战来自检测奖励请求