mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 16:02:26 +08:00
1172 lines
38 KiB
Go
1172 lines
38 KiB
Go
package game
|
|
|
|
import (
|
|
"math/rand"
|
|
"time"
|
|
|
|
"hk4e/common/constant"
|
|
"hk4e/gdconf"
|
|
"hk4e/gs/model"
|
|
"hk4e/pkg/logger"
|
|
"hk4e/protocol/cmd"
|
|
"hk4e/protocol/proto"
|
|
)
|
|
|
|
// ControllerType 操控者类型
|
|
type ControllerType uint8
|
|
|
|
const (
|
|
ControllerType_None ControllerType = iota
|
|
ControllerType_Player // 玩家
|
|
ControllerType_AI // AI
|
|
)
|
|
|
|
// GCGSkillInfo 游戏对局内卡牌技能信息
|
|
type GCGSkillInfo struct {
|
|
skillId uint32 // 技能Id
|
|
}
|
|
|
|
// GCGCardInfo 游戏对局内卡牌
|
|
type GCGCardInfo struct {
|
|
cardId uint32 // 卡牌Id
|
|
cardType CardInfoType // 卡牌类型
|
|
guid uint32 // 唯一Id
|
|
controllerId uint32 // 拥有它的操控者
|
|
faceType uint32 // 卡面类型
|
|
tagList []uint32 // Tag
|
|
tokenMap map[uint32]uint32 // Token
|
|
skillList []*GCGSkillInfo // 技能列表
|
|
skillLimitList []uint32 // 技能限制列表
|
|
}
|
|
|
|
func (g *GCGCardInfo) ToProto(controller *GCGController) *proto.GCGCard {
|
|
// 如果这不是指定操控者的牌 或 该牌在牌堆内 则隐藏详细信息
|
|
// 角色牌不受此影响
|
|
if g.cardType != CardInfoType_Char && (controller.controllerId != g.controllerId || g.cardType == CardInfoType_Deck) {
|
|
return &proto.GCGCard{ControllerId: g.controllerId, Guid: g.guid}
|
|
}
|
|
gcgCard := &proto.GCGCard{
|
|
TagList: g.tagList,
|
|
Guid: g.guid,
|
|
IsShow: true,
|
|
TokenList: make([]*proto.GCGToken, 0, len(g.tokenMap)),
|
|
FaceType: g.faceType,
|
|
SkillIdList: make([]uint32, 0, len(g.skillList)),
|
|
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,
|
|
})
|
|
}
|
|
// SkillIdList
|
|
for _, skillInfo := range g.skillList {
|
|
gcgCard.SkillIdList = append(gcgCard.SkillIdList, skillInfo.skillId)
|
|
}
|
|
// TODO SkillLimitsList
|
|
for _, skillId := range g.skillLimitList {
|
|
gcgCard.SkillLimitsList = append(gcgCard.SkillLimitsList, &proto.GCGSkillLimitsInfo{
|
|
SkillId: skillId,
|
|
LimitsList: nil, // TODO 技能限制列表
|
|
})
|
|
}
|
|
return gcgCard
|
|
}
|
|
|
|
// ControllerLoadState 操控者加载状态
|
|
type ControllerLoadState uint8
|
|
|
|
const (
|
|
ControllerLoadState_None ControllerLoadState = iota
|
|
ControllerLoadState_AskDuel // 回复决斗
|
|
ControllerLoadState_InitFinish // 初始化完成
|
|
)
|
|
|
|
// CardInfoType 卡牌信息类型
|
|
type CardInfoType uint8
|
|
|
|
const (
|
|
CardInfoType_None CardInfoType = iota
|
|
CardInfoType_Char // 角色牌
|
|
CardInfoType_Hand // 手牌
|
|
CardInfoType_Deck // 牌堆
|
|
)
|
|
|
|
// GCGController 操控者
|
|
type GCGController struct {
|
|
controllerId uint32 // 操控者Id
|
|
cardMap map[CardInfoType][]*GCGCardInfo // 卡牌列表
|
|
loadState ControllerLoadState // 加载状态
|
|
allow uint32 // 是否允许操控 0 -> 不允许 1 -> 允许
|
|
selectedCharCardGuid uint32 // 选择的角色卡牌guid
|
|
serverSeqCounter uint32 // 请求序列生成计数器
|
|
msgPackList []*proto.GCGMessagePack // 消息包待发送区
|
|
historyMsgPackList []*proto.GCGMessagePack // 历史消息包列表
|
|
historyCardList []*GCGCardInfo // 历史卡牌列表
|
|
controllerType ControllerType // 操控者的类型
|
|
player *model.Player // 玩家对象
|
|
ai *GCGAi // AI对象
|
|
}
|
|
|
|
// GetSelectedCharCard 获取操控者当前选择的角色卡牌
|
|
func (g *GCGController) GetSelectedCharCard() *GCGCardInfo {
|
|
return g.GetCharCardByGuid(g.selectedCharCardGuid)
|
|
}
|
|
|
|
// GetCharCardByGuid 通过卡牌的Guid获取角色牌
|
|
func (g *GCGController) GetCharCardByGuid(cardGuid uint32) *GCGCardInfo {
|
|
charCardList := g.cardMap[CardInfoType_Char]
|
|
for _, info := range charCardList {
|
|
if info.guid == cardGuid {
|
|
return info
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetHandCardByGuid 通过卡牌的Guid获取手牌
|
|
func (g *GCGController) GetHandCardByGuid(cardGuid uint32) *GCGCardInfo {
|
|
handCardList := g.cardMap[CardInfoType_Hand]
|
|
for _, info := range handCardList {
|
|
if info.guid == cardGuid {
|
|
return info
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetDeckCardByGuid 通过卡牌的Guid获取牌堆里的牌
|
|
func (g *GCGController) GetDeckCardByGuid(cardGuid uint32) *GCGCardInfo {
|
|
deckCardList := g.cardMap[CardInfoType_Deck]
|
|
for _, info := range deckCardList {
|
|
if info.guid == cardGuid {
|
|
return info
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GCGManager 七圣召唤管理器
|
|
type GCGManager struct {
|
|
phaseFuncMap map[proto.GCGPhaseType]func(game *GCGGame) // 游戏阶段处理
|
|
gameMap map[uint32]*GCGGame // 游戏列表 uint32 -> guid
|
|
gameGuidCounter uint32 // 游戏guid生成计数器
|
|
}
|
|
|
|
func NewGCGManager() *GCGManager {
|
|
gcgManager := new(GCGManager)
|
|
gcgManager.phaseFuncMap = map[proto.GCGPhaseType]func(game *GCGGame){
|
|
proto.GCGPhaseType_GCG_PHASE_START: gcgManager.PhaseStart,
|
|
proto.GCGPhaseType_GCG_PHASE_DRAW: gcgManager.PhaseDraw,
|
|
proto.GCGPhaseType_GCG_PHASE_DICE: gcgManager.PhaseRollDice,
|
|
proto.GCGPhaseType_GCG_PHASE_PRE_MAIN: gcgManager.PhasePreMain,
|
|
proto.GCGPhaseType_GCG_PHASE_MAIN: gcgManager.PhaseMain,
|
|
}
|
|
gcgManager.gameMap = make(map[uint32]*GCGGame)
|
|
return gcgManager
|
|
}
|
|
|
|
// CreateGame 创建GCG游戏对局
|
|
func (g *GCGManager) CreateGame(gameId uint32, playerList []*model.Player) *GCGGame {
|
|
g.gameGuidCounter++
|
|
game := &GCGGame{
|
|
guid: g.gameGuidCounter,
|
|
gameId: gameId,
|
|
roundInfo: &GCGRoundInfo{
|
|
roundNum: 1, // 默认以第一回合开始
|
|
firstController: 1, // 1号操控者为先手
|
|
diceSideMap: make(map[uint32][]proto.GCGDiceSideType, 2),
|
|
},
|
|
controllerMap: make(map[uint32]*GCGController, 2),
|
|
}
|
|
// 初始化游戏
|
|
game.InitGame(playerList)
|
|
// 记录游戏
|
|
g.gameMap[game.guid] = game
|
|
return game
|
|
}
|
|
|
|
// PhaseStart 阶段开始
|
|
func (g *GCGManager) PhaseStart(game *GCGGame) {
|
|
// 设置除了先手的玩家不允许操控
|
|
game.SetExceptControllerAllow(game.roundInfo.firstController, false, true)
|
|
// 游戏跳过阶段消息包
|
|
game.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_SEND_MESSAGE, game.GCGMsgPhaseContinue())
|
|
// 等待玩家进入
|
|
}
|
|
|
|
// PhaseDraw 阶段抽取手牌
|
|
func (g *GCGManager) PhaseDraw(game *GCGGame) {
|
|
// TODO 新手教程关不抽手牌
|
|
// 每位操控者抽取手牌
|
|
for _, controller := range game.controllerMap {
|
|
game.ControllerDrawCard(controller, 5) // 默认5张
|
|
}
|
|
// 游戏选择角色卡牌阶段
|
|
game.ChangePhase(proto.GCGPhaseType_GCG_PHASE_ON_STAGE)
|
|
}
|
|
|
|
// PhaseRollDice 阶段投掷骰子
|
|
func (g *GCGManager) PhaseRollDice(game *GCGGame) {
|
|
// 给每位玩家投掷骰子
|
|
for _, controller := range game.controllerMap {
|
|
diceSideList := make([]proto.GCGDiceSideType, 0, 8)
|
|
rand.Seed(time.Now().UnixNano()) // 随机数种子
|
|
// 玩家需要8个骰子
|
|
for i := 0; i < 8; i++ {
|
|
// diceSide := proto.GCGDiceSideType(random.GetRandomInt32(1, 8))
|
|
diceSide := proto.GCGDiceSideType_GCG_DICE_SIDE_PAIMON
|
|
diceSideList = append(diceSideList, diceSide)
|
|
}
|
|
// 存储该回合玩家的骰子
|
|
game.roundInfo.diceSideMap[controller.controllerId] = diceSideList
|
|
for _, c := range game.controllerMap {
|
|
// 发送给其他玩家骰子信息时隐藏具体的骰子类型
|
|
if c == controller {
|
|
game.AddMsgPack(c, controller.controllerId, proto.GCGActionType_GCG_ACTION_ROLL, game.GCGMsgDiceRoll(controller.controllerId, uint32(len(diceSideList)), diceSideList))
|
|
} else {
|
|
game.AddMsgPack(c, controller.controllerId, proto.GCGActionType_GCG_ACTION_ROLL, game.GCGMsgDiceRoll(controller.controllerId, uint32(len(diceSideList)), []proto.GCGDiceSideType{}))
|
|
}
|
|
}
|
|
}
|
|
// 等待玩家确认重投骰子
|
|
}
|
|
|
|
// PhasePreMain 阶段战斗开始
|
|
func (g *GCGManager) PhasePreMain(game *GCGGame) {
|
|
// TODO 使用技能完善
|
|
game.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_TRIGGER_SKILL, game.GCGMsgUseSkill(195, 33024), game.GCGMsgNewCard(), game.GCGMsgModifyAdd(2, proto.GCGReason_GCG_REASON_EFFECT, 4, []uint32{23}), game.GCGMsgUseSkillEnd(181, 33024))
|
|
// 设置先手允许操控
|
|
game.SetControllerAllow(game.controllerMap[game.roundInfo.firstController], true, false)
|
|
// 游戏行动阶段
|
|
game.ChangePhase(proto.GCGPhaseType_GCG_PHASE_MAIN)
|
|
}
|
|
|
|
// PhaseMain 阶段行动
|
|
func (g *GCGManager) PhaseMain(game *GCGGame) {
|
|
// 消耗费用信息
|
|
for _, controller := range game.controllerMap {
|
|
game.AddMsgPack(controller, 0, proto.GCGActionType_GCG_ACTION_NOTIFY_COST, game.GCGMsgCostRevise(controller))
|
|
// 如果玩家当前允许操作则发送技能预览信息
|
|
if controller.allow == 1 && controller.player != nil {
|
|
GAME_MANAGER.SendMsg(cmd.GCGSkillPreviewNotify, controller.player.PlayerID, controller.player.ClientSeq, GAME_MANAGER.PacketGCGSkillPreviewNotify(game, controller))
|
|
}
|
|
}
|
|
}
|
|
|
|
type GCGGameState uint8
|
|
|
|
const (
|
|
GCGGameState_None GCGGameState = iota
|
|
GCGGameState_Waiting // 等待玩家加载
|
|
GCGGameState_Running // 游戏运行中
|
|
GCGGameState_Stoped // 游戏已结束
|
|
)
|
|
|
|
// GCGRoundInfo 游戏对局回合信息
|
|
type GCGRoundInfo struct {
|
|
roundNum uint32 // 游戏当前回合数
|
|
phaseType proto.GCGPhaseType // 现在所处的阶段类型
|
|
allowControllerMap map[uint32]uint32 // 阶段玩家允许列表 主要用于断线重连
|
|
firstController uint32 // 当前回合先手的操控者
|
|
diceSideMap map[uint32][]proto.GCGDiceSideType // 操控者骰子列表 uint32 -> controllerId
|
|
isLastMsgPack bool // 是否为阶段切换的最后一个消息包 用于粘包模拟官服效果
|
|
}
|
|
|
|
// GCGGame 游戏对局
|
|
type GCGGame struct {
|
|
guid uint32 // 唯一Id
|
|
gameId uint32 // 游戏Id
|
|
gameState GCGGameState // 游戏运行状态
|
|
gameTick uint32 // 游戏tick
|
|
controllerIdCounter uint32 // 操控者Id生成器
|
|
cardGuidCounter uint32 // 卡牌guid生成计数器
|
|
roundInfo *GCGRoundInfo // 游戏回合信息
|
|
controllerMap map[uint32]*GCGController // 操控者列表 uint32 -> controllerId
|
|
}
|
|
|
|
// CreateController 创建操控者
|
|
func (g *GCGGame) CreateController() *GCGController {
|
|
// 创建操控者
|
|
g.controllerIdCounter++
|
|
controller := &GCGController{
|
|
controllerId: g.controllerIdCounter,
|
|
cardMap: map[CardInfoType][]*GCGCardInfo{
|
|
CardInfoType_Char: make([]*GCGCardInfo, 0, 3),
|
|
CardInfoType_Hand: make([]*GCGCardInfo, 0, 30),
|
|
CardInfoType_Deck: make([]*GCGCardInfo, 0, 30),
|
|
},
|
|
allow: 1,
|
|
msgPackList: make([]*proto.GCGMessagePack, 0, 10),
|
|
historyMsgPackList: make([]*proto.GCGMessagePack, 0, 50),
|
|
historyCardList: make([]*GCGCardInfo, 0, 100),
|
|
}
|
|
// 记录操控者
|
|
g.controllerMap[g.controllerIdCounter] = controller
|
|
return controller
|
|
}
|
|
|
|
// AddPlayer GCG游戏添加玩家
|
|
func (g *GCGGame) AddPlayer(player *model.Player) {
|
|
// 创建操控者
|
|
controller := g.CreateController()
|
|
controller.controllerType = ControllerType_Player
|
|
controller.player = player
|
|
// 生成卡牌信息
|
|
g.GiveCharCard(controller, 1301)
|
|
g.GiveCharCard(controller, 1103)
|
|
// 玩家记录当前所在的游戏guid
|
|
player.GCGCurGameGuid = g.guid
|
|
}
|
|
|
|
// AddAI GCG游戏添加AI
|
|
func (g *GCGGame) AddAI() {
|
|
// 创建操控者
|
|
controller := g.CreateController()
|
|
controller.controllerType = ControllerType_AI
|
|
controller.ai = &GCGAi{
|
|
game: g,
|
|
controllerId: g.controllerIdCounter,
|
|
}
|
|
// 生成卡牌信息
|
|
g.GiveCharCard(controller, 3001)
|
|
g.GiveCharCard(controller, 3302)
|
|
// AI加载完毕
|
|
controller.loadState = ControllerLoadState_InitFinish
|
|
}
|
|
|
|
// InitDeckCard 初始化操控者的卡组
|
|
func (g *GCGGame) InitDeckCard(controller *GCGController, cardIdList ...uint32) {
|
|
for _, cardId := range cardIdList {
|
|
// 生成卡牌信息
|
|
g.cardGuidCounter++
|
|
cardInfo := &GCGCardInfo{
|
|
cardId: cardId,
|
|
cardType: CardInfoType_Deck,
|
|
guid: g.cardGuidCounter,
|
|
controllerId: controller.controllerId,
|
|
}
|
|
controller.cardMap[CardInfoType_Deck] = append(controller.cardMap[CardInfoType_Deck], cardInfo)
|
|
}
|
|
}
|
|
|
|
// GiveCharCard 给予操控者角色卡牌
|
|
func (g *GCGGame) GiveCharCard(controller *GCGController, charId uint32) {
|
|
// 读取角色卡牌配置表
|
|
gcgCharConfig := gdconf.GetGCGCharDataById(int32(charId))
|
|
if gcgCharConfig == nil {
|
|
logger.Error("gcg char config error, charId: %v", charId)
|
|
return
|
|
}
|
|
// 生成卡牌信息
|
|
g.cardGuidCounter++
|
|
cardInfo := &GCGCardInfo{
|
|
cardId: charId,
|
|
cardType: CardInfoType_Char,
|
|
guid: g.cardGuidCounter,
|
|
controllerId: controller.controllerId,
|
|
faceType: 0, // 1为金卡
|
|
tagList: gcgCharConfig.TagList,
|
|
tokenMap: map[uint32]uint32{
|
|
constant.GCG_TOKEN_TYPE_CUR_HEALTH: uint32(gcgCharConfig.HPBase), // 血量
|
|
constant.GCG_TOKEN_TYPE_MAX_HEALTH: uint32(gcgCharConfig.HPBase), // 最大血量(不确定)
|
|
constant.GCG_TOKEN_TYPE_CUR_ELEM: 0, // 充能
|
|
constant.GCG_TOKEN_TYPE_MAX_ELEM: uint32(gcgCharConfig.MaxElemVal), // 充能条
|
|
},
|
|
skillList: make([]*GCGSkillInfo, 0, len(gcgCharConfig.SkillList)),
|
|
skillLimitList: []uint32{},
|
|
}
|
|
// SkillMap
|
|
for _, skillId := range gcgCharConfig.SkillList {
|
|
skillInfo := &GCGSkillInfo{
|
|
skillId: skillId,
|
|
}
|
|
cardInfo.skillList = append(cardInfo.skillList, skillInfo)
|
|
}
|
|
controller.cardMap[CardInfoType_Char] = append(controller.cardMap[CardInfoType_Char], cardInfo)
|
|
// 添加历史卡牌
|
|
for _, gcgController := range g.controllerMap {
|
|
// 每位玩家都记录其他玩家的角色卡牌
|
|
gcgController.historyCardList = append(gcgController.historyCardList, cardInfo)
|
|
}
|
|
}
|
|
|
|
// ChangePhase 游戏更改阶段
|
|
func (g *GCGGame) ChangePhase(phase proto.GCGPhaseType) {
|
|
beforePhase := g.roundInfo.phaseType
|
|
// 修改游戏的阶段
|
|
g.roundInfo.phaseType = phase
|
|
// 改变阶段覆盖掉上层可能有的true
|
|
g.roundInfo.isLastMsgPack = false
|
|
|
|
// 操控者允许操作列表
|
|
g.roundInfo.allowControllerMap = make(map[uint32]uint32, len(g.controllerMap))
|
|
|
|
// 根据阶段改变操控者允许状态
|
|
switch phase {
|
|
case proto.GCGPhaseType_GCG_PHASE_ON_STAGE, proto.GCGPhaseType_GCG_PHASE_DICE:
|
|
// 该阶段允许所有操控者操作
|
|
g.SetAllControllerAllow(true, false)
|
|
|
|
for _, controller := range g.controllerMap {
|
|
g.roundInfo.allowControllerMap[controller.controllerId] = controller.allow
|
|
}
|
|
case proto.GCGPhaseType_GCG_PHASE_MAIN:
|
|
// 行动阶段仅允许操控者操作
|
|
for _, controller := range g.controllerMap {
|
|
// 跳过不允许的操控者
|
|
if controller.allow == 0 {
|
|
continue
|
|
}
|
|
g.roundInfo.allowControllerMap[controller.controllerId] = controller.allow
|
|
}
|
|
}
|
|
|
|
allowControllerMap := make(map[uint32]uint32)
|
|
for controllerId, allow := range g.roundInfo.allowControllerMap {
|
|
allowControllerMap[controllerId] = allow
|
|
}
|
|
|
|
// 游戏下一阶段切换消息包
|
|
g.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_NEXT_PHASE, g.GCGMsgPhaseChange(beforePhase, phase, allowControllerMap))
|
|
|
|
// 执行阶段处理前假装现在是最后一个阶段处理
|
|
g.roundInfo.isLastMsgPack = true
|
|
|
|
// 执行下一阶段
|
|
phaseFunc, ok := GCG_MANAGER.phaseFuncMap[g.roundInfo.phaseType]
|
|
// 确保该阶段有进行处理的函数
|
|
if ok {
|
|
phaseFunc(g) // 进行该阶段的处理
|
|
}
|
|
|
|
// 如果阶段里不嵌套处理别的阶段了就在此发送消息包
|
|
// 总之就是确保发送的时候为最后一个阶段变更
|
|
if g.roundInfo.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.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_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.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_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.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_NONE, g.GCGMsgUpdateController())
|
|
}
|
|
}
|
|
|
|
// ControllerSelectChar 操控者选择角色卡牌
|
|
func (g *GCGGame) ControllerSelectChar(controller *GCGController, cardInfo *GCGCardInfo, costDiceIndexList []uint32) {
|
|
// 角色卡牌仅在未选择时无需消耗元素骰子
|
|
if controller.selectedCharCardGuid != 0 && len(costDiceIndexList) == 0 {
|
|
// 首次选择角色牌不消耗点数
|
|
return
|
|
}
|
|
// TODO 消耗骰子点数
|
|
// 设置角色卡牌
|
|
controller.selectedCharCardGuid = cardInfo.guid
|
|
|
|
// 设置玩家禁止操作
|
|
g.SetControllerAllow(controller, false, true)
|
|
|
|
// 广播选择的角色卡牌消息包
|
|
g.AddAllMsgPack(controller.controllerId, proto.GCGActionType_GCG_ACTION_SELECT_ONSTAGE, g.GCGMsgSelectOnStage(controller.controllerId, cardInfo.guid, proto.GCGReason_GCG_REASON_DEFAULT))
|
|
|
|
// 该阶段确保每位玩家都选择了角色牌
|
|
isAllSelectedChar := true
|
|
for _, c := range g.controllerMap {
|
|
if c.selectedCharCardGuid == 0 {
|
|
isAllSelectedChar = false
|
|
}
|
|
}
|
|
// 如果有玩家未选择角色牌不同处理
|
|
if isAllSelectedChar {
|
|
// 回合信息
|
|
g.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_SEND_MESSAGE, g.GCGMsgDuelDataChange())
|
|
// 游戏投掷骰子阶段
|
|
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_DICE)
|
|
} else {
|
|
// 跳过该阶段 官服是这样的我也不知道为什么
|
|
g.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_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_PRE_MAIN)
|
|
}
|
|
|
|
// ControllerUseSkill 操控者使用技能
|
|
func (g *GCGGame) ControllerUseSkill(controller *GCGController, skillId uint32, costDiceIndexList []uint32) {
|
|
logger.Error("controller use skill, id: %v, skillId: %v", controller.controllerId, skillId)
|
|
// 获取对方的操控者对象
|
|
targetController := g.GetOtherController(controller.controllerId)
|
|
if targetController == nil {
|
|
logger.Error("target controller is nil, controllerId: %v", controller.controllerId)
|
|
return
|
|
}
|
|
// 获取对方出战的角色牌
|
|
targetSelectedCharCard := targetController.GetSelectedCharCard()
|
|
// 确保玩家选择了角色牌
|
|
if targetController == nil {
|
|
logger.Error("selected char card is nil, cardGuid: %v", controller.selectedCharCardGuid)
|
|
return
|
|
}
|
|
// 其他操控者允许操作
|
|
g.SetExceptControllerAllow(controller.controllerId, true, false)
|
|
// 该操控者禁止操作
|
|
g.SetControllerAllow(controller, false, true)
|
|
|
|
msgList := make([]*proto.GCGMessage, 0, 0)
|
|
|
|
// 使用技能消耗元素骰子
|
|
msgList = append(msgList, g.GCGMsgCostDice(controller, proto.GCGReason_GCG_REASON_COST, costDiceIndexList))
|
|
|
|
msgList = append(msgList, g.GCGMsgUseSkill(controller.selectedCharCardGuid, skillId))
|
|
|
|
msgList = append(msgList, g.GCGMsgTokenChange(targetSelectedCharCard.guid, proto.GCGReason_GCG_REASON_EFFECT, 11, 1))
|
|
msgList = append(msgList, g.GCGMsgTokenChange(targetSelectedCharCard.guid, proto.GCGReason_GCG_REASON_EFFECT_DAMAGE, constant.GCG_TOKEN_TYPE_CUR_HEALTH, 6))
|
|
msgList = append(msgList, g.GCGMsgSkillResult(targetSelectedCharCard.guid, skillId))
|
|
|
|
msgList = append(msgList, g.GCGMsgUseSkillEnd(controller.selectedCharCardGuid, skillId))
|
|
|
|
// 因为使用技能自身充能+1
|
|
msgList = append(msgList, g.GCGMsgTokenChange(controller.selectedCharCardGuid, proto.GCGReason_GCG_REASON_ATTACK, constant.GCG_TOKEN_TYPE_CUR_ELEM, 3))
|
|
g.AddAllMsgPack(controller.controllerId, proto.GCGActionType_GCG_ACTION_ATTACK, msgList...)
|
|
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_MAIN)
|
|
}
|
|
|
|
// ControllerDrawCard 操控者抽取手牌
|
|
func (g *GCGGame) ControllerDrawCard(controller *GCGController, count int) {
|
|
msgList := make([]*proto.GCGMessage, 0, count)
|
|
// 隐藏卡牌信息的消息列表
|
|
otherMsgList := make([]*proto.GCGMessage, 0, count)
|
|
for i := 0; i < count; i++ {
|
|
deckCardList := controller.cardMap[CardInfoType_Deck]
|
|
// 没有卡了就别拿了再拿就报错了
|
|
if len(deckCardList) < 1 {
|
|
logger.Error("deck card len error, len: %v", len(deckCardList))
|
|
return
|
|
}
|
|
cardInfo := deckCardList[0] // 拿最上面的一张
|
|
cardInfo.cardType = CardInfoType_Hand // 修改卡牌类型为手牌
|
|
// 添加到消息列表
|
|
msgList = append(msgList, g.GCGMsgCardUpdate(cardInfo.ToProto(controller)))
|
|
otherMsgList = append(otherMsgList, g.GCGMsgCardUpdate(&proto.GCGCard{ControllerId: controller.controllerId, Guid: cardInfo.guid}))
|
|
// 加入到手牌
|
|
controller.cardMap[CardInfoType_Hand] = append(controller.cardMap[CardInfoType_Hand], cardInfo)
|
|
// 删除已经被拿走的手牌
|
|
deckCardList = append(deckCardList[:0], deckCardList[1:]...)
|
|
}
|
|
// 发送给别人隐藏卡牌信息的消息包 为了安全
|
|
for _, c := range g.controllerMap {
|
|
if c == controller {
|
|
g.AddMsgPack(c, controller.controllerId, proto.GCGActionType_GCG_ACTION_DRAW, msgList...)
|
|
} else {
|
|
g.AddMsgPack(c, controller.controllerId, proto.GCGActionType_GCG_ACTION_DRAW, otherMsgList...)
|
|
}
|
|
}
|
|
}
|
|
|
|
// onTick 游戏的Tick
|
|
func (g *GCGGame) onTick() {
|
|
// 判断游戏是否运行中
|
|
if g.gameState != GCGGameState_Running {
|
|
return
|
|
}
|
|
// 每10s触发
|
|
if g.gameTick%10 == 0 {
|
|
// GCG游戏心跳包
|
|
for _, controller := range g.controllerMap {
|
|
// 跳过AI
|
|
if controller.player == nil {
|
|
continue
|
|
}
|
|
gcgHeartBeatNotify := &proto.GCGHeartBeatNotify{
|
|
ServerSeq: controller.serverSeqCounter,
|
|
}
|
|
GAME_MANAGER.SendMsg(cmd.GCGHeartBeatNotify, controller.player.PlayerID, controller.player.ClientSeq, gcgHeartBeatNotify)
|
|
}
|
|
}
|
|
g.gameTick++
|
|
}
|
|
|
|
// InitGame 初始化GCG游戏
|
|
func (g *GCGGame) InitGame(playerList []*model.Player) {
|
|
// 初始化玩家
|
|
for _, player := range playerList {
|
|
g.AddPlayer(player)
|
|
}
|
|
// 添加AI
|
|
g.AddAI()
|
|
|
|
// 每位操控者生成牌堆
|
|
for _, controller := range g.controllerMap {
|
|
g.InitDeckCard(controller, 311101, 311201, 311301, 311401, 311501)
|
|
}
|
|
|
|
// 游戏状态更改为等待玩家加载
|
|
g.gameState = GCGGameState_Waiting
|
|
|
|
// TODO 验证玩家人数是否符合
|
|
// 游戏开始阶段
|
|
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_START)
|
|
}
|
|
|
|
// StartGame 开始GCG游戏
|
|
func (g *GCGGame) StartGame() {
|
|
// 游戏状态更改为游戏运行中
|
|
g.gameState = GCGGameState_Running
|
|
|
|
logger.Error("game running")
|
|
|
|
// 游戏开始设置所有玩家不允许操作
|
|
g.SetAllControllerAllow(false, true)
|
|
// 分配先手
|
|
g.AddAllMsgPack(0, proto.GCGActionType_GCG_ACTION_PHASE_EXIT, g.GCGMsgClientPerform(proto.GCGClientPerformType_GCG_PERFORM_FIRST_HAND, []uint32{g.roundInfo.firstController}))
|
|
// 游戏抽取手牌阶段
|
|
g.ChangePhase(proto.GCGPhaseType_GCG_PHASE_DRAW)
|
|
}
|
|
|
|
// CheckAllInitFinish 检查所有玩家是否加载完成
|
|
func (g *GCGGame) CheckAllInitFinish() {
|
|
// 判断游戏是否已开始
|
|
if g.gameState == GCGGameState_Running {
|
|
logger.Error("gcg game is running")
|
|
return
|
|
}
|
|
// 检查所有玩家是否加载完成
|
|
for _, controller := range g.controllerMap {
|
|
if controller.loadState != ControllerLoadState_InitFinish {
|
|
return
|
|
}
|
|
}
|
|
// TODO 可能会玩家中途退了 超时结束游戏
|
|
// 正式开始游戏
|
|
g.StartGame()
|
|
}
|
|
|
|
// AddAllMsgPack 添加GCG消息包至每位游戏玩家的待发送区
|
|
func (g *GCGGame) AddAllMsgPack(controllerId uint32, actionType proto.GCGActionType, msgList ...*proto.GCGMessage) {
|
|
// 给每位操控者添加消息包
|
|
for _, controller := range g.controllerMap {
|
|
g.AddMsgPack(controller, controllerId, actionType, msgList...)
|
|
}
|
|
}
|
|
|
|
// AddMsgPack 添加GCG消息包至待发送区
|
|
func (g *GCGGame) AddMsgPack(controller *GCGController, controllerId uint32, actionType proto.GCGActionType, msgList ...*proto.GCGMessage) {
|
|
pack := &proto.GCGMessagePack{
|
|
ActionType: actionType,
|
|
MsgList: make([]*proto.GCGMessage, 0, len(msgList)),
|
|
ControllerId: controllerId,
|
|
}
|
|
// 将每个GCG消息添加进消息包中
|
|
for _, message := range msgList {
|
|
pack.MsgList = append(pack.MsgList, message)
|
|
}
|
|
// 将消息包添加进待发送区
|
|
controller.msgPackList = append(controller.msgPackList, pack)
|
|
}
|
|
|
|
// SendMsgPack 发送待发送区的所有消息包
|
|
func (g *GCGGame) SendMsgPack(controller *GCGController) {
|
|
// 不发送空的消息包
|
|
if len(controller.msgPackList) == 0 {
|
|
return
|
|
}
|
|
// 游戏不处于运行状态仅记录历史消息包
|
|
if g.gameState == GCGGameState_Running {
|
|
controller.serverSeqCounter++
|
|
GAME_MANAGER.SendGCGMessagePackNotify(controller, controller.serverSeqCounter, controller.msgPackList)
|
|
}
|
|
// 记录发送的历史消息包
|
|
for _, pack := range controller.msgPackList {
|
|
// 根据观察 历史消息包的每个消息都将拆分为单独的消息包
|
|
for _, message := range pack.MsgList {
|
|
controller.historyMsgPackList = append(controller.historyMsgPackList, &proto.GCGMessagePack{
|
|
ActionType: pack.ActionType,
|
|
MsgList: []*proto.GCGMessage{
|
|
message,
|
|
},
|
|
ControllerId: pack.ControllerId,
|
|
})
|
|
}
|
|
}
|
|
// 清空待发送区消息包
|
|
controller.msgPackList = make([]*proto.GCGMessagePack, 0, 10)
|
|
}
|
|
|
|
// SendAllMsgPack 发送所有玩家的待发送区的消息包
|
|
func (g *GCGGame) SendAllMsgPack() {
|
|
for _, controller := range g.controllerMap {
|
|
g.SendMsgPack(controller)
|
|
}
|
|
}
|
|
|
|
// GCGMsgPhaseChange GCG消息阶段改变
|
|
func (g *GCGGame) GCGMsgPhaseChange(beforePhase proto.GCGPhaseType, afterPhase proto.GCGPhaseType, allowControllerMap map[uint32]uint32) *proto.GCGMessage {
|
|
gcgMsgPhaseChange := &proto.GCGMsgPhaseChange{
|
|
BeforePhase: beforePhase,
|
|
AfterPhase: afterPhase,
|
|
AllowControllerMap: allowControllerMap,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_PhaseChange{
|
|
PhaseChange: gcgMsgPhaseChange,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgPhaseContinue GCG消息阶段跳过
|
|
func (g *GCGGame) GCGMsgPhaseContinue() *proto.GCGMessage {
|
|
gcgMsgPhaseContinue := &proto.GCGMsgPhaseContinue{}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_PhaseContinue{
|
|
PhaseContinue: gcgMsgPhaseContinue,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgUpdateController GCG消息更新操控者
|
|
func (g *GCGGame) GCGMsgUpdateController() *proto.GCGMessage {
|
|
gcgMsgUpdateController := &proto.GCGMsgUpdateController{
|
|
AllowControllerMap: make(map[uint32]uint32),
|
|
}
|
|
// 操控者的是否允许操作
|
|
for _, controller := range g.controllerMap {
|
|
// 如果处于行动阶段只发送允许操作的
|
|
if g.roundInfo.phaseType == proto.GCGPhaseType_GCG_PHASE_MAIN && controller.allow == 0 {
|
|
continue
|
|
}
|
|
gcgMsgUpdateController.AllowControllerMap[controller.controllerId] = controller.allow
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_UpdateController{
|
|
UpdateController: gcgMsgUpdateController,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgClientPerform GCG消息客户端执行
|
|
func (g *GCGGame) GCGMsgClientPerform(performType proto.GCGClientPerformType, paramList []uint32) *proto.GCGMessage {
|
|
gcgMsgClientPerform := &proto.GCGMsgClientPerform{
|
|
ParamList: paramList,
|
|
PerformType: performType,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_ClientPerform{
|
|
ClientPerform: gcgMsgClientPerform,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgSelectOnStage GCG消息切换角色卡牌
|
|
func (g *GCGGame) GCGMsgSelectOnStage(controllerId uint32, cardGuid uint32, reason proto.GCGReason) *proto.GCGMessage {
|
|
gcgMsgClientPerform := &proto.GCGMsgSelectOnStage{
|
|
Reason: reason,
|
|
ControllerId: controllerId,
|
|
CardGuid: cardGuid,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_SelectOnStage{
|
|
SelectOnStage: gcgMsgClientPerform,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgPVEIntention GCG消息敌方行动意图
|
|
func (g *GCGGame) GCGMsgPVEIntention(pveIntentionList ...*proto.GCGMsgPVEIntention) *proto.GCGMessage {
|
|
gcgMsgPVEIntention := &proto.GCGMsgPVEIntentionInfo{
|
|
IntentionMap: make(map[uint32]*proto.GCGMsgPVEIntention),
|
|
}
|
|
for _, intention := range pveIntentionList {
|
|
gcgMsgPVEIntention.IntentionMap[intention.CardGuid] = intention
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_PveIntentionInfo{
|
|
PveIntentionInfo: gcgMsgPVEIntention,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgDuelDataChange GCG消息切换回合
|
|
func (g *GCGGame) GCGMsgDuelDataChange() *proto.GCGMessage {
|
|
gcgMsgDuelDataChange := &proto.GCGMsgDuelDataChange{
|
|
Round: g.roundInfo.roundNum,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_DuelDataChange{
|
|
DuelDataChange: gcgMsgDuelDataChange,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgDiceRoll GCG消息摇骰子
|
|
func (g *GCGGame) GCGMsgDiceRoll(controllerId uint32, diceNum uint32, diceSideList []proto.GCGDiceSideType) *proto.GCGMessage {
|
|
gcgMsgDiceRoll := &proto.GCGMsgDiceRoll{
|
|
ControllerId: controllerId,
|
|
DiceNum: diceNum,
|
|
DiceSideList: diceSideList,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_DiceRoll{
|
|
DiceRoll: gcgMsgDiceRoll,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgUseSkill GCG消息使用技能
|
|
func (g *GCGGame) GCGMsgUseSkill(selectedCharCardGuid uint32, skillId uint32) *proto.GCGMessage {
|
|
useSkillCardGuid := uint32(0)
|
|
switch selectedCharCardGuid {
|
|
case 1:
|
|
useSkillCardGuid = 235
|
|
case 2:
|
|
useSkillCardGuid = 245 // 没有实际数据这个猜的
|
|
case 3:
|
|
useSkillCardGuid = 251
|
|
case 4:
|
|
useSkillCardGuid = 195
|
|
case 5:
|
|
useSkillCardGuid = 185 // 猜测
|
|
case 6:
|
|
useSkillCardGuid = 175 // 猜测
|
|
}
|
|
gcgMsgUseSkill := &proto.GCGMsgUseSkill{
|
|
SkillId: skillId,
|
|
CardGuid: useSkillCardGuid,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_UseSkill{
|
|
UseSkill: gcgMsgUseSkill,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgUseSkillEnd GCG消息使用技能结束
|
|
func (g *GCGGame) GCGMsgUseSkillEnd(selectedCharCardGuid uint32, skillId uint32) *proto.GCGMessage {
|
|
useSkillEndCardGuid := uint32(0)
|
|
switch selectedCharCardGuid {
|
|
case 1:
|
|
useSkillEndCardGuid = 161
|
|
case 2:
|
|
useSkillEndCardGuid = 0 // 暂无数据
|
|
case 3:
|
|
useSkillEndCardGuid = 169
|
|
case 4:
|
|
useSkillEndCardGuid = 181
|
|
}
|
|
gcgMsgUseSkillEnd := &proto.GCGMsgUseSkillEnd{
|
|
SkillId: skillId,
|
|
CardGuid: useSkillEndCardGuid,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_UseSkillEnd{
|
|
UseSkillEnd: gcgMsgUseSkillEnd,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgCostRevise GCG消息消耗信息修改
|
|
func (g *GCGGame) GCGMsgCostRevise(controller *GCGController) *proto.GCGMessage {
|
|
selectedCharCard := controller.GetSelectedCharCard()
|
|
if selectedCharCard == nil {
|
|
logger.Error("selected char card is nil, cardGuid: %v", controller.selectedCharCardGuid)
|
|
return new(proto.GCGMessage)
|
|
}
|
|
gcgMsgCostRevise := &proto.GCGMsgCostRevise{
|
|
CostRevise: &proto.GCGCostReviseInfo{
|
|
// 可以使用的手牌Id列表
|
|
CanUseHandCardIdList: nil,
|
|
// 切换角色消耗列表
|
|
SelectOnStageCostList: make([]*proto.GCGSelectOnStageCostInfo, 0, len(controller.cardMap[CardInfoType_Char])),
|
|
// 打出牌时的消耗列表
|
|
PlayCardCostList: nil,
|
|
// 技能攻击消耗列表
|
|
AttackCostList: make([]*proto.GCGAttackCostInfo, 0, len(selectedCharCard.skillList)),
|
|
// 是否允许攻击
|
|
IsCanAttack: true,
|
|
},
|
|
ControllerId: controller.controllerId,
|
|
}
|
|
// AttackCostList
|
|
for _, skillInfo := range selectedCharCard.skillList {
|
|
// 读取卡牌技能配置表
|
|
gcgSkillConfig := gdconf.GetGCGSkillDataById(int32(skillInfo.skillId))
|
|
if gcgSkillConfig == nil {
|
|
logger.Error("gcg skill config error, skillId: %v", skillInfo.skillId)
|
|
return new(proto.GCGMessage)
|
|
}
|
|
gcgAttackCostInfo := &proto.GCGAttackCostInfo{
|
|
CostMap: make(map[uint32]uint32),
|
|
SkillId: skillInfo.skillId,
|
|
}
|
|
// 技能消耗
|
|
for costType, costValue := range gcgSkillConfig.CostMap {
|
|
gcgAttackCostInfo.CostMap[costType] = costValue
|
|
}
|
|
gcgMsgCostRevise.CostRevise.AttackCostList = append(gcgMsgCostRevise.CostRevise.AttackCostList, gcgAttackCostInfo)
|
|
}
|
|
// SelectOnStageCostList
|
|
for _, cardInfo := range controller.cardMap[CardInfoType_Char] {
|
|
// 排除当前已选中的角色卡
|
|
if cardInfo.guid == selectedCharCard.guid {
|
|
continue
|
|
}
|
|
gcgSelectOnStageCostInfo := &proto.GCGSelectOnStageCostInfo{
|
|
CardGuid: cardInfo.guid,
|
|
CostMap: map[uint32]uint32{
|
|
10: 1,
|
|
},
|
|
}
|
|
gcgMsgCostRevise.CostRevise.SelectOnStageCostList = append(gcgMsgCostRevise.CostRevise.SelectOnStageCostList, gcgSelectOnStageCostInfo)
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_CostRevise{
|
|
CostRevise: gcgMsgCostRevise,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgCostDice GCG消息消耗骰子
|
|
func (g *GCGGame) GCGMsgCostDice(controller *GCGController, gcgReason proto.GCGReason, selectDiceIndexList []uint32) *proto.GCGMessage {
|
|
gcgMsgCostDice := &proto.GCGMsgCostDice{
|
|
Reason: gcgReason,
|
|
SelectDiceIndexList: selectDiceIndexList,
|
|
ControllerId: controller.controllerId,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_CostDice{
|
|
CostDice: gcgMsgCostDice,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgTokenChange GCG消息卡牌Token修改
|
|
func (g *GCGGame) GCGMsgTokenChange(cardGuid uint32, reason proto.GCGReason, tokenType uint32, tokenValue uint32) *proto.GCGMessage {
|
|
tokenChangeValue := uint32(0)
|
|
switch tokenValue {
|
|
case 0:
|
|
tokenChangeValue = 2802
|
|
case 1:
|
|
tokenChangeValue = 2806
|
|
case 2:
|
|
tokenChangeValue = 2810
|
|
case 3:
|
|
tokenChangeValue = 2814 // 72
|
|
case 4:
|
|
tokenChangeValue = 2786
|
|
case 5:
|
|
tokenChangeValue = 2790
|
|
case 6:
|
|
tokenChangeValue = 2794
|
|
case 7:
|
|
tokenChangeValue = 2798 // 28
|
|
case 8:
|
|
tokenChangeValue = 2770
|
|
case 9:
|
|
tokenChangeValue = 2774
|
|
case 10:
|
|
// 暂无
|
|
}
|
|
gcgMsgTokenChange := &proto.GCGMsgTokenChange{
|
|
TokenType: tokenType,
|
|
// token改变为的值
|
|
After: tokenChangeValue,
|
|
Reason: reason,
|
|
// 可能是改变之前的值 无所谓就算是0也能跑
|
|
Before: 0, // Unk
|
|
CardGuid: cardGuid,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_TokenChange{
|
|
TokenChange: gcgMsgTokenChange,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgSkillResult GCG消息技能结果
|
|
func (g *GCGGame) GCGMsgSkillResult(selectedCharCardGuid uint32, skillId uint32) *proto.GCGMessage {
|
|
// 读取卡牌技能配置表
|
|
gcgSkillConfig := gdconf.GetGCGSkillDataById(int32(skillId))
|
|
if gcgSkillConfig == nil {
|
|
logger.Error("gcg skill config error, skillId: %v", skillId)
|
|
return new(proto.GCGMessage)
|
|
}
|
|
resultTargetCardGuid := uint32(0)
|
|
switch selectedCharCardGuid {
|
|
case 1:
|
|
resultTargetCardGuid = 174
|
|
case 2:
|
|
resultTargetCardGuid = 0 // 暂无数据
|
|
case 3:
|
|
resultTargetCardGuid = 166
|
|
case 4:
|
|
resultTargetCardGuid = 186
|
|
}
|
|
gcgMsgSkillResult := &proto.GCGMsgSkillResult{
|
|
// 攻击附带的元素特效
|
|
EffectElement: gcgSkillConfig.ElementType,
|
|
TargetCardGuid: resultTargetCardGuid,
|
|
// Unk3300_PDBAGJINFPF: 0, // Unk
|
|
DetailList: []*proto.GCGDamageDetail{},
|
|
SkillId: skillId,
|
|
Damage: gcgSkillConfig.Damage,
|
|
// Unk3300_EPNDCIAJOJP: 0,
|
|
// Unk3300_NNJAOEHNPPD: 0,
|
|
// Unk3300_LPGLOCDDPCL: 0,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_SkillResult{
|
|
SkillResult: gcgMsgSkillResult,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgNewCard GCG消息新卡牌
|
|
func (g *GCGGame) GCGMsgNewCard() *proto.GCGMessage {
|
|
gcgMsgNewCard := &proto.GCGMsgNewCard{
|
|
Card: &proto.GCGCard{
|
|
TagList: nil,
|
|
Guid: 6,
|
|
IsShow: true,
|
|
TokenList: []*proto.GCGToken{
|
|
{
|
|
Value: 3,
|
|
Key: 8,
|
|
},
|
|
},
|
|
FaceType: 0,
|
|
SkillIdList: []uint32{
|
|
63,
|
|
},
|
|
SkillLimitsList: nil,
|
|
Id: 133021,
|
|
ControllerId: 2,
|
|
},
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_NewCard{
|
|
NewCard: gcgMsgNewCard,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgCardUpdate GCG消息卡牌更新
|
|
func (g *GCGGame) GCGMsgCardUpdate(card *proto.GCGCard) *proto.GCGMessage {
|
|
gcgMsgCardUpdate := &proto.GCGMsgCardUpdate{
|
|
Card: card,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_CardUpdate{
|
|
CardUpdate: gcgMsgCardUpdate,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GCGMsgModifyAdd GCG消息修饰添加
|
|
func (g *GCGGame) GCGMsgModifyAdd(controllerId uint32, reason proto.GCGReason, ownerCardGuid uint32, cardGuidList []uint32) *proto.GCGMessage {
|
|
gcgMsgModifyAdd := &proto.GCGMsgModifyAdd{
|
|
OwnerCardGuid: ownerCardGuid,
|
|
Pos: 0,
|
|
CardGuidList: cardGuidList,
|
|
ControllerId: controllerId,
|
|
Reason: reason,
|
|
}
|
|
gcgMessage := &proto.GCGMessage{
|
|
Message: &proto.GCGMessage_ModifyAdd{
|
|
ModifyAdd: gcgMsgModifyAdd,
|
|
},
|
|
}
|
|
return gcgMessage
|
|
}
|
|
|
|
// GetOtherController 获取除了这个操控者之外的操控者
|
|
// 游戏目前仅支持两个玩家对战 不用考虑三个人及以上的问题
|
|
func (g *GCGGame) GetOtherController(controllerId uint32) *GCGController {
|
|
for _, controller := range g.controllerMap {
|
|
if controller.controllerId == controllerId {
|
|
continue
|
|
}
|
|
return controller
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetControllerByUserId 通过玩家Id获取GCGController对象
|
|
func (g *GCGGame) GetControllerByUserId(userId uint32) *GCGController {
|
|
for _, controller := range g.controllerMap {
|
|
// 为nil说明该操控者不是玩家
|
|
if controller.player == nil {
|
|
continue
|
|
}
|
|
if controller.player.PlayerID == userId {
|
|
return controller
|
|
}
|
|
}
|
|
return nil
|
|
}
|