package gamelogic import ( "encoding/json" "fmt" "math/rand" "strconv" "time" "bet24.com/servers/games/baloot/config" "bet24.com/servers/insecureframe/frame" "bet24.com/servers/insecureframe/gate" ladder "bet24.com/servers/micros/ladderservice/proto" waterpool "bet24.com/servers/micros/waterpool/proto" "bet24.com/utils" "github.com/google/uuid" ) type tablesink struct { table frame.Table gameScene *GameScene simulator *simulatorScene roomInfo config.RoomInfo privateData string logic *cardlogic LastOpraTime time.Time //记录操作时间点 uniqueId string // 唯一标识 roomType string // "","PrivateRoom","Match" surrenderInfo *SurrenderInfo // 投降消息 allPassCount int } func newTableSink(table frame.Table, data string) *tablesink { ts := new(tablesink) ts.table = table ts.privateData = data ts.logic = newCardLogic() found := false err := json.Unmarshal([]byte(data), &ts.roomInfo) if err != nil { for _, v := range config.Rooms.Rooms { if data == v.RoomName { ts.roomInfo = v found = true break } } if !found { ts.roomInfo = config.NewUserRoom.RoomInfo found = true } } else { found = true } if !found { ts.roomInfo = config.NewUserRoom.RoomInfo } ts.uniqueId = uuid.New().String() ts.allPassCount = 0 ts.gameScene = newGameScene(table.GetTableID(), ts.roomInfo.ScoreToWin, ts.roomInfo.MaxSurrenderCount) ts.surrenderInfo = newSurrenderInfo() return ts } func (ts *tablesink) Destroy() { ts.table.LogWithTableId("------tablesink: Destroy-------") } func (ts *tablesink) OnGameMessage(userIndex int32, msg, data string) bool { switch msg { case CMD_TABLECHAT: ts.recvChatMsg(userIndex, data) case CMD_CANCLE_AUTO: ts.recvCancleAutoMsg(userIndex, data) case CMD_AUTO: ts.recvAutoMsg(userIndex, data) case CMD_ACTION: return ts.recvAction(userIndex, data) case CMD_SYNCDATA: return ts.recvSyncData(userIndex, data) case CMD_SURRENDER: return ts.recvSurrender(userIndex, data) case CMD_SURRENDER_RESULT: return ts.recvSurrenderResult(userIndex, data) default: ts.table.LogWithTableId("tablesink.OnGameMessage %s\n%s", msg, data) return false } return true } func (ts *tablesink) OnUserEnterTable(userIndex int32, chairId int) { usr := gate.GetUserInfo(userIndex) if usr == nil { ts.table.LogWithTableId("tablesink.OnUserEnterTable user not exist") return } ts.table.LogWithTableId("tablesink.OnUserEnterTable chair[%d]: %d:%s ", chairId, usr.GetUserId(), usr.GetUserNickName()) //下发房间配置 d, _ := json.Marshal(ts.roomInfo.RoomInfoBase) ts.table.SendGameData(userIndex, CMD_ROOMINFO, string(d)) ts.table.SetTimer(TIMER_READY_0+chairId, SEC_READY) //有玩家进桌, 更新在线 go func() { frame.UpdateRoomOnline(ts.roomInfo.RoomName, ts.roomInfo.RoomID-1) }() ts.gameScene.Players[chairId].isEndToStart = false ts.gameScene.Players[chairId].userID = usr.GetUserId() if usr.IsRobot() { ts.table.SetTimer(TIMER_READY_0+chairId, 100) } // 如果比赛场,可以查询玩家当前分数、底分和局数 if ts.table.GetOwner() == -1 { ts.table.LogWithTableId("userScore:%d,baseScore:%d,setCount:%d", usr.GetScore(), usr.GetBaseScore(), usr.GetSetCount()) ts.gameScene.Players[chairId].MatchScore = usr.GetScore() ts.gameScene.Players[chairId].IsValid = true } if config.Server.IsLadderRoom > 0 { data := ladder.GetUserLadderInfo(usr.GetUserId(), GAMEID) if data != nil { ts.gameScene.Players[chairId].LadderInfo = *data ts.gameScene.Players[chairId].LastWinCount = ladder.GetUserConsecutiveWinCount(usr.GetUserId(), GAMEID) info := ts.gameScene.getPlayerLadderInfo() ts.table.SendGameData(-1, CMD_LADDERINFO, info) } else { ts.table.LogWithTableId("User:%d, LadderInfo is nil", usr.GetUserId()) } } if !usr.IsRobot() && ts.table.GetOwner() <= 0 { ts.table.NotifySceneChanged(chairId) } if usr.IsRobot() { ts.gameScene.Players[chairId].robotType = rand.Intn(3) friendId := ts.gameScene.Players[getFriendChair(chairId)].userID if friendId != 0 { friend := ts.table.GetPlayerByUserId(friendId) if friend != nil { ts.gameScene.Players[chairId].robotType = ts.gameScene.Players[getFriendChair(chairId)].robotType } } ts.gameScene.Players[chairId].robotActionProb = 100 - 50*ts.gameScene.Players[chairId].robotType ts.gameScene.Players[chairId].robotType = RobotType_Cautious ts.gameScene.Players[chairId].robotActionProb = 100 } } func (ts *tablesink) OnUserExitTable(userIndex int32, chairId int) { usr := ts.table.GetUserByChair(chairId) if usr == nil { ts.table.LogWithTableId("tablesink.OnUserExitTable user not exist") return } ts.table.LogWithTableId("tablesink.OnUserExitTable chair[%d]: %d:%s", chairId, usr.GetUserId(), usr.GetUserNickName()) ts.gameScene.Players[chairId].isEndToStart = false //有玩家离开, 更新在线 go func() { frame.UpdateRoomOnline(ts.roomInfo.RoomName, ts.roomInfo.RoomID-1) }() if ts.gameScene.Phase == Phase_Free || ts.gameScene.Phase == Phase_End { ts.table.KillTimer(TIMER_READY_0 + chairId) if ts.gameScene.Phase != Phase_End && !usr.IsRobot() { ts.table.SetTimer(TIMER_ADD_ROBOT, 500) } go ts.checkAndStartGame() } else { // 没有参与游戏? p := &ts.gameScene.Players[chairId] if !p.IsValid { return } if ts.table.IsPrivate() { return } //游戏中离开,逃跑 p.IsValid = false ts.writeScore(p.userID, p.EndScore, 0, 0, ScoreType_Flee, ts.roomInfo.RoomName, p.isRobot) go ts.table.WriteBetRecordWithSetcount(usr.GetUserId(), ts.gameScene.Players[chairId].bet, 0, 1.0, "fleeGold", "flee", ts.roomInfo.RoomName, 1) for i := 0; i < CHAIR_COUNT; i++ { p := &ts.gameScene.Players[i] if !p.IsValid { continue } p.EndScore = p.bet ts.writeScore(p.userID, p.bet, 0, 0, ScoreType_Return, ts.roomInfo.RoomName, p.isRobot) } ts.gameScene.Phase = Phase_End ts.endGame() ts.table.NotifySceneChanged(-1) ts.uniqueId = uuid.New().String() ts.gameScene.initData(ts.table.GetTableID(), ts.roomInfo.ScoreToWin, ts.roomInfo.MaxSurrenderCount) } } func (ts *tablesink) OnUserOffline(chairId int) { usr := ts.table.GetUserByChair(chairId) if usr == nil { ts.table.LogWithTableId("tablesink.OnUserOffline user not exist") return } ts.table.LogWithTableId("tablesink.OnUserOffline %d:%s", usr.GetUserId(), usr.GetUserNickName()) } func (ts *tablesink) OnUserReplay(chairId int) { usr := ts.table.GetUserByChair(chairId) if usr == nil { ts.table.LogWithTableId("tablesink.OnUserOffline user not exist") return } ts.table.LogWithTableId("tablesink.OnUserReplay %d:%s", usr.GetUserId(), usr.GetUserNickName()) //下发房间配置 d, _ := json.Marshal(ts.roomInfo.RoomInfoBase) ts.table.SendGameData(usr.GetUserIndex(), CMD_ROOMINFO, string(d)) ts.gameScene.Players[chairId].AutoOut = false if ts.surrenderInfo.canDoSurrender(chairId) { userIndex := ts.table.GetUserByChair(chairId).GetUserIndex() ts.table.SendGameData(userIndex, CMD_SURRENDER_RESULT, ts.surrenderInfo.getSurrenderInfo()) } } func (ts *tablesink) OnUserReady(userIndex int32, chairId int) { defer utils.TimeCost(fmt.Sprintf("tablesink.OnUserReady %d", userIndex))() usr := gate.GetUserInfo(userIndex) if usr == nil { ts.table.LogWithTableId("tablesink.OnUserReady user not exist") return } userGold := ts.table.GetUserChipOrGoldByUser(usr) if userGold < ts.roomInfo.MinGold || (ts.roomInfo.MaxGold > 0 && userGold > ts.roomInfo.MaxGold) { ts.table.LogWithTableId("tablesink.OnUserReady %d 金币不足,站起", usr.GetUserId()) if usr.IsRobot() { ts.table.KickUser(usr.GetUserIndex(), false) } else { ts.table.UserWatch(usr.GetUserIndex()) } return } ts.table.LogWithTableId("tablesink.OnUserReady chair[%d]: %d:%s", chairId, usr.GetUserId(), usr.GetUserNickName()) ts.table.KillTimer(TIMER_READY_0 + chairId) if ts.gameScene.Phase != Phase_GameEnd || ts.gameScene.Players[chairId].isEndToStart { ts.table.SetTimer(TIMER_ADD_ROBOT, 500) } if !usr.IsRobot() && ts.gameScene.Players[chairId].isEndToStart { if config.Server.IsLadderRoom > 0 { data := ladder.GetUserLadderInfo(usr.GetUserId(), GAMEID) if data != nil { ts.gameScene.Players[chairId].LadderInfo = *data info := ts.gameScene.getPlayerLadderInfo() ts.table.SendGameData(-1, CMD_LADDERINFO, info) } else { ts.table.LogWithTableId("User:%d, LadderInfo is nil", usr.GetUserId()) } } ts.table.NotifySceneChanged(chairId) } ts.checkAndStartGame() } func (ts *tablesink) OnUserCancelReady(userIndex int32, chairId int) { usr := gate.GetUserInfo(userIndex) if usr == nil { ts.table.LogWithTableId("tablesink.OnUserCancelReady user not exist") return } ts.table.LogWithTableId("tablesink.OnUserCancelReady %d:%s", usr.GetUserId(), usr.GetUserNickName()) } func (ts *tablesink) OnGetChairScene(chairId int, isPlayer bool) string { now := time.Now() ts.gameScene.LeftSec = ts.getSecond(ts.gameScene.Phase)/1000 - int(now.Sub(ts.LastOpraTime).Seconds()) return ts.gameScene.getScene(chairId, isPlayer, false) } func (ts *tablesink) OnGetPrivateRoomScene(chairId int) string { now := time.Now() ts.gameScene.LeftSec = ts.getSecond(ts.gameScene.Phase)/1000 - int(now.Sub(ts.LastOpraTime).Seconds()) str := ts.gameScene.getScene(chairId, true, true) return str } func (ts *tablesink) OnGetChairCount() int { return CHAIR_COUNT } func (ts *tablesink) OnTimer(timerId int) { switch timerId { case TIMER_READY_0: fallthrough case TIMER_READY_1: fallthrough case TIMER_READY_2: fallthrough case TIMER_READY_3: ts.checkUserReadyStatus(timerId - TIMER_READY_0) case TIMER_GAME: ts.dealGameTimeOut() case TIMER_REMOVE_ROBOT: ts.removeOneRobot() case TIMER_ADD_ROBOT: ts.checkIsNeedRobot() case TIMER_SEND_LEFT_CARD: ts.sendLeftCard() case TIMER_START_OUT_CARD: ts.onPlayerFirstOutCard() case TIMER_NEWROUND: ts.onTimerNewRound() case TIMER_ROBOT_ACTION_0: fallthrough case TIMER_ROBOT_ACTION_1: fallthrough case TIMER_ROBOT_ACTION_2: fallthrough case TIMER_ROBOT_ACTION_3: ts.onTimerRobotAction(timerId - TIMER_ROBOT_ACTION_0) case TIMER_AUTO_ACTION_0: fallthrough case TIMER_AUTO_ACTION_1: fallthrough case TIMER_AUTO_ACTION_2: fallthrough case TIMER_AUTO_ACTION_3: ts.onTimerAutoAction(timerId - TIMER_AUTO_ACTION_0) case TIMER_ALL_PASS: ts.onTimerBuyFailed() case TIMER_BUY_CHANGE: ts.gameScene.Index++ ts.table.NotifySceneChanged(-1) case TIMER_DOUBLE_CHANGE: ts.gameScene.initAllPlayerLastAction() ts.gameScene.Index++ ts.table.NotifySceneChanged(-1) ts.resetGameTimer() case TIMER_DELAY_END: ts.table.EndGame() case TIMER_START_GAME: ts.checkStartGame() case TIMER_SAWA: ts.onTimerSawa() case TIMER_CORRECTFINISH: ts.onTimerCorrectFinish() case TIMER_CORRECTDELAY: // 轮次结束也要清理收牌信息 ts.gameScene.newOutCardRound() // 进入SetEnd阶段 ts.enterGameEndPhase(true) case TIMER_SURRENDER: index := ts.table.GetUserByChair(getFriendChair(ts.surrenderInfo.WhoseSurrender)).GetUserIndex() data := Surrender_Failed ts.recvSurrenderResult(index, fmt.Sprintf("%d", data)) case TIMER_ROBOT_SURRENDER: index := ts.table.GetUserByChair(getFriendChair(ts.surrenderInfo.WhoseSurrender)).GetUserIndex() data := Surrender_Success ts.recvSurrenderResult(index, fmt.Sprintf("%d", data)) case TIMER_ROBOT_REPLY: start := rand.Intn(4) for i := 0; i < CHAIR_COUNT; i++ { c := (start + i) % CHAIR_COUNT r := rand.Intn(100) if r <= 60 && ts.gameScene.Players[c].isRobot { ts.sendRobotChatAction(RobotChatAction_Reply, ts.gameScene.Players[c].userID, -1, 0) break } } case TIMER_ROBOT_SEND_CHAT_0: fallthrough case TIMER_ROBOT_SEND_CHAT_1: fallthrough case TIMER_ROBOT_SEND_CHAT_2: fallthrough case TIMER_ROBOT_SEND_CHAT_3: chairId := timerId - TIMER_ROBOT_SEND_CHAT_0 if ts.gameScene.Players[chairId].outTimeCount >= 2 { return } if ts.gameScene.WhoseTurn == chairId { start := rand.Intn(4) for i := 0; i < CHAIR_COUNT; i++ { c := (start + i) % CHAIR_COUNT if c == chairId { continue } if ts.gameScene.Players[c].isRobot { if ts.gameScene.Players[chairId].outTimeCount == 1 { ts.sendRobotChatAction(RobotChatAction_MuiltyTimeOut, ts.gameScene.Players[c].userID, ts.gameScene.Players[chairId].userID, 0) } break } } ts.gameScene.Players[chairId].outTimeCount++ } } } func (ts *tablesink) checkStartGame() { if !ts.canStartGame(false) { if ts.table.GetOwner() <= 0 { ts.table.NotifySceneChanged(-1) } return } start := rand.Intn(4) for i := 0; i < CHAIR_COUNT; i++ { c := (start + i) % CHAIR_COUNT r := rand.Intn(100) if r <= 30 && ts.gameScene.Players[c].isRobot { ts.sendRobotChatAction(RobotChatAction_EnterRoom, ts.gameScene.Players[c].userID, -1, 0) ts.table.SetTimer(TIMER_ROBOT_REPLY, 1500) break } } ts.gameScene.setNextBanker() ts.gameScene.gameInit(getPreviousChair(ts.gameScene.Banker)) controlType := ts.checkNeedControlPlayer() if controlType <= waterpool.PoolControl_Normal { ts.checkNeedControlRobot() } if !ts.table.IsPrivate() { ts.gameScene.initMaxDoubling(ts.roomInfo.IsDoublingMode) } if ts.roomInfo.RoomID == 0 && !ts.table.IsPrivate() { for i := 0; i < CHAIR_COUNT; i++ { usr := ts.table.GetUserByChair(i) if usr == nil { continue } if !usr.IsRobot() { ts.gameScene.Banker = getNextChair(i) ts.gameScene.WhoseTurn = i ts.gameScene.FirstActionChair = i break } } } ts.gameStart() ts.table.StartGame() if ts.roomInfo.IsDoublingMode { if getCardValue(ts.gameScene.PublicCard) == CardValueJ { ts.addDoublingData(Doubling_PublicCard_J) ts.sendShowDoublingMsg([]int{Doubling_PublicCard_J}) } } ts.table.LogWithTableId("tablesink.startGame[%d]", ts.table.GetTableID()) } func (ts *tablesink) DumpScene() { ts.gameScene.dump(true) } func (ts *tablesink) GetGoldLimit() (min, max int) { return ts.roomInfo.MinGold, ts.roomInfo.MaxGold } func (ts *tablesink) IsDual() bool { return ts.roomInfo.IsDual > 0 } func (ts *tablesink) OnBaseScoreChanged(baseScore int) { ts.roomInfo.BaseScore = baseScore d, _ := json.Marshal(ts.roomInfo.RoomInfoBase) ts.table.SendGameData(-1, CMD_ROOMINFO, string(d)) } func (ts *tablesink) SetPrivateRoomParam(param int, value string) { ts.table.LogWithTableId("tablesink.SetPrivateRoomParam %d:%s", param, value) switch param { case frame.Param_Target: t, err := strconv.Atoi(value) if err == nil { ts.roomInfo.ScoreToWin = t ts.uniqueId = uuid.New().String() ts.gameScene.initData(ts.table.GetTableID(), ts.roomInfo.ScoreToWin, ts.roomInfo.MaxSurrenderCount) } case frame.Param_PlayTimeout: t, err := strconv.Atoi(value) if err == nil { ts.roomInfo.SecPlay = t } } } func (ts *tablesink) OnPrivateRoomStatusChanged(oldStatus, newStatus int) { ts.table.LogWithTableId("OnPrivateRoomStatusChanged %d->%d", oldStatus, newStatus) ts.roomType = ts.table.PrivateRoomGetRoomType() ts.table.LogWithTableId("tablesink.OnPrivateRoomStatusChanged roomType:%s", ts.roomType) } func (ts *tablesink) OnPrivateRoomDismissed() { ts.table.LogWithTableId("OnPrivateRoomDismissed ") } func (ts *tablesink) IsAllRobot() bool { bExist := false for i := 0; i < CHAIR_COUNT; i++ { usr := ts.table.GetUserByChair(i) if usr == nil { continue } bExist = true if !usr.IsRobot() { return false } } return bExist }