mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 16:02:26 +08:00
GCG流程至投掷骰子
This commit is contained in:
@@ -21,6 +21,7 @@ type GameDataConfig struct {
|
||||
AvatarSkillDataMap map[int32]*AvatarSkillData // 角色技能
|
||||
AvatarSkillDepotDataMap map[int32]*AvatarSkillDepotData // 角色技能库
|
||||
DropGroupDataMap map[int32]*DropGroupData // 掉落组
|
||||
GCGCharDataMap map[int32]*GCGCharData // 角色卡牌
|
||||
}
|
||||
|
||||
func InitGameDataConfig() {
|
||||
@@ -62,6 +63,7 @@ func (g *GameDataConfig) load() {
|
||||
g.loadAvatarSkillData() // 角色技能
|
||||
g.loadAvatarSkillDepotData() // 角色技能库
|
||||
g.loadDropGroupData() // 掉落组
|
||||
g.loadGCGCharData() // 角色卡牌
|
||||
}
|
||||
|
||||
func (g *GameDataConfig) readCsvFileData(fileName string) []byte {
|
||||
|
||||
75
gdconf/game_data_config/csv/GCGCharData.csv
Normal file
75
gdconf/game_data_config/csv/GCGCharData.csv
Normal file
@@ -0,0 +1,75 @@
|
||||
CharId,,TagId1,TagId2,TagId3,TagId4,TagId5,,,,,SkillListStr,,HPBase,MaxElemVal,,
|
||||
int32,,int32,int32,int32,int32,int32,,,,,string,,int32,int32,,
|
||||
ID,卡牌类型,[卡牌标签列表]1,[卡牌标签列表]2,[卡牌标签列表]3,[卡牌标签列表]4,[卡牌标签列表]5,[卡牌变量]1类型,[卡牌变量]1值,[卡牌变量]2类型,[卡牌变量]2值,卡牌技能列表,可进构筑,角色生命值,角色充能上限,最大行动意图数,死亡后移出游戏
|
||||
1001,1,303,503,502,201,,,,,,80,,50,1,1,
|
||||
1002,1,301,503,502,204,,,,,,80,,50,1,1,1
|
||||
1003,1,303,503,502,201,,,,,,80#1130211,,50,1,1,
|
||||
1101,1,301,204,402,,,16,0,,,11011# 11012# 11013# 11014,1,10,2,2,
|
||||
1102,1,301,204,401,,,,,,,11021# 11022# 11023,1,10,3,2,
|
||||
1103,1,301,201,401,,,,,,,11031# 11032# 11033,1,10,2,2,
|
||||
1104,1,301,203,402,,,,,,,11041# 11042# 11043,1,10,3,2,
|
||||
1105,1,301,201,403,,,,,,,11051# 11052# 11053# 11054,1,10,3,2,
|
||||
1201,1,302,202,401,,,,,,,12011# 12012# 12013,1,10,3,2,
|
||||
1202,1,302,201,402,,,,,,,12021# 12022# 12023,1,10,2,2,
|
||||
1203,1,302,202,401,,,,,,,12031# 12032# 12033# 12034,1,10,3,2,
|
||||
1301,1,303,203,401,,,,,,,13011# 13012# 13013,1,10,3,2,
|
||||
1302,1,303,205,402,,,,,,,13021# 13022# 13023,1,10,2,2,
|
||||
1303,1,303,201,401,,,,,,,13031# 13032# 13033,1,10,2,2,
|
||||
1305,1,303,204,403,,,,,,,13051# 13052# 13053,1,10,2,2,
|
||||
1401,1,304,204,401,,,,,,,14011# 14012# 14013,1,10,3,2,
|
||||
1402,1,304,203,401,,,,,,,14021# 14022# 14023,1,10,3,2,
|
||||
1403,1,304,201,402,,,,,,,14031# 14032# 14033,1,10,3,2,
|
||||
1404,1,304,205,404,,,,,,,14041# 14042# 14043# 14044,1,10,2,2,
|
||||
1501,1,307,202,401,,,,,,,15011# 15012# 15013,1,10,2,2,
|
||||
1502,1,307,201,401,,,,,,,15021# 15022# 15023,1,10,3,2,
|
||||
1601,1,305,202,402,,,,,,,16011# 16012# 16013,1,10,3,2,
|
||||
1602,1,305,203,401,,,,,,,16021# 16022# 16023,1,10,2,2,
|
||||
1701,1,306,204,404,,,,,,,17011# 17012# 17013,1,10,2,2,
|
||||
2201,1,302,200,503,,,,,,,22011# 22012# 22013# 22014,1,10,3,2,
|
||||
2202,1,302,200,501,,,,,,,22021# 22022# 22023,1,10,2,2,
|
||||
2301,1,303,200,501,,,,,,,23011# 23012# 23013# 23014,1,10,2,2,
|
||||
2501,1,307,200,503,,,,,,,25011# 25012# 25013# 25014,1,10,3,2,
|
||||
2601,1,305,200,503,502,,,,,,26011# 26012# 26013# 26014,1,8,2,2,
|
||||
2701,1,306,200,503,,,,,,,27011# 27012# 27013# 27014,1,10,2,2,
|
||||
3001,1,300,503,502,,,,,,,30011# 30012# 30013,,4,2,1,1
|
||||
3002,1,300,503,502,,,,,,,30021# 30022# 30023,,3,2,1,1
|
||||
3003,1,300,504,,,,,,,,30031# 30032# 30033# 30034# 30035# 30036,,6,2,1,1
|
||||
3101,1,301,503,502,,,,,,,31011# 31012# 31013# 31014# 31015,,8,2,2,1
|
||||
3102,1,301,503,502,,,,,,,31021# 31022# 31023,,3,2,1,1
|
||||
3103,1,301,503,,,,,,,,31031# 31032# 31033# 31034# 31035,,4,2,2,1
|
||||
3201,1,302,503,,,,,,,,32011# 32012# 32013# 32014# 32015,,4,3,2,1
|
||||
3202,1,302,503,502,,,,,,,32021# 32022# 32023,,4,2,2,1
|
||||
3203,1,302,501,,,,,,,,32031# 32032# 32033# 32034# 32035,,10,3,2,1
|
||||
3204,1,302,503,,,,,,,,32041# 32042# 32043,,4,2,1,1
|
||||
3301,1,303,503,,,,,,,,33011# 33012# 33013# 33014# 33015,,4,3,2,1
|
||||
3302,1,303,503,502,,,,,,,33021# 33022# 33023# 33024,,8,2,2,1
|
||||
3303,1,303,504,,,,,,,,33031# 33032# 33033# 33034# 33035# 33036# 33037,,10,2,2,1
|
||||
3304,1,303,503,502,,,,,,,33041# 33042# 33043,,4,2,1,1
|
||||
3305,1,303,504,,,,,,,,33051# 33052# 30033# 30034# 30035# 30036,,6,2,1,1
|
||||
3401,1,304,504,,,,,,,,34011# 34012# 34013# 34014# 34015# 34016# 34017,,10,2,2,1
|
||||
3402,1,304,503,502,,,,,,,34021# 34022# 34023,,3,2,1,1
|
||||
3403,1,304,503,502,,,,,,,34031# 34032# 34033# 34034,,8,2,2,1
|
||||
3405,1,304,504,,,,,,,,34051# 34052# 30033# 30034# 30035# 30036,,6,2,1,1
|
||||
3406,1,304,503,,,,,,,,34061# 34062# 34063,,4,2,1,1
|
||||
3501,1,307,503,502,,,,,,,35011# 35012# 35013,,4,2,2,1
|
||||
3502,1,307,501,,,,,,,,35021# 35022# 35023# 35024# 35025,,10,2,2,1
|
||||
3701,1,306,503,,,,,,,,37011# 37012# 37013# 37014,,6,2,2,1
|
||||
3703,1,306,503,502,,,,,,,37031# 37032# 37033,,4,2,1,1
|
||||
4601,1,305,200,503,502,,,,,,26011# 26012 # 26013,,12,2,2,1
|
||||
4602,1,305,200,503,502,,,,,,26011# 26012 # 26013# 26014,,16,2,3,1
|
||||
4603,1,305,200,503,502,,,,,,26011# 26012 # 26013# 26014,,24,2,3,1
|
||||
4604,1,305,200,503,502,,,,,,26011# 26012 # 26013# 26014,,8,2,2,1
|
||||
4201,1,302,200,503,,,,,,,22011# 22012 # 22013# 22014# 32043,,30,3,4,1
|
||||
4202,1,302,200,503,,,,,,,22011# 22012 # 22013# 22014# 32043,,45,3,4,1
|
||||
4203,1,302,200,501,,,,,,,22021# 22022 # 22023,,10,2,3,1
|
||||
4204,1,302,200,501,,,,,,,22021# 22022 # 22023,,10,2,2,1
|
||||
4301,1,303,200,501,,,,,,,23011# 23012 # 23013# 23014,,10,2,3,1
|
||||
4302,1,303,200,501,,,,,,,23011# 23012 # 23013# 23014,,10,2,2,1
|
||||
4501,1,307,200,503,,,,,,,25011# 25012 # 25013# 25014,,20,3,2,1
|
||||
4502,1,307,200,503,,,,,,,25011# 25012 # 25013# 25014,,28,3,2,1
|
||||
4701,1,306,200,503,,,,,,,27011# 27012 # 27013# 27014,,36,2,4,1
|
||||
4702,1,306,200,503,,,,,,,27011# 27012 # 27013# 27014,,48,2,4,1
|
||||
4703,1,306,200,503,,,,,,,27011# 27012 # 27013# 27014,,10,2,2,1
|
||||
4704,1,306,200,503,,,,,,,27011# 27012 # 27013# 27014,,30,2,3,1
|
||||
5201,1,302,503,,,,,,,,32011# 32012# 32013# 32014# 32015# 32016,,4,3,2,1
|
||||
5301,1,303,503,,,,,,,,33011# 33012# 33013# 33014# 33015# 33016,,4,3,2,1
|
||||
|
66
gdconf/gcg_char_data.go
Normal file
66
gdconf/gcg_char_data.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package gdconf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hk4e/pkg/logger"
|
||||
|
||||
"github.com/jszwec/csvutil"
|
||||
)
|
||||
|
||||
// 角色卡牌配置表
|
||||
|
||||
type GCGCharData struct {
|
||||
CharId int32 `csv:"CharId"` // ID
|
||||
TagId1 int32 `csv:"TagId1,omitempty"` // 卡牌标签列表1
|
||||
TagId2 int32 `csv:"TagId2,omitempty"` // 卡牌标签列表2
|
||||
TagId3 int32 `csv:"TagId3,omitempty"` // 卡牌标签列表3
|
||||
TagId4 int32 `csv:"TagId4,omitempty"` // 卡牌标签列表4
|
||||
TagId5 int32 `csv:"TagId5,omitempty"` // 卡牌标签列表5
|
||||
SkillListStr string `csv:"SkillListStr,omitempty"` // 卡牌技能列表文本
|
||||
HPBase int32 `csv:"HPBase,omitempty"` // 角色生命值
|
||||
MaxElemVal int32 `csv:"MaxElemVal,omitempty"` // 角色充能上限
|
||||
|
||||
TagList []uint32 // 卡牌标签列表
|
||||
SkillList []uint32 // 卡牌技能列表
|
||||
}
|
||||
|
||||
func (g *GameDataConfig) loadGCGCharData() {
|
||||
g.GCGCharDataMap = make(map[int32]*GCGCharData)
|
||||
data := g.readCsvFileData("GCGCharData.csv")
|
||||
var gcgCharDataList []*GCGCharData
|
||||
err := csvutil.Unmarshal(data, &gcgCharDataList)
|
||||
if err != nil {
|
||||
info := fmt.Sprintf("parse file error: %v", err)
|
||||
panic(info)
|
||||
}
|
||||
for _, gcgCharData := range gcgCharDataList {
|
||||
// 将TagId整合进TagList
|
||||
gcgCharData.TagList = make([]uint32, 0, 5)
|
||||
tempTagList := make([]int32, 0, 5)
|
||||
tempTagList = append(tempTagList, gcgCharData.TagId1, gcgCharData.TagId2, gcgCharData.TagId3, gcgCharData.TagId4, gcgCharData.TagId5)
|
||||
for _, tagId := range tempTagList {
|
||||
// 跳过为0的tag
|
||||
if tagId == 0 {
|
||||
continue
|
||||
}
|
||||
gcgCharData.TagList = append(gcgCharData.TagList, uint32(tagId))
|
||||
}
|
||||
// 技能列表读取转换
|
||||
tempSkillList := strings.Split(strings.ReplaceAll(gcgCharData.SkillListStr, " ", ""), "#")
|
||||
gcgCharData.SkillList = make([]uint32, 0, len(tempSkillList))
|
||||
for _, s := range tempSkillList {
|
||||
skillId, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
logger.Error("skill id to i err, %v", err)
|
||||
return
|
||||
}
|
||||
gcgCharData.SkillList = append(gcgCharData.SkillList, uint32(skillId))
|
||||
}
|
||||
// list -> map
|
||||
g.GCGCharDataMap[gcgCharData.CharId] = gcgCharData
|
||||
}
|
||||
logger.Info("GCGCharData count: %v", len(g.GCGCharDataMap))
|
||||
}
|
||||
43
gs/game/gcg_ai.go
Normal file
43
gs/game/gcg_ai.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"hk4e/pkg/logger"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GCGAi struct {
|
||||
game *GCGGame // 所在的游戏
|
||||
controllerId uint32 // 操控者Id
|
||||
}
|
||||
|
||||
// ReceiveGCGMessagePackNotify 接收GCG消息包通知
|
||||
func (g *GCGAi) ReceiveGCGMessagePackNotify(notify *proto.GCGMessagePackNotify) {
|
||||
// 获取玩家的操控者对象
|
||||
gameController := g.game.controllerMap[g.controllerId]
|
||||
if gameController == nil {
|
||||
logger.Error("ai 角色 nil")
|
||||
return
|
||||
}
|
||||
|
||||
for _, pack := range notify.MsgPackList {
|
||||
for _, message := range pack.MsgList {
|
||||
switch message.Message.(type) {
|
||||
case *proto.GCGMessage_PhaseChange:
|
||||
// 阶段改变
|
||||
msg := message.GetPhaseChange()
|
||||
switch msg.AfterPhase {
|
||||
case proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE:
|
||||
logger.Error("请选择你的英雄 hhh")
|
||||
go func() {
|
||||
time.Sleep(1000 * 3)
|
||||
// 默认选第一张牌
|
||||
cardInfo := gameController.cardList[0]
|
||||
// 操控者选择角色牌
|
||||
g.game.ControllerSelectChar(gameController, cardInfo, []uint32{})
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,23 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"hk4e/gdconf"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/pkg/logger"
|
||||
"hk4e/pkg/random"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ControllerType 操控者类型
|
||||
type ControllerType uint8
|
||||
|
||||
const (
|
||||
ControllerType_Player ControllerType = iota // 玩家
|
||||
ControllerType_AI // AI
|
||||
ControllerType_None ControllerType = iota
|
||||
ControllerType_Player // 玩家
|
||||
ControllerType_AI // AI
|
||||
)
|
||||
|
||||
// GCGCardInfo 游戏对局内卡牌
|
||||
@@ -36,12 +42,24 @@ const (
|
||||
|
||||
// GCGController 操控者
|
||||
type GCGController struct {
|
||||
controllerId uint32 // 操控者Id
|
||||
cardMap map[uint32]*GCGCardInfo // 卡牌列表
|
||||
loadState ControllerLoadState // 加载状态
|
||||
controllerType ControllerType // 操控者的类型
|
||||
player *model.Player
|
||||
ai uint32 // 暂时不写
|
||||
controllerId uint32 // 操控者Id
|
||||
cardList []*GCGCardInfo // 卡牌列表
|
||||
loadState ControllerLoadState // 加载状态
|
||||
allow uint32 // 是否允许操控 0 -> 不允许 1 -> 允许
|
||||
selectedCharCard *GCGCardInfo // 选择的角色卡牌
|
||||
controllerType ControllerType // 操控者的类型
|
||||
player *model.Player // 玩家对象
|
||||
ai *GCGAi // AI对象
|
||||
}
|
||||
|
||||
// GetCardByGuid 通过卡牌的Guid获取卡牌
|
||||
func (g *GCGController) GetCardByGuid(cardGuid uint32) *GCGCardInfo {
|
||||
for _, info := range g.cardList {
|
||||
if info.guid == cardGuid {
|
||||
return info
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GCGManager 七圣召唤管理器
|
||||
@@ -63,14 +81,14 @@ func (g *GCGManager) CreateGame(gameId uint32, playerList []*model.Player) *GCGG
|
||||
guid: g.gameGuidCounter,
|
||||
gameId: gameId,
|
||||
roundInfo: &GCGRoundInfo{
|
||||
roundNum: 1, // 默认以第一回合开始
|
||||
allowControllerMap: make(map[uint32]uint32, 0),
|
||||
firstController: 1, // 1号操控者为先手
|
||||
roundNum: 1, // 默认以第一回合开始
|
||||
firstController: 1, // 1号操控者为先手
|
||||
diceSideMap: make(map[uint32][]proto.GCGDiceSideType, 2),
|
||||
},
|
||||
controllerMap: make(map[uint32]*GCGController, 0),
|
||||
controllerMsgPackMap: make(map[uint32][]*proto.GCGMessagePack),
|
||||
historyCardList: make([]*proto.GCGCard, 0, 0),
|
||||
historyMsgPackList: make([]*proto.GCGMessagePack, 0, 0),
|
||||
controllerMap: make(map[uint32]*GCGController, 2),
|
||||
msgPackList: make([]*proto.GCGMessagePack, 0, 10),
|
||||
historyMsgPackList: make([]*proto.GCGMessagePack, 0, 50),
|
||||
historyCardList: make([]*GCGCardInfo, 0, 100),
|
||||
}
|
||||
// 初始化游戏
|
||||
game.InitGame(playerList)
|
||||
@@ -79,20 +97,351 @@ func (g *GCGManager) CreateGame(gameId uint32, playerList []*model.Player) *GCGG
|
||||
return game
|
||||
}
|
||||
|
||||
// GCGMsgPhaseChange GCG消息阶段改变
|
||||
func (g *GCGManager) GCGMsgPhaseChange(game *GCGGame, afterPhase proto.GCGPhaseType) *proto.GCGMessage {
|
||||
gcgMsgPhaseChange := &proto.GCGMsgPhaseChange{
|
||||
BeforePhase: game.roundInfo.phaseType,
|
||||
AfterPhase: afterPhase,
|
||||
AllowControllerMap: make([]*proto.Uint32Pair, 0, len(game.controllerMap)),
|
||||
type GCGGameState uint8
|
||||
|
||||
const (
|
||||
GCGGameState_None GCGGameState = iota
|
||||
GCGGameState_Waiting // 等待玩家加载
|
||||
GCGGameState_Running // 游戏运行中
|
||||
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 阶段开局准备
|
||||
func PhaseStartReady(game *GCGGame) {
|
||||
// 客户端更新操控者
|
||||
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)
|
||||
}
|
||||
|
||||
// PhaseSelectChar 阶段选择角色卡牌
|
||||
func PhaseSelectChar(game *GCGGame) {
|
||||
// 该阶段确保每位玩家都选择了角色
|
||||
for _, controller := range game.controllerMap {
|
||||
if controller.selectedCharCard == nil {
|
||||
// 如果有没选择角色卡牌的则不执行后面
|
||||
return
|
||||
}
|
||||
}
|
||||
// 开始阶段所有玩家允许操作
|
||||
if afterPhase == proto.GCGPhaseType_GCG_PHASE_TYPE_START || afterPhase == proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE || afterPhase == proto.GCGPhaseType_GCG_PHASE_TYPE_MAIN {
|
||||
for controllerId := range game.controllerMap {
|
||||
gcgMsgPhaseChange.AllowControllerMap = append(gcgMsgPhaseChange.AllowControllerMap, &proto.Uint32Pair{
|
||||
Key: controllerId,
|
||||
Value: 1,
|
||||
})
|
||||
// 回合信息
|
||||
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, game.GCGMsgDuelDataChange())
|
||||
// 游戏投掷骰子阶段
|
||||
game.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_DICE)
|
||||
}
|
||||
|
||||
// PhaseRollDice 阶段投掷骰子
|
||||
func 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))
|
||||
diceSideList = append(diceSideList, diceSide)
|
||||
}
|
||||
// 存储该回合玩家的骰子
|
||||
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.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 阶段战斗开始
|
||||
func PhasePreMain(game *GCGGame) {
|
||||
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_TRIGGER_SKILL, game.GCGMsgUseSkill(195, 33024), game.GCGMsgUseSkillEnd(195, 33024))
|
||||
}
|
||||
|
||||
// GCGRoundInfo 游戏对局回合信息
|
||||
type GCGRoundInfo struct {
|
||||
roundNum uint32 // 游戏当前回合数
|
||||
phaseType proto.GCGPhaseType // 现在所处的阶段类型
|
||||
firstController uint32 // 当前回合先手的操控者
|
||||
diceSideMap map[uint32][]proto.GCGDiceSideType // 操控者骰子列表 uint32 -> controllerId
|
||||
}
|
||||
|
||||
// GCGGame 游戏对局
|
||||
type GCGGame struct {
|
||||
guid uint32 // 唯一Id
|
||||
gameId uint32 // 游戏Id
|
||||
gameState GCGGameState // 游戏运行状态
|
||||
gameTick uint32 // 游戏tick
|
||||
serverSeqCounter uint32 // 请求序列生成计数器
|
||||
controllerIdCounter uint32 // 操控者Id生成器
|
||||
cardGuidCounter uint32 // 卡牌guid生成计数器
|
||||
roundInfo *GCGRoundInfo // 游戏回合信息
|
||||
controllerMap map[uint32]*GCGController // 操控者列表 uint32 -> controllerId
|
||||
msgPackList []*proto.GCGMessagePack // 消息包待发送区
|
||||
historyMsgPackList []*proto.GCGMessagePack // 历史消息包列表
|
||||
historyCardList []*GCGCardInfo // 历史卡牌列表
|
||||
}
|
||||
|
||||
// AddPlayer GCG游戏添加玩家
|
||||
func (g *GCGGame) AddPlayer(player *model.Player) {
|
||||
// 创建操控者
|
||||
g.controllerIdCounter++
|
||||
controller := &GCGController{
|
||||
controllerId: g.controllerIdCounter,
|
||||
cardList: make([]*GCGCardInfo, 0, 50),
|
||||
loadState: ControllerLoadState_None,
|
||||
controllerType: ControllerType_Player,
|
||||
player: player,
|
||||
}
|
||||
// 生成卡牌信息
|
||||
g.GiveCharCard(controller, 1301)
|
||||
g.GiveCharCard(controller, 1103)
|
||||
// 记录操控者
|
||||
g.controllerMap[g.controllerIdCounter] = controller
|
||||
player.GCGCurGameGuid = g.guid
|
||||
}
|
||||
|
||||
// AddAI GCG游戏添加AI
|
||||
func (g *GCGGame) AddAI() {
|
||||
// 创建操控者
|
||||
g.controllerIdCounter++
|
||||
controller := &GCGController{
|
||||
controllerId: g.controllerIdCounter,
|
||||
cardList: make([]*GCGCardInfo, 0, 50),
|
||||
loadState: ControllerLoadState_InitFinish,
|
||||
controllerType: ControllerType_AI,
|
||||
ai: &GCGAi{
|
||||
game: g,
|
||||
controllerId: g.controllerIdCounter,
|
||||
},
|
||||
}
|
||||
// 生成卡牌信息
|
||||
g.GiveCharCard(controller, 3001)
|
||||
g.GiveCharCard(controller, 3302)
|
||||
// 记录操控者
|
||||
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 给予操控者角色卡牌
|
||||
func (g *GCGGame) GiveCharCard(controller *GCGController, charId uint32) {
|
||||
// 读取角色卡牌配置表
|
||||
gcgCharConfig, ok := gdconf.CONF.GCGCharDataMap[int32(charId)]
|
||||
if !ok {
|
||||
logger.Error("gcg char config error, charId: %v", charId)
|
||||
return
|
||||
}
|
||||
// 生成卡牌信息
|
||||
g.cardGuidCounter++
|
||||
controller.cardList = append(controller.cardList, &GCGCardInfo{
|
||||
cardId: charId,
|
||||
guid: g.cardGuidCounter,
|
||||
faceType: 0, // 1为金卡
|
||||
tagList: gcgCharConfig.TagList,
|
||||
tokenMap: map[uint32]uint32{
|
||||
1: uint32(gcgCharConfig.HPBase), // 血量
|
||||
2: uint32(gcgCharConfig.HPBase), // 最大血量(不确定)
|
||||
4: 0, // 充能
|
||||
5: uint32(gcgCharConfig.MaxElemVal), // 充能条
|
||||
},
|
||||
skillIdList: gcgCharConfig.SkillList,
|
||||
skillLimitList: []uint32{},
|
||||
isShow: true,
|
||||
})
|
||||
}
|
||||
|
||||
// ControllerSelectChar 操控者选择角色卡牌
|
||||
func (g *GCGGame) ControllerSelectChar(controller *GCGController, cardInfo *GCGCardInfo, costDiceIndexList []uint32) {
|
||||
// 判断选择角色卡牌消耗的点数是否正确
|
||||
if controller.selectedCharCard != nil && len(costDiceIndexList) == 0 {
|
||||
// 首次选择角色牌不消耗点数
|
||||
return
|
||||
}
|
||||
// TODO 消耗骰子点数
|
||||
// 设置角色卡牌
|
||||
controller.selectedCharCard = cardInfo
|
||||
// 设置操控者禁止操作
|
||||
controller.allow = 0
|
||||
// 广播选择的角色卡牌消息包
|
||||
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))
|
||||
}
|
||||
|
||||
// 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: g.serverSeqCounter,
|
||||
}
|
||||
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++
|
||||
}
|
||||
|
||||
// InitGame 初始化GCG游戏
|
||||
func (g *GCGGame) InitGame(playerList []*model.Player) {
|
||||
// 初始化玩家
|
||||
for _, player := range playerList {
|
||||
g.AddPlayer(player)
|
||||
}
|
||||
// 添加AI
|
||||
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
|
||||
}
|
||||
|
||||
// StartGame 开始GCG游戏
|
||||
func (g *GCGGame) StartGame() {
|
||||
// 游戏开始设置所有玩家不允许操作
|
||||
// for _, c := range g.controllerMap {
|
||||
// c.allow = 0
|
||||
// }
|
||||
|
||||
// 游戏状态更改为游戏运行中
|
||||
g.gameState = GCGGameState_Running
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// AddMsgPack 添加GCG消息包至待发送区
|
||||
func (g *GCGGame) AddMsgPack(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)
|
||||
}
|
||||
// 将消息包添加进待发送区
|
||||
g.msgPackList = append(g.msgPackList, pack)
|
||||
}
|
||||
|
||||
// SendAllMsgPack 发送所有待发送区的消息包
|
||||
func (g *GCGGame) SendAllMsgPack(recordOnly bool) {
|
||||
// 不发送空的消息包
|
||||
if len(g.msgPackList) == 0 {
|
||||
return
|
||||
}
|
||||
// 是否仅记录历史消息包
|
||||
if !recordOnly {
|
||||
g.serverSeqCounter++
|
||||
for _, controller := range g.controllerMap {
|
||||
GAME_MANAGER.SendGCGMessagePackNotify(controller, g.serverSeqCounter, g.msgPackList)
|
||||
}
|
||||
}
|
||||
// 记录发送的历史消息包
|
||||
for _, pack := range g.msgPackList {
|
||||
g.historyMsgPackList = append(g.historyMsgPackList, pack)
|
||||
}
|
||||
// 清空待发送区消息包
|
||||
g.msgPackList = make([]*proto.GCGMessagePack, 0, 10)
|
||||
}
|
||||
|
||||
// GCGMsgPhaseChange GCG消息阶段改变
|
||||
func (g *GCGGame) GCGMsgPhaseChange(beforePhase proto.GCGPhaseType, afterPhase proto.GCGPhaseType) *proto.GCGMessage {
|
||||
gcgMsgPhaseChange := &proto.GCGMsgPhaseChange{
|
||||
BeforePhase: beforePhase,
|
||||
AfterPhase: afterPhase,
|
||||
AllowControllerMap: make([]*proto.Uint32Pair, 0, len(g.controllerMap)),
|
||||
}
|
||||
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{
|
||||
@@ -100,13 +449,11 @@ func (g *GCGManager) GCGMsgPhaseChange(game *GCGGame, afterPhase proto.GCGPhaseT
|
||||
PhaseChange: gcgMsgPhaseChange,
|
||||
},
|
||||
}
|
||||
// 修改游戏的阶段状态
|
||||
game.roundInfo.phaseType = afterPhase
|
||||
return gcgMessage
|
||||
}
|
||||
|
||||
// GCGMsgPhaseContinue GCG消息阶段跳过
|
||||
func (g *GCGManager) GCGMsgPhaseContinue() *proto.GCGMessage {
|
||||
func (g *GCGGame) GCGMsgPhaseContinue() *proto.GCGMessage {
|
||||
gcgMsgPhaseContinue := &proto.GCGMsgPhaseContinue{}
|
||||
gcgMessage := &proto.GCGMessage{
|
||||
Message: &proto.GCGMessage_PhaseContinue{
|
||||
@@ -117,16 +464,17 @@ func (g *GCGManager) GCGMsgPhaseContinue() *proto.GCGMessage {
|
||||
}
|
||||
|
||||
// GCGMsgUpdateController GCG消息更新操控者
|
||||
func (g *GCGManager) GCGMsgUpdateController(game *GCGGame) *proto.GCGMessage {
|
||||
func (g *GCGGame) GCGMsgUpdateController() *proto.GCGMessage {
|
||||
gcgMsgUpdateController := &proto.GCGMsgUpdateController{
|
||||
AllowControllerMap: make([]*proto.Uint32Pair, 0, len(game.controllerMap)),
|
||||
AllowControllerMap: make([]*proto.Uint32Pair, 0, len(g.controllerMap)),
|
||||
}
|
||||
// 操控者的允许次数
|
||||
for controllerId, _ := range game.roundInfo.allowControllerMap {
|
||||
gcgMsgUpdateController.AllowControllerMap = append(gcgMsgUpdateController.AllowControllerMap, &proto.Uint32Pair{
|
||||
Key: controllerId,
|
||||
Value: 0,
|
||||
})
|
||||
// 操控者的是否允许操作
|
||||
for _, controller := range g.controllerMap {
|
||||
pair := &proto.Uint32Pair{
|
||||
Key: controller.controllerId,
|
||||
Value: controller.allow,
|
||||
}
|
||||
gcgMsgUpdateController.AllowControllerMap = append(gcgMsgUpdateController.AllowControllerMap, pair)
|
||||
}
|
||||
gcgMessage := &proto.GCGMessage{
|
||||
Message: &proto.GCGMessage_UpdateController{
|
||||
@@ -137,7 +485,7 @@ func (g *GCGManager) GCGMsgUpdateController(game *GCGGame) *proto.GCGMessage {
|
||||
}
|
||||
|
||||
// GCGMsgClientPerform GCG消息客户端执行
|
||||
func (g *GCGManager) GCGMsgClientPerform(performType proto.GCGClientPerformType, paramList []uint32) *proto.GCGMessage {
|
||||
func (g *GCGGame) GCGMsgClientPerform(performType proto.GCGClientPerformType, paramList []uint32) *proto.GCGMessage {
|
||||
gcgMsgClientPerform := &proto.GCGMsgClientPerform{
|
||||
ParamList: paramList,
|
||||
PerformType: performType,
|
||||
@@ -150,278 +498,92 @@ func (g *GCGManager) GCGMsgClientPerform(performType proto.GCGClientPerformType,
|
||||
return gcgMessage
|
||||
}
|
||||
|
||||
// GCGRoundInfo 游戏对局回合信息
|
||||
type GCGRoundInfo struct {
|
||||
roundNum uint32 // 游戏当前回合数
|
||||
phaseType proto.GCGPhaseType // 现在所处的阶段类型
|
||||
allowControllerMap map[uint32]uint32 // 回合内操控者允许的次数
|
||||
firstController uint32 // 当前回合先手的操控者
|
||||
}
|
||||
|
||||
// GCGGame 游戏对局
|
||||
type GCGGame struct {
|
||||
guid uint32 // 唯一Id
|
||||
gameId uint32 // 游戏Id
|
||||
serverSeqCounter uint32 // 请求序列生成计数器
|
||||
controllerIdCounter uint32 // 操控者Id生成器
|
||||
cardGuidCounter uint32 // 卡牌guid生成计数器
|
||||
roundInfo *GCGRoundInfo // 游戏回合信息
|
||||
controllerMap map[uint32]*GCGController // 操控者列表 uint32 -> controllerId
|
||||
controllerMsgPackMap map[uint32][]*proto.GCGMessagePack // 操控者消息包待发送区 0代表全局
|
||||
// TODO 游戏重连
|
||||
historyCardList []*proto.GCGCard // 历史发送的卡牌
|
||||
historyMsgPackList []*proto.GCGMessagePack // 历史发送的消息包
|
||||
}
|
||||
|
||||
// AddPlayer GCG游戏添加玩家
|
||||
func (g *GCGGame) AddPlayer(player *model.Player) {
|
||||
// 创建操控者
|
||||
g.controllerIdCounter++
|
||||
controller := &GCGController{
|
||||
controllerId: g.controllerIdCounter,
|
||||
cardMap: make(map[uint32]*GCGCardInfo, 0),
|
||||
loadState: ControllerLoadState_None,
|
||||
controllerType: ControllerType_Player,
|
||||
player: player,
|
||||
}
|
||||
// 生成卡牌信息
|
||||
g.cardGuidCounter++
|
||||
controller.cardMap[1301] = &GCGCardInfo{
|
||||
cardId: 1301,
|
||||
guid: g.cardGuidCounter,
|
||||
faceType: 0,
|
||||
tagList: []uint32{203, 303, 401},
|
||||
tokenMap: map[uint32]uint32{
|
||||
1: 10,
|
||||
2: 10,
|
||||
4: 0,
|
||||
5: 3,
|
||||
},
|
||||
skillIdList: []uint32{
|
||||
13011,
|
||||
13012,
|
||||
13013,
|
||||
},
|
||||
skillLimitList: []uint32{},
|
||||
isShow: true,
|
||||
}
|
||||
g.cardGuidCounter++
|
||||
controller.cardMap[1103] = &GCGCardInfo{
|
||||
cardId: 1103,
|
||||
guid: g.cardGuidCounter,
|
||||
faceType: 0,
|
||||
tagList: []uint32{201, 301, 401},
|
||||
tokenMap: map[uint32]uint32{
|
||||
1: 10, // 血量
|
||||
2: 10, // 最大血量(不确定)
|
||||
4: 0, // 充能
|
||||
5: 2, // 充能条
|
||||
},
|
||||
skillIdList: []uint32{
|
||||
11031,
|
||||
11032,
|
||||
11033,
|
||||
},
|
||||
skillLimitList: []uint32{},
|
||||
isShow: true,
|
||||
}
|
||||
g.cardGuidCounter++
|
||||
controller.cardMap[3001] = &GCGCardInfo{
|
||||
cardId: 3001,
|
||||
guid: g.cardGuidCounter,
|
||||
faceType: 0,
|
||||
tagList: []uint32{200, 300, 502, 503},
|
||||
tokenMap: map[uint32]uint32{
|
||||
1: 4,
|
||||
2: 4,
|
||||
4: 0,
|
||||
5: 2,
|
||||
},
|
||||
skillIdList: []uint32{
|
||||
30011,
|
||||
30012,
|
||||
30013,
|
||||
},
|
||||
skillLimitList: []uint32{},
|
||||
isShow: true,
|
||||
}
|
||||
// g.cardGuidCounter++
|
||||
// controller.cardMap[1301011] = &GCGCardInfo{
|
||||
// cardId: 1301011,
|
||||
// guid: g.cardGuidCounter,
|
||||
// faceType: 0,
|
||||
// skillIdList: []uint32{
|
||||
// 13010111,
|
||||
// },
|
||||
// skillLimitList: []uint32{},
|
||||
// isShow: true,
|
||||
// }
|
||||
// 记录操控者
|
||||
g.controllerMap[g.controllerIdCounter] = controller
|
||||
player.GCGCurGameGuid = g.guid
|
||||
}
|
||||
|
||||
// AddAI GCG游戏添加AI
|
||||
func (g *GCGGame) AddAI() {
|
||||
// 创建操控者
|
||||
g.controllerIdCounter++
|
||||
controller := &GCGController{
|
||||
controllerId: g.controllerIdCounter,
|
||||
cardMap: make(map[uint32]*GCGCardInfo, 0),
|
||||
loadState: ControllerLoadState_InitFinish,
|
||||
controllerType: ControllerType_AI,
|
||||
ai: 233,
|
||||
}
|
||||
// 生成卡牌信息
|
||||
g.cardGuidCounter++
|
||||
controller.cardMap[3001] = &GCGCardInfo{
|
||||
cardId: 3001,
|
||||
guid: g.cardGuidCounter,
|
||||
faceType: 0,
|
||||
tagList: []uint32{200, 300, 502, 503},
|
||||
tokenMap: map[uint32]uint32{
|
||||
1: 4,
|
||||
2: 4,
|
||||
4: 0,
|
||||
5: 2,
|
||||
},
|
||||
skillIdList: []uint32{
|
||||
30011,
|
||||
30012,
|
||||
30013,
|
||||
},
|
||||
skillLimitList: []uint32{},
|
||||
isShow: true,
|
||||
}
|
||||
g.cardGuidCounter++
|
||||
controller.cardMap[3302] = &GCGCardInfo{
|
||||
cardId: 3302,
|
||||
guid: g.cardGuidCounter,
|
||||
faceType: 0,
|
||||
tagList: []uint32{200, 303, 502, 503},
|
||||
tokenMap: map[uint32]uint32{
|
||||
1: 8,
|
||||
2: 8,
|
||||
4: 0,
|
||||
5: 2,
|
||||
},
|
||||
skillIdList: []uint32{
|
||||
33021,
|
||||
33022,
|
||||
33023,
|
||||
33024,
|
||||
},
|
||||
skillLimitList: []uint32{},
|
||||
isShow: true,
|
||||
}
|
||||
// 记录操控者
|
||||
g.controllerMap[g.controllerIdCounter] = controller
|
||||
}
|
||||
|
||||
// InitGame 初始化GCG游戏
|
||||
func (g *GCGGame) InitGame(playerList []*model.Player) {
|
||||
// 初始化玩家
|
||||
for _, player := range playerList {
|
||||
g.AddPlayer(player)
|
||||
}
|
||||
// 添加AI
|
||||
g.AddAI()
|
||||
|
||||
// 初始化每个操控者的次数
|
||||
for controllerId := range g.controllerMap {
|
||||
g.roundInfo.allowControllerMap[controllerId] = 0
|
||||
}
|
||||
// 先手者操控数为1
|
||||
g.roundInfo.allowControllerMap[g.roundInfo.firstController] = 1
|
||||
|
||||
// TODO 验证玩家人数是否符合
|
||||
// 预开始游戏
|
||||
g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, GCG_MANAGER.GCGMsgPhaseChange(g, proto.GCGPhaseType_GCG_PHASE_TYPE_START), GCG_MANAGER.GCGMsgUpdateController(g))
|
||||
g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_SEND_MESSAGE, GCG_MANAGER.GCGMsgPhaseContinue())
|
||||
g.SendMessagePack(0)
|
||||
// 预开始游戏后 ServerSeq 会跟官服不同 这里重置一下
|
||||
g.serverSeqCounter = 0
|
||||
logger.Error("gcg init")
|
||||
}
|
||||
|
||||
// StartGame 开始GCG游戏
|
||||
func (g *GCGGame) StartGame() {
|
||||
// 开始游戏消息包
|
||||
g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, GCG_MANAGER.GCGMsgUpdateController(g))
|
||||
g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_PHASE_EXIT, GCG_MANAGER.GCGMsgClientPerform(proto.GCGClientPerformType_GCG_CLIENT_PERFORM_TYPE_FIRST_HAND, []uint32{g.roundInfo.firstController}))
|
||||
g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NEXT_PHASE, GCG_MANAGER.GCGMsgPhaseChange(g, proto.GCGPhaseType_GCG_PHASE_TYPE_DRAW))
|
||||
g.AddMessagePack(0, proto.GCGActionType_GCG_ACTION_TYPE_NEXT_PHASE, GCG_MANAGER.GCGMsgPhaseChange(g, proto.GCGPhaseType_GCG_PHASE_TYPE_ON_STAGE))
|
||||
g.SendMessagePack(0)
|
||||
logger.Error("gcg start")
|
||||
}
|
||||
|
||||
// CheckAllInitFinish 检查所有玩家是否加载完成
|
||||
func (g *GCGGame) CheckAllInitFinish() {
|
||||
// 检查所有玩家是否加载完成
|
||||
for _, controller := range g.controllerMap {
|
||||
if controller.loadState != ControllerLoadState_InitFinish {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO 可能会玩家中途退了 超时结束游戏
|
||||
// 正式开始游戏
|
||||
g.StartGame()
|
||||
}
|
||||
|
||||
// AddMessagePack 添加操控者的待发送区GCG消息
|
||||
func (g *GCGGame) AddMessagePack(controllerId uint32, actionType proto.GCGActionType, msgList ...*proto.GCGMessage) {
|
||||
_, ok := g.controllerMsgPackMap[controllerId]
|
||||
if !ok {
|
||||
g.controllerMsgPackMap[controllerId] = make([]*proto.GCGMessagePack, 0, len(msgList)*5)
|
||||
}
|
||||
pack := &proto.GCGMessagePack{
|
||||
ActionType: actionType,
|
||||
MsgList: make([]*proto.GCGMessage, 0, len(msgList)),
|
||||
// GCGMsgSelectOnStage GCG消息切换角色卡牌
|
||||
func (g *GCGGame) GCGMsgSelectOnStage(controllerId uint32, cardGuid uint32, reason proto.GCGReason) *proto.GCGMessage {
|
||||
gcgMsgClientPerform := &proto.GCGMsgSelectOnStage{
|
||||
Reason: reason,
|
||||
ControllerId: controllerId,
|
||||
CardGuid: cardGuid,
|
||||
}
|
||||
// 将每个GCG消息添加进消息包中
|
||||
for _, message := range msgList {
|
||||
pack.MsgList = append(pack.MsgList, message)
|
||||
gcgMessage := &proto.GCGMessage{
|
||||
Message: &proto.GCGMessage_SelectOnStage{
|
||||
SelectOnStage: gcgMsgClientPerform,
|
||||
},
|
||||
}
|
||||
// 将消息包添加进待发送区
|
||||
g.controllerMsgPackMap[controllerId] = append(g.controllerMsgPackMap[controllerId], pack)
|
||||
return gcgMessage
|
||||
}
|
||||
|
||||
// SendMessagePack 发送操控者的待发送区GCG消息
|
||||
func (g *GCGGame) SendMessagePack(controllerId uint32) {
|
||||
msgPackList, ok := g.controllerMsgPackMap[controllerId]
|
||||
if !ok {
|
||||
logger.Error("msg pack list error, controllerId: %v", controllerId)
|
||||
return
|
||||
// GCGMsgPVEIntention GCG消息PVE意向
|
||||
func (g *GCGGame) GCGMsgPVEIntention(pveIntentionList ...*proto.GCGMsgPVEIntention) *proto.GCGMessage {
|
||||
gcgMsgPVEIntention := &proto.GCGMsgPVEIntentionInfo{
|
||||
IntentionMap: make(map[uint32]*proto.GCGMsgPVEIntention),
|
||||
}
|
||||
// 0代表广播给全体玩家
|
||||
if controllerId == 0 {
|
||||
g.serverSeqCounter++
|
||||
for _, controller := range g.controllerMap {
|
||||
GAME_MANAGER.SendGCGMessagePackNotify(controller, g.serverSeqCounter, msgPackList)
|
||||
}
|
||||
} else {
|
||||
// 获取指定的操控者
|
||||
controller, ok := g.controllerMap[controllerId]
|
||||
if !ok {
|
||||
logger.Error("controller is nil, controllerId: %v", controllerId)
|
||||
return
|
||||
}
|
||||
g.serverSeqCounter++
|
||||
GAME_MANAGER.SendGCGMessagePackNotify(controller, g.serverSeqCounter, msgPackList)
|
||||
for _, intention := range pveIntentionList {
|
||||
gcgMsgPVEIntention.IntentionMap[intention.CardGuid] = intention
|
||||
}
|
||||
// 记录发送的历史消息包
|
||||
for _, pack := range msgPackList {
|
||||
g.historyMsgPackList = append(g.historyMsgPackList, pack)
|
||||
gcgMessage := &proto.GCGMessage{
|
||||
Message: &proto.GCGMessage_PveIntentionInfo{
|
||||
PveIntentionInfo: gcgMsgPVEIntention,
|
||||
},
|
||||
}
|
||||
// 清空待发送区的数据
|
||||
g.controllerMsgPackMap[controllerId] = make([]*proto.GCGMessagePack, 0, len(msgPackList))
|
||||
return gcgMessage
|
||||
}
|
||||
|
||||
// // CreateGameCardInfo 生成操控者卡牌信息
|
||||
// func (g *GCGManager) CreateGameCardInfo(controller *GCGController, gcgDeck *model.GCGDeck) *GCGCardInfo {
|
||||
//
|
||||
// }
|
||||
// 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(cardGuid uint32, skillId uint32) *proto.GCGMessage {
|
||||
gcgMsgMsgUseSkill := &proto.GCGMsgUseSkill{
|
||||
SkillId: skillId,
|
||||
CardGuid: cardGuid,
|
||||
}
|
||||
gcgMessage := &proto.GCGMessage{
|
||||
Message: &proto.GCGMessage_UseSkill{
|
||||
UseSkill: gcgMsgMsgUseSkill,
|
||||
},
|
||||
}
|
||||
return gcgMessage
|
||||
}
|
||||
|
||||
// GCGMsgUseSkillEnd GCG消息使用技能结束
|
||||
func (g *GCGGame) GCGMsgUseSkillEnd(cardGuid uint32, skillId uint32) *proto.GCGMessage {
|
||||
gcgMsgMsgUseSkillEnd := &proto.GCGMsgUseSkillEnd{
|
||||
SkillId: skillId,
|
||||
CardGuid: cardGuid,
|
||||
}
|
||||
gcgMessage := &proto.GCGMessage{
|
||||
Message: &proto.GCGMessage_UseSkillEnd{
|
||||
UseSkillEnd: gcgMsgMsgUseSkillEnd,
|
||||
},
|
||||
}
|
||||
return gcgMessage
|
||||
}
|
||||
|
||||
// GetControllerByUserId 通过玩家Id获取GCGController对象
|
||||
func (g *GCGGame) GetControllerByUserId(userId uint32) *GCGController {
|
||||
|
||||
@@ -126,6 +126,7 @@ func (r *RouteManager) initRoute() {
|
||||
r.registerRouter(cmd.GetOnlinePlayerInfoReq, GAME_MANAGER.GetOnlinePlayerInfoReq)
|
||||
r.registerRouter(cmd.GCGAskDuelReq, GAME_MANAGER.GCGAskDuelReq)
|
||||
r.registerRouter(cmd.GCGInitFinishReq, GAME_MANAGER.GCGInitFinishReq)
|
||||
r.registerRouter(cmd.GCGOperationReq, GAME_MANAGER.GCGOperationReq)
|
||||
}
|
||||
|
||||
func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
|
||||
|
||||
@@ -363,6 +363,10 @@ func (t *TickManager) onTickSecond(now int64) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// GCG游戏Tick
|
||||
for _, game := range GCG_MANAGER.gameMap {
|
||||
game.onTick()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TickManager) onTick200MilliSecond(now int64) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package game
|
||||
import (
|
||||
"hk4e/common/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/pkg/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
|
||||
@@ -158,7 +159,7 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
|
||||
// 阶段数据
|
||||
Phase: &proto.GCGPhase{
|
||||
PhaseType: game.roundInfo.phaseType,
|
||||
AllowControllerMap: game.roundInfo.allowControllerMap,
|
||||
AllowControllerMap: make(map[uint32]uint32),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -178,7 +179,7 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
|
||||
playerField := &proto.GCGPlayerField{
|
||||
Unk3300_IKJMGAHCFPM: 0,
|
||||
// 卡牌图片
|
||||
ModifyZoneMap: make(map[uint32]*proto.GCGZone, len(controller.cardMap)),
|
||||
ModifyZoneMap: make(map[uint32]*proto.GCGZone, len(controller.cardList)),
|
||||
Unk3300_GGHKFFADEAL: 0,
|
||||
Unk3300_AOPJIOHMPOF: &proto.GCGZone{
|
||||
CardList: []uint32{},
|
||||
@@ -196,7 +197,7 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
|
||||
ControllerId: controller.controllerId,
|
||||
// 卡牌位置
|
||||
Unk3300_INDJNJJJNKL: &proto.GCGZone{
|
||||
CardList: make([]uint32, 0, len(controller.cardMap)),
|
||||
CardList: make([]uint32, 0, len(controller.cardList)),
|
||||
},
|
||||
Unk3300_EFNAEFBECHD: &proto.GCGZone{
|
||||
CardList: []uint32{},
|
||||
@@ -208,7 +209,7 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
|
||||
Unk3300_GLNIFLOKBPM: 0,
|
||||
}
|
||||
// 卡牌信息
|
||||
for _, info := range controller.cardMap {
|
||||
for _, info := range controller.cardList {
|
||||
gcgCard := &proto.GCGCard{
|
||||
TagList: info.tagList,
|
||||
Guid: info.guid,
|
||||
@@ -239,6 +240,8 @@ func (g *GameManager) GCGAskDuelReq(player *model.Player, payloadMsg pb.Message)
|
||||
// Field
|
||||
playerField.ModifyZoneMap[info.guid] = &proto.GCGZone{CardList: []uint32{}}
|
||||
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)
|
||||
@@ -276,12 +279,68 @@ func (g *GameManager) GCGInitFinishReq(player *model.Player, payloadMsg pb.Messa
|
||||
game.CheckAllInitFinish()
|
||||
}
|
||||
|
||||
// SendGCGMessagePackNotify 发送GCG消息包通知
|
||||
func (g *GameManager) SendGCGMessagePackNotify(controller *GCGController, serverSeq uint32, msgPackList []*proto.GCGMessagePack) {
|
||||
// 确保为玩家
|
||||
if controller.player == nil {
|
||||
// GCGOperationReq GCG游戏客户端操作请求
|
||||
func (g *GameManager) GCGOperationReq(player *model.Player, payloadMsg pb.Message) {
|
||||
req := payloadMsg.(*proto.GCGOperationReq)
|
||||
|
||||
// 获取玩家所在的游戏
|
||||
game, ok := GCG_MANAGER.gameMap[player.GCGCurGameGuid]
|
||||
if !ok {
|
||||
g.CommonRetError(cmd.GCGOperationRsp, player, &proto.GCGOperationRsp{}, proto.Retcode_RET_GCG_GAME_NOT_RUNNING)
|
||||
return
|
||||
}
|
||||
// 获取玩家的操控者对象
|
||||
gameController := game.GetControllerByUserId(player.PlayerID)
|
||||
if gameController == nil {
|
||||
g.CommonRetError(cmd.GCGOperationRsp, player, &proto.GCGOperationRsp{}, proto.Retcode_RET_GCG_NOT_IN_GCG_DUNGEON)
|
||||
return
|
||||
}
|
||||
|
||||
switch req.Op.Op.(type) {
|
||||
case *proto.GCGOperation_OpSelectOnStage:
|
||||
// 选择角色卡牌
|
||||
op := req.Op.GetOpSelectOnStage()
|
||||
// 操作者是否拥有该卡牌
|
||||
cardInfo := gameController.GetCardByGuid(op.CardGuid)
|
||||
if cardInfo == nil {
|
||||
GAME_MANAGER.CommonRetError(cmd.GCGOperationRsp, player, &proto.GCGOperationRsp{}, proto.Retcode_RET_GCG_SELECT_HAND_CARD_GUID_ERROR)
|
||||
return
|
||||
}
|
||||
// 操控者选择角色牌
|
||||
game.ControllerSelectChar(gameController, cardInfo, op.CostDiceIndexList)
|
||||
case *proto.GCGOperation_OpReroll:
|
||||
// 确认骰子不重投
|
||||
op := req.Op.GetOpReroll()
|
||||
diceSideList, ok := game.roundInfo.diceSideMap[gameController.controllerId]
|
||||
if !ok {
|
||||
g.CommonRetError(cmd.GCGOperationRsp, player, &proto.GCGOperationRsp{}, proto.Retcode_RET_GCG_DICE_INDEX_INVALID)
|
||||
return
|
||||
}
|
||||
// 判断骰子索引是否有效
|
||||
for _, diceIndex := range op.DiceIndexList {
|
||||
if diceIndex > uint32(len(diceSideList)) {
|
||||
g.CommonRetError(cmd.GCGOperationRsp, player, &proto.GCGOperationRsp{}, proto.Retcode_RET_GCG_DICE_INDEX_INVALID)
|
||||
return
|
||||
}
|
||||
}
|
||||
// 客户端更新操控者
|
||||
game.AddMsgPack(0, proto.GCGActionType_GCG_ACTION_TYPE_NONE, game.GCGMsgUpdateController())
|
||||
// 游戏行动阶段
|
||||
game.GameChangePhase(proto.GCGPhaseType_GCG_PHASE_TYPE_PRE_MAIN)
|
||||
default:
|
||||
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
|
||||
}
|
||||
|
||||
// PacketGCGOperationRsp
|
||||
gcgOperationRsp := &proto.GCGOperationRsp{
|
||||
OpSeq: req.OpSeq,
|
||||
}
|
||||
GAME_MANAGER.SendMsg(cmd.GCGOperationRsp, player.PlayerID, player.ClientSeq, gcgOperationRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SendGCGMessagePackNotify(controller *GCGController, serverSeq uint32, msgPackList []*proto.GCGMessagePack) {
|
||||
// 确保加载完成
|
||||
if controller.loadState != ControllerLoadState_InitFinish {
|
||||
return
|
||||
@@ -291,7 +350,16 @@ func (g *GameManager) SendGCGMessagePackNotify(controller *GCGController, server
|
||||
ServerSeq: serverSeq,
|
||||
MsgPackList: msgPackList,
|
||||
}
|
||||
GAME_MANAGER.SendMsg(cmd.GCGMessagePackNotify, controller.player.PlayerID, controller.player.ClientSeq, gcgMessagePackNotify)
|
||||
// 根据操控者的类型发送消息包
|
||||
switch controller.controllerType {
|
||||
case ControllerType_Player:
|
||||
GAME_MANAGER.SendMsg(cmd.GCGMessagePackNotify, controller.player.PlayerID, controller.player.ClientSeq, gcgMessagePackNotify)
|
||||
case ControllerType_AI:
|
||||
controller.ai.ReceiveGCGMessagePackNotify(gcgMessagePackNotify)
|
||||
default:
|
||||
logger.Error("controller type error, %v", controller.controllerType)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// PacketGCGGameBriefDataNotify GCG游戏简要数据通知
|
||||
@@ -309,7 +377,7 @@ func (g *GameManager) PacketGCGGameBriefDataNotify(player *model.Player, busines
|
||||
gcgPlayerBriefData := &proto.GCGPlayerBriefData{
|
||||
ControllerId: controller.controllerId,
|
||||
ProfilePicture: new(proto.ProfilePicture),
|
||||
CardIdList: make([]uint32, 0, len(controller.cardMap)),
|
||||
CardIdList: make([]uint32, 0, len(controller.cardList)),
|
||||
}
|
||||
// 玩家信息
|
||||
if controller.player != nil {
|
||||
|
||||
@@ -260,11 +260,14 @@ func (c *CmdProtoMap) registerAllMessage() {
|
||||
c.registerMessage(GCGTCTavernInfoNotify, &proto.GCGTCTavernInfoNotify{}) // GCG酒馆信息通知
|
||||
c.registerMessage(GCGTavernNpcInfoNotify, &proto.GCGTavernNpcInfoNotify{}) // GCG酒馆NPC信息通知
|
||||
c.registerMessage(GCGGameBriefDataNotify, &proto.GCGGameBriefDataNotify{}) // GCG游戏简要数据通知
|
||||
c.registerMessage(GCGAskDuelReq, &proto.GCGAskDuelReq{}) // GCG决斗请求
|
||||
c.registerMessage(GCGAskDuelRsp, &proto.GCGAskDuelRsp{}) // GCG决斗响应
|
||||
c.registerMessage(GCGInitFinishReq, &proto.GCGInitFinishReq{}) // GCG初始化完成请求
|
||||
c.registerMessage(GCGInitFinishRsp, &proto.GCGInitFinishRsp{}) // GCG初始化完成响应
|
||||
c.registerMessage(GCGMessagePackNotify, &proto.GCGMessagePackNotify{}) // GCG消息包通知
|
||||
c.registerMessage(GCGAskDuelReq, &proto.GCGAskDuelReq{}) // GCG游戏对局信息请求
|
||||
c.registerMessage(GCGAskDuelRsp, &proto.GCGAskDuelRsp{}) // GCG游戏对局信息响应
|
||||
c.registerMessage(GCGInitFinishReq, &proto.GCGInitFinishReq{}) // GCG游戏初始化完成请求
|
||||
c.registerMessage(GCGInitFinishRsp, &proto.GCGInitFinishRsp{}) // GCG游戏初始化完成响应
|
||||
c.registerMessage(GCGMessagePackNotify, &proto.GCGMessagePackNotify{}) // GCG游戏消息包通知
|
||||
c.registerMessage(GCGHeartBeatNotify, &proto.GCGHeartBeatNotify{}) // GCG游戏心跳包通知
|
||||
c.registerMessage(GCGOperationReq, &proto.GCGOperationReq{}) // GCG游戏客户端操作请求
|
||||
c.registerMessage(GCGOperationRsp, &proto.GCGOperationRsp{}) // GCG游戏客户端操作响应
|
||||
|
||||
// // TODO 客户端开始GCG游戏
|
||||
// c.registerMessage(GCGStartChallengeByCheckRewardReq, &proto.GCGStartChallengeByCheckRewardReq{}) // GCG开始挑战来自检测奖励请求
|
||||
|
||||
Reference in New Issue
Block a user