samba/server/cacheta/room/cathetaRoom.go

823 lines
23 KiB
Go
Raw Permalink Normal View History

2025-06-04 09:51:39 +08:00
package room
import (
"errors"
"github.com/google/uuid"
"math/rand"
"samba/pkg/log"
"samba/pkg/servername"
"samba/proto"
"samba/server/cacheta/poker"
. "samba/server/cacheta/service"
. "samba/server/game/baseroom"
. "samba/server/game/player"
"samba/stub"
"samba/util/event"
"samba/util/model"
"samba/util/routingKey"
"samba/util/state"
"samba/util/util"
"time"
)
const (
WaitRealPlayerTimeout = 30 // 30秒等待真人
RandRobotTimeout = 10 // 10秒内随机机器人
)
func NewPlayer(uid int64) (*Player, error) {
p := &Player{UserInfo: &model.UserInfo{UID: uid}}
return p, p.Load()
}
type GameRoom struct {
*BaseRoom[*GameSeat]
*event.Events
pokers poker.IPokerGenerator
pickPokers []*poker.Poker // 摸牌区
outPokers []*poker.Poker // 弃牌区
dealer int // 庄家座位
current int // 当前行动人座位
roundStartPos int // 本轮中最开始的位置,用于比牌
round int // 当前轮
gameStep GameStep // 游戏状态
gameNo string // 本局游戏唯一id
startTime time.Time
endTime time.Time
record *TrucoGameRecord // 战绩玩家查询
gameLog *TrucoGameLog // 游戏操作汇总给后台
smallGameCount int // 记录第几小局
waitSecond int // 记录第一个入座玩家等待了几秒,用于分配机器人
}
func NewGameRoom(id, roomType, clubId int) (IRoom, proto.ErrorCode) {
baseRoom, code := NewBaseRoom[*GameSeat](id, roomType, clubId)
if code != proto.Ok {
return nil, code
}
room := &GameRoom{
BaseRoom: baseRoom,
Events: event.NewEvents(),
pokers: poker.NewCachetaPokers(),
dealer: 0,
current: 0,
round: 0,
gameStep: GsReadyGame,
gameNo: uuid.NewString(),
//record: NewTrucoGameRecord(),
smallGameCount: 0,
}
if room.pokers == nil {
log.Error(room.Log("create room fail.play type:%v", baseRoom.RoomCnf.PlayType))
return nil, proto.Internal
}
room.SetTruthRoom(room)
room.SetTimerHandler(room)
if room.RoomCnf.CathetaInitPoint == 0 {
room.RoomCnf.CathetaInitPoint = 5
}
for i := 0; i < room.RoomCnf.MinPlayers; i++ {
room.Seats = append(room.Seats, &GameSeat{
BaseSeat: NewBaseSeat(i),
pokers: make([]*poker.Poker, 0),
//ActType: AtUnknown,
Point: room.RoomCnf.CathetaInitPoint,
})
}
room.dealer = int(rand.Int31n(int32(len(room.Seats))))
room.current = room.dealer
room.roundStartPos = room.current
if err := CathetaService.QueueBind(QueueName(), routingKey.RoomKey(room.Id()), util.Direct(servername.Cacheta)); err != nil {
log.Error(err.Error())
}
return room, code
}
// 获取金币或者俱乐部币
func (r *GameRoom) getCoin(uid int64) (coins int64) {
op := model.NewUserResourceOp()
coins, _ = op.Get(uid, util.Tie[string](r.ClubId() == 0, model.ResCoins, model.ResClubUserScore))
return coins
}
// 获取金币或者俱乐部币
func (r *GameRoom) getTakeCoin(player *Player) (coins int64) {
return util.Tie(r.ClubId() == 0, player.TakeCoin, player.TakeClubCoin)
}
func (r *GameRoom) addTakeCoin(player *Player, add int64, reason string) {
// holdTakeCoin在多开时是多个房间的总携带不是本房间的携带
if r.ClubId() == 0 {
if holdTakeCoin, ok := model.NewUserResourceOp().AddTakeCoin(player.UID, add); ok {
player.TakeCoin += add
res := &proto.ReqAddResource{
UserId: player.UID,
ResValue: add,
ResType: model.ResTakeCoins,
Reason: reason,
RoomId: r.Id(),
RoomType: r.Type(),
GameNo: r.gameNo,
Desc: "",
IsNotify: true,
}
model.NewResourceRecord(res, holdTakeCoin).Flush(CathetaService)
}
} else {
log.Error(r.Log("club room:%v has not take_club_coin.room_type:%v play_type:%v club:%v ", r.Id(), r.Type(), r.PlayType(), r.ClubId()))
//if holdTakeCoin, ok := model.NewUserResourceOp().AddClubTakeCoin(player.UID, add); ok {
// player.TakeCoin += add
// res := &proto.ReqAddResource{
// UserId: player.UID,
// ResValue: add,
// ResType: model.ResTakeClubCoins,
// Reason: reason,
// RoomId: r.Id(),
// RoomId: r.Type(),
// GetGameNo: r.gameNo,
// Desc: "",
// }
// model.NewResourceRecord(res, holdTakeCoin).Flush(CathetaService)
//}
}
}
func (r *GameRoom) addResource(player *Player, add int64, resType, reason string) {
if resType == model.ResTakeCoins {
r.addTakeCoin(player, add, reason)
} else {
resType = util.Tie[string](r.ClubId() == 0, model.ResCoins, model.ResClubUserScore)
router := routingKey.DbKey(player.UID)
SendMsgToDb(router, player.UID, proto.ReqAddResourceId, &proto.ReqAddResource{
UserId: player.UID,
ResValue: add,
ResType: resType,
Reason: reason,
RoomId: r.Id(),
RoomType: r.Type(),
GameNo: r.gameNo,
Desc: "",
IsNotify: true,
})
}
}
// 大局之前初始化
func (r *GameRoom) ReInit() {
RoomMgr.Add(r)
r.startTime = time.Now()
r.record = NewTrucoGameRecord()
var err error
var playingNum int64
for _, seat := range r.Seats {
if !seat.Empty() && !seat.Player().IsRobot() {
num, err1 := model.AddRoomTypePlayerNum(r.RoomCnf, seat.Player().UID)
if err1 != nil {
err = errors.Join(err1)
} else {
playingNum = num
}
seat.Point = r.RoomCnf.CathetaInitPoint
}
}
if err == nil && r.RoomCnf.Mode != int(stub.RmClub) {
// 金币场 广播虚假在玩人数
BroadcastMsg(proto.NtfPlayingNumId, &proto.NtfPlayingNum{RoomType: r.RoomCnf.Id, PlayingNum: model.CalculateFakeCount(playingNum)})
}
r.record.AddPlayers(r)
r.gameLog = NewTrucoGameLog(r)
}
func (r *GameRoom) OnMessage(msgId string, msg map[string]interface{}) {
switch msgId {
case proto.ReqReadyGameId:
r.onReady(msg)
case proto.ReqEmoteId:
r.onEmote(msg)
case proto.ReqLeaveRoomId:
r.onLeaveRoom(msg)
case proto.ReqEnterRoomId:
r.onEnterRoom(msg)
case proto.ReqCachetaTidyPokerId:
r.onTidyPoker(msg)
case proto.ReqCachetaPickPokerId:
r.onPickPoker(msg)
case proto.ReqCachetaOutPokerId:
r.onOutPoker(msg)
case proto.ReqCachetaHuId:
r.onHu(msg)
case proto.ReqCachetaReconnectId, proto.ReqReconnectId:
r.onReconnect(msg)
case proto.NtfMaintainId:
r.onMaintain(msg)
case proto.ReqDisbandRoomId:
r.onDisbandRoom(msg)
}
}
func (r *GameRoom) FindSeat(uid int64) *GameSeat {
for _, seat := range r.Seats {
if !seat.Empty() && seat.Player().UID == uid {
return seat
}
}
return nil
}
func (r *GameRoom) GetSeat(uid int64) *GameSeat {
st := r.FindSeat(uid)
if st != nil {
return st
}
log.Error(r.Log("player:%d not in any seat", uid))
return nil
}
func (r *GameRoom) GetSeatNo(uid int64) int {
for _, seat := range r.Seats {
if !seat.Empty() && seat.Player().UID == uid {
return seat.No()
}
}
log.Error(r.Log("player:%d is not in any seat", uid))
return -1
}
func (r *GameRoom) groupHighToHandPoker(groups []*poker.GroupPokers, high []*poker.Poker) proto.CachetaHandPoker {
var handPoker proto.CachetaHandPoker
for _, group := range groups {
g := proto.GroupPoker{}
for _, pk := range group.Pokers {
g.Pokers = append(g.Pokers, pk.ToInt())
}
handPoker.Groups = append(handPoker.Groups, &g)
}
for _, h := range high {
handPoker.Pokers = append(handPoker.Pokers, h.ToInt())
}
return handPoker
}
// 发牌
func (r *GameRoom) testStraight() []*poker.Poker {
var pks []*poker.Poker
pks = append(pks, poker.NewPokerEx(poker.Club, poker.PointA, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Club, poker.Point2, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Club, poker.Point3, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Club, poker.Point4, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Club, poker.Point5, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Club, poker.Point6, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Club, poker.Point7, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Club, poker.Point8, poker.Ext1))
pks = append(pks, poker.NewPokerEx(poker.Diamond, poker.Point9, poker.Ext1))
return pks
}
// 发牌
func (r *GameRoom) dealPoker() {
r.gameStep = GsDealPoker
r.pokers.Shuffle()
begin := 0
for _, seat := range r.Seats {
if seat.Empty() {
continue
}
seat.pokers = append(seat.pokers, r.pokers.Pokers()[begin:begin+PlayerPokersNum]...)
// 调整手牌
groups, high := poker.FindBestGroupsAndRemains(r.pokers.WildPoker(), seat.pokers)
seat.handPoker = r.groupHighToHandPoker(groups, high)
log.Debug(r.SeatLog(seat, "玩家手牌:%v", poker.PokersToString(seat.pokers)))
begin = begin + PlayerPokersNum
}
r.outPokers = append(r.outPokers, r.pokers.Pokers()[begin])
begin += 1
r.pickPokers = r.pokers.Pokers()[begin:]
log.Debug(r.Log("所有牌数量:%v, 摸牌区数据:%v, begin:%v", len(r.pokers.Pokers()), len(r.pickPokers), begin))
}
func (r *GameRoom) playerPokersToPorto(seatNo int) []*proto.CachetaHandPoker {
var handPokers []*proto.CachetaHandPoker
for _, seat := range r.Seats {
if seat.Empty() {
handPokers = append(handPokers, &proto.CachetaHandPoker{Pokers: make([]int, 0)})
continue
}
if seat.No() == seatNo {
handPokers = append(handPokers, &seat.handPoker)
} else {
handPokers = append(handPokers, &proto.CachetaHandPoker{Pokers: make([]int, PlayerPokersNum)})
}
}
return handPokers
}
// 开始游戏
func (r *GameRoom) GameStart() {
r.BaseRoom.GameStart()
RoomMgr.CreateClubRoom(r.ClubId(), r.Type(), NewGameRoom)
r.smallGameStart()
}
// 小局游戏开始
func (r *GameRoom) smallGameStart() {
r.smallGameCount++
log.Debug(r.Log("第%d小局开始发牌", r.smallGameCount))
r.record.NewGame()
r.SetStatus(state.RsGaming)
exist := false
for _, st := range r.Seats {
st.ReInit()
if st.Empty() {
continue
}
// 清理分数为0的玩家信息
if st.Point < 1 {
r.leaveRoom(st, true)
} else {
exist = true
r.TriggerClubMemberPlaying(st.Player().UID, true)
}
}
if !exist {
log.Error(r.Log("房间所有位置都是空,无法开始"))
return
}
r.current = r.dealer
r.NextSeat()
r.dealer = r.current
r.roundStartPos = r.current
r.round = 0
r.dealPoker()
r.notifyDealPoker()
r.NewTimer(TtDealPoker, time.Duration(stub.GGlobal.TrucoDealPokerTime)*time.Second, r.CurrentPlayer())
}
// 广播发牌
func (r *GameRoom) notifyDealPoker() {
// 向玩家发送消息
rsp := &proto.NtfDealCachetaPokers{
Time: 0,
CuttingPoker: 0,
WildPoker: nil,
Poker: nil,
Dealer: r.dealer,
DropPoker: r.outPokers[0].ToInt(),
PickPokerNum: len(r.pickPokers),
GameCount: r.smallGameCount,
}
if r.pokers.CutPoker() != nil {
rsp.CuttingPoker = r.pokers.CutPoker().ToInt()
}
for _, pk := range r.pokers.WildPokers() {
rsp.WildPoker = append(rsp.WildPoker, pk.ToInt())
}
for _, seat := range r.Seats {
if !seat.Empty() {
rsp.Seat = seat.No()
rsp.Poker = r.playerPokersToPorto(seat.No())
r.SendMsg(seat.Player(), proto.NtfDealCachetaPokersId, rsp, false)
}
}
log.Debug(r.SeatLog(r.Seats[r.dealer], "庄家:%v", r.dealer))
rsp.Seat = 0
rsp.Poker = nil
for _, seat := range r.Seats {
if !seat.Empty() {
rsp.Poker = append(rsp.Poker, &seat.handPoker)
}
}
// 牌局回顾
r.record.AddAction(proto.NtfDealCachetaPokersId, rsp)
}
func (r *GameRoom) CurrentPlayer() *Player {
return r.Seats[r.current].Player()
}
func (r *GameRoom) CurrentSeat() *GameSeat {
return r.Seats[r.current]
}
func (r *GameRoom) NextSeat() {
for i := r.current + 1; i < r.current+len(r.Seats); i++ {
seatNo := i % len(r.Seats)
if seatNo == r.current {
break
}
if !r.Seats[seatNo].Empty() {
r.current = seatNo
r.Seats[r.current].ActType = SatPickPokerOrWin
break
}
}
}
//func (r *GameRoom) CutLineSeat() *GameSeat {
// for i := r.current + 1; i < r.current+len(r.Seats); i++ {
// seatNo := i % len(r.Seats)
// if seatNo == r.current {
// break
// }
// if !r.Seats[seatNo].Empty() && r.Seats[seatNo].TingHu {
// return r.Seats[seatNo]
// }
// }
// return nil
//}
func (r *GameRoom) AutoPlayerPickPoker() {
if r.Seats[r.current].Player().IsRobot() {
log.Error(r.SeatLog(r.Seats[r.current], "robot can not trigger timer auto out poker"))
}
req := proto.ReqCachetaPickPoker{}
log.Debug(r.SeatLog(r.Seats[r.current], "自动摸牌"))
msg := util.MakeMessage(proto.ReqCachetaPickPokerId, req, r.CurrentPlayer().UID, r.Id())
r.OnMessage(proto.ReqCachetaPickPokerId, msg)
}
func (r *GameRoom) copyHandPoker(hp proto.CachetaHandPoker) proto.CachetaHandPoker {
var handPoker proto.CachetaHandPoker
for _, g := range hp.Groups {
var ng proto.GroupPoker
ng.Pokers = append(ng.Pokers, g.Pokers...)
handPoker.Groups = append(handPoker.Groups, &ng)
}
handPoker.Pokers = append(handPoker.Pokers, hp.Pokers...)
return handPoker
}
func (r *GameRoom) AutoPlayerOutPoker() {
if r.Seats[r.current].Player().IsRobot() {
log.Error(r.SeatLog(r.Seats[r.current], "robot can not trigger timer auto out poker"))
}
seat := r.Seats[r.current]
// 有牌则出牌
if len(seat.pokers) > 0 {
outPoker := 0
if len(seat.handPoker.Pokers) != 0 {
pk := seat.handPoker.Pokers[len(seat.handPoker.Pokers)-1]
for _, p := range seat.pokers {
if pk == p.ToInt() {
outPoker = pk
break
}
}
}
if outPoker == 0 {
for i := len(seat.handPoker.Groups) - 1; i >= 0; i-- {
if len(seat.handPoker.Groups[i].Pokers) != 0 {
pks := seat.handPoker.Groups[i].Pokers
pk := pks[len(pks)-1]
for _, p := range seat.pokers {
if pk == p.ToInt() {
outPoker = pk
break
}
}
if outPoker != 0 {
break
}
}
}
}
if outPoker == 0 {
outPoker = seat.pokers[len(seat.pokers)-1].ToInt()
}
req := proto.ReqCachetaOutPoker{Poker: outPoker}
log.Debug(r.SeatLog(r.Seats[r.current], "自动出牌:%v", poker.NewPoker(req.Poker).ToString()))
msg := util.MakeMessage(proto.ReqCachetaOutPokerId, req, r.CurrentPlayer().UID, r.Id())
r.OnMessage(proto.ReqCachetaOutPokerId, msg)
return
}
log.Error(r.SeatLog(r.Seats[r.current], "poker was empty"))
}
func (r *GameRoom) OnTimer(timerType TimerType, args ...interface{}) {
r.CancelTimer(timerType)
switch timerType {
case TtSecond:
r.onWaitTimer()
case TtGameReadyStart:
if r.SeatPlayerNum() >= r.RoomCnf.MinPlayers && r.Status() != state.RsGaming {
r.ReInit()
r.GameStart()
}
case TtDealPoker:
r.PlayerAct(r.CurrentPlayer())
case TtPlayerAct:
user := args[0].(*Player)
if r.CurrentPlayer() == user {
seat := r.CurrentSeat()
if seat.ActType == SatPickPokerOrWin {
r.AutoPlayerPickPoker()
} else {
r.AutoPlayerOutPoker()
}
} else {
log.Error(r.SeatLog(r.Seats[r.current], " is not user:%v", user.UID))
}
case TtPlayerCutLine:
r.NextSeat()
r.PlayerAct(r.CurrentPlayer())
case TtNextGame:
r.smallGameStart()
}
}
// PlayerAct 通知玩家行动
func (r *GameRoom) PlayerAct(user *Player) {
seat := r.GetSeat(user.UID)
if seat.No() != r.current {
log.Error(r.SeatLog(r.GetSeat(user.UID), "is not current:%v", r.current))
return
}
r.gameStep = GsPlayerAct
r.notifyPlayerAct(seat)
r.NewTimer(TtPlayerAct, time.Duration(r.RoomCnf.ActTime+stub.GGlobal.TrucoActExTime)*time.Second, user)
}
// 通知玩家行动
func (r *GameRoom) notifyPlayerAct(seat *GameSeat) {
// 向玩家发送消息
rsp := &proto.NtfPlayerCachetaAct{
RoomId: r.Id(),
Seat: r.current,
Countdown: r.RoomCnf.ActTime,
CountdownEx: stub.GGlobal.TrucoActExTime,
Type: int(seat.ActType),
CanWin: 0,
}
_, highPokers := poker.FindBestGroupsAndRemains(r.pokers.WildPoker(), seat.pokers)
if len(highPokers) == 0 || (len(seat.pokers) == poker.HandlerPokerCount+1 && len(highPokers) == 1) {
rsp.CanWin = 1
}
log.Debug(r.SeatLog(seat, "玩家行动:%s", seat.ActType.String()))
r.Broadcast(proto.NtfPlayerCachetaActId, rsp, true)
// 牌局回顾
r.record.AddAction(proto.NtfPlayerCachetaActId, rsp)
}
// 结算
func (r *GameRoom) settlementBySeat(winSeat *GameSeat, highNum int) bool {
point := util.Tie(highNum == 0, 2, 1)
//winnerAddPoint := 0
// 通杀
bigWinner := 0 // 为1时表明全场只有庄家分数大于0
for _, st := range r.Seats {
if st.Empty() {
continue
}
if st.No() != winSeat.No() {
st.Point = util.Tie(st.Point-point > 0, st.Point-point, 0)
//winnerAddPoint += point
//winSeat.Point += point
}
if st.Point > 0 {
bigWinner++
}
}
// 结算消息
ntf := &proto.NtfCachetaGameSettle{
SeatSettle: nil,
NextGame: util.Tie(bigWinner == 1, 0, 1),
}
for _, st := range r.Seats {
if st.Empty() {
continue
}
seatSettle := &proto.SeatSettle{Seat: st.No(), SumPoint: st.Point, HandPoker: st.HandPoker()}
if st.No() != winSeat.No() {
seatSettle.AddPoint = -point
// 没分数,个人大结算
if st.Point < 1 {
seatSettle.AddScore = -r.RoomCnf.Blind
seatSettle.SumScore = 0
}
} else {
//seatSettle.AddPoint = winnerAddPoint
// 最终胜利者,大结算
if bigWinner == 1 {
seatSettle.AddScore += int64(r.RoomCnf.MinPlayers-1) * r.RoomCnf.Blind
}
}
// 净胜分结算
if seatSettle.AddScore != 0 {
if seatSettle.AddScore > 0 {
tip := seatSettle.AddScore * int64(r.RoomCnf.Rate) / int64(100)
r.gameLog.Player(st.No()).Tip = tip
seatSettle.AddScore -= tip
}
log.Info(r.SeatLog(st, "赢取金币:%v", seatSettle.AddScore))
// 机器人输赢汇入总池
if st.Player().IsRobot() {
model.AddRobotResourcePool(r.Type(), seatSettle.AddScore, util.Tie[string](r.ClubId() <= 0, model.ResCoins, model.ResClubUserScore))
}
r.addResource(st.Player(), -r.RoomCnf.Blind, model.ResTakeCoins, model.ReasonGame)
if seatSettle.AddScore != 0 {
r.addResource(st.Player(), seatSettle.AddScore, model.ResCoins, model.ReasonGame)
}
}
ntf.SeatSettle = append(ntf.SeatSettle, seatSettle)
}
r.Broadcast(proto.NtfCachetaGameSettleId, ntf, false)
r.record.AddAction(proto.NtfCachetaGameSettleId, ntf)
return bigWinner == 1
}
// GameOver 本局游戏结束,会清理部分数据
func (r *GameRoom) GameOver(seat *GameSeat, highNum int) {
r.gameStep = GsGameSettle
//log.Debug(r.Log("cancel timer:all timer"))
r.CancelAllTimer()
clear(r.LastMsg)
bigSettle := r.settlementBySeat(seat, highNum)
if !bigSettle {
// 开启下一局
r.NewTimer(TtNextGame, time.Duration(stub.GGlobal.TrucoNextGameTime)*time.Second)
return
}
// 游戏结束
r.endTime = time.Now()
// 牌局回顾
for _, st := range r.Seats {
if !st.Empty() {
r.record.AddPlayerRecord(r, st.Player().UID, r.getTakeCoin(st.Player()), r.getTakeCoin(st.Player()), r.ClubId())
}
}
r.record.Flush()
r.gameLog.Flush(r)
r.gameStep = GsWaitGame
// 清理玩家信息
for _, st := range r.Seats {
if !st.Empty() {
r.leaveRoom(st, true)
}
}
}
// 离开房间
func (r *GameRoom) SetFakeLeave(uid int64, fake bool) {
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
if fake {
log.Debug(r.SeatLog(seat, "玩家假离开, room status:%v", r.gameStep))
seat.SetFakeLeave(true)
} else {
log.Debug(r.SeatLog(seat, "玩家假离开后返回, room status:%v", r.gameStep))
seat.SetFakeLeave(false)
}
r.notifyFakeLeave(seat)
}
// 推送房间信息给玩家
func (r *GameRoom) notifyFakeLeave(seat *GameSeat) {
ntf := &proto.NtfFakeLeave{
RoomId: r.Id(),
CurrentSeat: seat.No(),
FakeLeave: util.Tie(seat.FakeLeave(), 0, 1),
}
r.Broadcast(proto.NtfFakeLeaveId, ntf, false)
}
// 推送房间信息给玩家
func (r *GameRoom) notifyRoomInfo(user *Player) {
ntf := r.makeProtoRoomInfo()
r.SendMsg(user, proto.NtfCachetaRoomInfoId, ntf, false)
}
// 推送玩家信息给房间里的玩家
func (r *GameRoom) notifyMeToOthers(user *Player) {
ntf := proto.NtfCachetaPlayerInfo{Players: make([]*proto.CachetaPlayer, 0)}
ntf.Players = append(ntf.Players, r.makePlayerToProto(r.GetSeat(user.UID), true))
for _, seat := range r.Seats {
if !seat.Empty() && seat.Player().UID != user.UID {
r.SendMsg(seat.Player(), proto.NtfCachetaPlayerInfoId, ntf, false)
}
}
}
// 推送玩家信息给房间里的玩家
func (r *GameRoom) notifyOthersToMe(user *Player) {
ntf := proto.NtfCachetaPlayerInfo{Players: make([]*proto.CachetaPlayer, 0)}
for _, seat := range r.Seats {
if !seat.Empty() {
ntf.Players = append(ntf.Players, r.makePlayerToProto(seat, true))
}
}
r.SendMsg(user, proto.NtfCachetaPlayerInfoId, ntf, false)
}
// 推送玩家信息给房间里的玩家
func (r *GameRoom) notifyPlayerInfo(user *Player, isReentry bool) {
if !isReentry {
r.notifyMeToOthers(user)
}
r.notifyOthersToMe(user)
}
func (r *GameRoom) SetGmPokers(uid int64, pokers [][]int, ghostPoker int) bool {
seatNo := 0
for _, seat := range r.Seats {
if !seat.Empty() && seat.Player().UID == uid {
seatNo = seat.No()
break
}
}
log.Debug(r.SeatLog(r.Seats[seatNo], "玩家:%v seat:%v 配牌:%+v 鬼牌:%v", uid, seatNo, pokers, ghostPoker))
r.pokers.SetGmPoker(pokers, ghostPoker, seatNo)
r.pokers.Pokers()
return true
}
func (r *GameRoom) SetRobotTemper(seatNo int, cnf stub.RobotTemper) {
seat := r.Seats[seatNo]
//user := seat.Player()
if !seat.Empty() && seat.Player().IsRobot() {
//switch cnf {
//case stub.RteAplomb:
// user.Robot = NewRobotAplomb(cnf, user.UserInfo, seat, r)
//case stub.RteNormal:
// user.Robot = NewRobotNormal(cnf, user.UserInfo, seat, r)
//case stub.RteRadical:
// user.Robot = NewRobotRadical(cnf, user.UserInfo, seat, r)
//case stub.RteRotten:
// user.Robot = NewRobotRotten(cnf, user.UserInfo, seat, r)
//case stub.RteEvaluation:
// user.Robot = NewRobotEvaluation(cnf, user.UserInfo, seat, r)
//default:
// log.Error(r.SeatLog(seat, "初始化机器人失败:%v", cnf.String()))
//}
log.Debug(r.SeatLog(seat, "初始化%v机器人", cnf.String()))
}
}
func (r *GameRoom) StopWaitTimer() {
r.CancelTimer(TtSecond)
r.waitSecond = 0
}
func (r *GameRoom) StartWaitTimer() {
r.NewTimer(TtSecond, time.Second)
}
func (r *GameRoom) onWaitTimer() {
r.waitSecond++
// 达到最少人数或者房间不是等待状态,结束等待定时器
if r.SeatPlayerNum() >= r.RoomCnf.MinPlayers || r.Status() != state.RsWait {
r.StopWaitTimer()
return
}
// 所有真人都离开,移除机器人
if r.RealPlayerNum() == 0 {
for _, st := range r.Seats {
if !st.Empty() {
r.leaveRoom(st, false)
}
}
return
}
/*
2.玩家点击匹配后优先匹配真人
1低于30S可修改若匹配到最大人数则立即开始游戏
2达到30S时若已经匹配到真人无论匹配到几个都立即开始游戏
3超过30S依旧未匹配到真人则匹配1个可修改AI并继续匹配10S可修改10S内若匹配到真人则立即开始游戏若没有匹配到真人达到10S时也立即开始游戏
*/
if r.RobotPlayerNum() == 0 && r.waitSecond > WaitRealPlayerTimeout && r.waitSecond > WaitRealPlayerTimeout+rand.Intn(RandRobotTimeout) {
if robot := RobotMgr.Pop(r.RoomCnf); robot != nil {
r.OnEnterRoom(robot)
}
}
r.NewTimer(TtSecond, time.Second)
}