1688 lines
50 KiB
Go
1688 lines
50 KiB
Go
package room
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"math/rand"
|
||
"samba/pkg/log"
|
||
"samba/pkg/servername"
|
||
"samba/proto"
|
||
. "samba/server/game/baseroom"
|
||
. "samba/server/game/player"
|
||
"samba/server/truco/poker"
|
||
. "samba/server/truco/service"
|
||
"samba/stub"
|
||
"samba/util/event"
|
||
"samba/util/model"
|
||
. "samba/util/playtype"
|
||
"samba/util/routingKey"
|
||
"samba/util/state"
|
||
"samba/util/util"
|
||
"slices"
|
||
"time"
|
||
)
|
||
|
||
type TrucoSeat struct {
|
||
*BaseSeat
|
||
Pokers []*poker.Poker // 手牌
|
||
//ActType ActType // 最近叫分行为
|
||
OutPoker *poker.Poker // 最近出的牌
|
||
disband state.DisbandType // 解散状态
|
||
}
|
||
|
||
// TeamAct 队伍操作
|
||
type TeamAct struct {
|
||
color TeamColor // 队伍颜色
|
||
maxAct ActType // 最大操作
|
||
actType map[int]ActType // 操作行为
|
||
//seatNo int // 操作的座位号
|
||
//round int // 叫分轮次
|
||
}
|
||
|
||
func newTeamAct(color TeamColor) *TeamAct {
|
||
act := &TeamAct{color: color, maxAct: AtUnknown, actType: make(map[int]ActType)}
|
||
return act
|
||
}
|
||
|
||
type TrucoRoom struct {
|
||
*BaseRoom[*TrucoSeat]
|
||
*event.Events
|
||
|
||
pokers poker.IPokerGenerator
|
||
pointType *poker.PlayTypeConst // 玩法不同,初始点数及加点也不同
|
||
dealer int // 庄家座位
|
||
current int // 当前行动人座位
|
||
roundStartPos int // 本轮中最开始的位置,用于比牌
|
||
round int // 当前轮 0-2
|
||
lastTrucoColor TeamColor // 最近叫分的队伍颜色
|
||
actTypes []*TeamAct // 双方最近行动类型
|
||
agreeStatus [2]ActType // 本局双方同意状态
|
||
points [2]int // 双方累积分
|
||
point int // 本局分数
|
||
light []GameLight // 回合结算胜负结果
|
||
gameStep GameStep // 游戏状态
|
||
decidingTeam TeamColor // 决胜局队伍
|
||
star int // 金币场,倍数,用星星表示,默认1倍
|
||
|
||
startTime time.Time
|
||
endTime time.Time
|
||
record *TrucoGameRecord // 战绩玩家查询
|
||
gameLog *TrucoGameLog // 游戏操作汇总给后台
|
||
smallGameCount int // 记录第几小局
|
||
isActTeam bool // 当前行动人数,1人或者1队
|
||
|
||
disbandInfo map[int64]int // 申请解散
|
||
disbandTime int64 // 申请解散房间的起始时间
|
||
disband state.RoomDisbandType // 解散状态
|
||
|
||
}
|
||
|
||
func NewTrucoRoom(id, roomType, clubId int) (IRoom, proto.ErrorCode) {
|
||
baseRoom, code := NewBaseRoom[*TrucoSeat](id, roomType, clubId)
|
||
if code != proto.Ok {
|
||
return nil, code
|
||
}
|
||
room := &TrucoRoom{
|
||
BaseRoom: baseRoom,
|
||
Events: event.NewEvents(),
|
||
pokers: poker.NewPokerGenerator(PlayType(baseRoom.RoomCnf.PlayType)),
|
||
pointType: poker.NewPlayTypeConst(PlayType(baseRoom.RoomCnf.PlayType)),
|
||
dealer: 0,
|
||
current: 0,
|
||
round: 0,
|
||
actTypes: make([]*TeamAct, 0),
|
||
star: 1,
|
||
agreeStatus: [2]ActType{AtUnknown, AtUnknown},
|
||
points: [2]int{0, 0},
|
||
point: poker.NewPlayTypeConst(PlayType(baseRoom.RoomCnf.PlayType)).GameStartPoint(),
|
||
light: make([]GameLight, 0),
|
||
gameStep: GsReadyGame,
|
||
gameLog: NewTrucoGameLog(),
|
||
smallGameCount: 0,
|
||
disband: state.RdtNormal,
|
||
}
|
||
room.SetTruthRoom(room)
|
||
if room.pokers == nil {
|
||
log.Error(room.Log("create room fail.play type:%v", baseRoom.RoomCnf.PlayType))
|
||
return nil, proto.Internal
|
||
}
|
||
room.SetTimerHandler(room)
|
||
|
||
for i := 0; i < room.RoomCnf.MinPlayers; i++ {
|
||
room.Seats = append(room.Seats, &TrucoSeat{
|
||
BaseSeat: NewBaseSeat(i),
|
||
Pokers: make([]*poker.Poker, 0),
|
||
//ActType: AtUnknown,
|
||
OutPoker: nil,
|
||
})
|
||
}
|
||
room.dealer = int(rand.Int31n(int32(len(room.Seats))))
|
||
room.current = (room.dealer + 1) % len(room.Seats)
|
||
room.roundStartPos = room.current
|
||
room.gameLog.Star = room.star
|
||
|
||
if err := TrucoService.QueueBind(QueueName(), routingKey.RoomKey(room.Id()), util.Direct(servername.Truco)); err != nil {
|
||
log.Error(err.Error())
|
||
}
|
||
room.UpdateClubWaitingRoom()
|
||
//room.SetGmPokers(0, [][]int{{302, 402, 102}, {403, 203, 303}}, 202)
|
||
return room, code
|
||
}
|
||
|
||
func (r *TrucoRoom) addResource(player *Player, add int64, resType, reason string) {
|
||
if add == 0 {
|
||
return
|
||
}
|
||
if resType == model.ResTakeCoins {
|
||
r.AddTakeCoin(player, add, reason)
|
||
} else {
|
||
r.AddUserResource(player.UID, add, resType, reason)
|
||
}
|
||
}
|
||
|
||
// 大局之前初始化
|
||
func (r *TrucoRoom) ReInit() {
|
||
//if err := TrucoService.QueueBind(QueueName(), routingKey.RoomKey(r.Id()), util.Direct(servername.Truco)); err != nil {
|
||
// log.Error(err.Error())
|
||
//}
|
||
// 进房间时,匹配房间已经移除
|
||
//GMatchQueue.RemoveRoom(r.Id(), r.Type())
|
||
RoomMgr.Add(r)
|
||
|
||
//r.gameNo = uuid.NewString()
|
||
|
||
r.star = 1
|
||
r.startTime = time.Now()
|
||
r.record = NewTrucoGameRecord()
|
||
var playingNum int64
|
||
var err error
|
||
for _, seat := range r.Seats {
|
||
log.Debug(r.SeatLog(seat, "颜色:%v", r.teamColor(seat.No())))
|
||
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
|
||
}
|
||
}
|
||
}
|
||
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.BaseGameLog = r.BaseGameLog()
|
||
r.gameLog.BaseGameLog.StartGame(r.startTime.Unix(), r.GameNo)
|
||
r.gameLog.AddPlayers(r)
|
||
}
|
||
|
||
func (r *TrucoRoom) OnMessage(msgId string, msg map[string]interface{}) {
|
||
switch msgId {
|
||
case proto.ReqReadyGameId:
|
||
r.onReady(msg)
|
||
case proto.ReqEmoteId:
|
||
r.onEmote(msg)
|
||
case proto.ReqEnterRoomId:
|
||
r.onReentryRoom(msg)
|
||
case proto.ReqLeaveRoomId:
|
||
r.onLeaveRoom(msg)
|
||
case proto.ReqSetDarkPokerId:
|
||
r.onSetDarkPoker(msg)
|
||
case proto.ReqPlayerOutPokerId:
|
||
r.onOutPoker(msg)
|
||
case proto.ReqPlayerActId:
|
||
r.onPlayerAct(msg)
|
||
case proto.ReqReconnectId:
|
||
r.onReconnect(msg)
|
||
case proto.ReqShowPokerId:
|
||
r.onShowPoker(msg)
|
||
case proto.NtfMaintainId:
|
||
r.onMaintain(msg)
|
||
case proto.ReqDisbandRoomId:
|
||
r.onDisbandRoom(msg)
|
||
case proto.ReqUserDisbandRoomId:
|
||
r.onUserDisbandRoom(msg)
|
||
case proto.ReqHostingId:
|
||
r.onHosting(msg)
|
||
}
|
||
}
|
||
|
||
func (r *TrucoRoom) GetSeat(uid int64) *TrucoSeat {
|
||
for _, seat := range r.Seats {
|
||
if !seat.Empty() && seat.Player().UID == uid {
|
||
return seat
|
||
}
|
||
}
|
||
log.Error(r.Log("player:%d not in any seat", uid))
|
||
return nil
|
||
}
|
||
|
||
func (r *TrucoRoom) GetSeatNo(uid int64) int {
|
||
for _, seat := range r.Seats {
|
||
if seat.Player() != nil && seat.Player().UID == uid {
|
||
return seat.No()
|
||
}
|
||
}
|
||
log.Error(r.Log("player:%d is not in any seat", uid))
|
||
return -1
|
||
}
|
||
|
||
// 发牌
|
||
func (r *TrucoRoom) dealPoker() {
|
||
r.gameStep = GsDealPoker
|
||
r.pokers.Shuffle()
|
||
alloc := &poker.Allocator{}
|
||
alloc.Init(r.pokers, r.pokers.Pokers())
|
||
|
||
// 发牌时,打乱发牌顺序
|
||
randSeats := slices.Clone(r.Seats)
|
||
rand.Shuffle(len(randSeats), func(i, j int) {
|
||
randSeats[i], randSeats[j] = randSeats[j], randSeats[i]
|
||
})
|
||
|
||
for _, seat := range randSeats {
|
||
var ok bool
|
||
sum, err := seat.Player().GetPlayCount(stub.Truco)
|
||
if err != nil {
|
||
log.Error(r.UserLog(seat.Player().UID, "获取玩家游戏次数失败:%s", err.Error()))
|
||
}
|
||
switch {
|
||
case r.ClubId() > 0:
|
||
seat.Pokers, _ = alloc.Alloc(poker.AllocNormal, PlayerPokersNum)
|
||
log.Debug(r.SeatLog(seat, "俱乐部场,普通配牌"))
|
||
case seat.Player().IsRobot():
|
||
// 机器人总是普通配牌
|
||
seat.Pokers, _ = alloc.Alloc(poker.AllocNormal, PlayerPokersNum)
|
||
log.Debug(r.SeatLog(seat, "机器人普通配牌"))
|
||
case r.HasLuckyUser:
|
||
// 房间内有幸运玩家(白名单),所有配好牌
|
||
seat.Pokers, ok = alloc.Alloc(poker.AllocGood, PlayerPokersNum)
|
||
log.Debug(r.SeatLog(seat, "房间内有幸运玩家,所有配好牌,是否成功配牌:%v", ok))
|
||
case err == nil && sum <= stub.PlayerNoviceThreshold:
|
||
// 新手玩家,不走幸运值逻辑,配好牌
|
||
seat.Pokers, ok = alloc.Alloc(poker.AllocGood, PlayerPokersNum)
|
||
log.Debug(r.SeatLog(seat, "游玩局数为 %d 新手配好牌,是否成功配牌:%v", sum, ok))
|
||
default:
|
||
// 走幸运值配牌
|
||
r.luckyAllocPoker(alloc, seat)
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// 幸运值配牌逻辑
|
||
func (r *TrucoRoom) luckyAllocPoker(alloc *poker.Allocator, seat *TrucoSeat) {
|
||
var ok bool
|
||
act := poker.AllocNormal
|
||
if !seat.Player().IsRobot() {
|
||
act = poker.AllocActByLuckyPoint(seat.Player().LuckyPoint.GetLuckyPoint(stub.Truco))
|
||
}
|
||
seat.Pokers, ok = alloc.Alloc(act, PlayerPokersNum)
|
||
if ok && act == poker.AllocGood {
|
||
// 触发配好牌行为
|
||
// 减少玩家幸运值
|
||
lp, err := model.NewUserLuckyPointOp().AddByGameType(seat.Player().UID, stub.Truco, -10)
|
||
if err == nil {
|
||
seat.Player().LuckyPoint.SetLuckyPoint(stub.Truco, lp)
|
||
} else {
|
||
log.Error(r.UserLog(seat.Player().UID, "配好牌时,减少幸运值失败:%s", err.Error()))
|
||
}
|
||
}
|
||
log.Debug(r.SeatLog(seat, "幸运值配牌,配牌行为 act:%s 是否成功配牌:%v", act, ok))
|
||
}
|
||
|
||
func (r *TrucoRoom) playerPokersToPorto(seatNo int) [][]int {
|
||
arr := make([][]int, len(r.Seats))
|
||
for no := range arr {
|
||
arr[no] = make([]int, PlayerPokersNum)
|
||
}
|
||
for i := 0; i < len(r.Seats[seatNo].Pokers); i++ {
|
||
arr[seatNo][i] = r.Seats[seatNo].Pokers[i].ToInt()
|
||
}
|
||
return arr
|
||
}
|
||
|
||
// 判断玩家队伍颜色
|
||
func (r *TrucoRoom) teamColor(seatNo int) TeamColor {
|
||
if seatNo%2 == 0 {
|
||
return TcRed
|
||
}
|
||
return TcGreen
|
||
}
|
||
|
||
// 判断对手队伍颜色
|
||
func (r *TrucoRoom) rivalColor(seatNo int) TeamColor {
|
||
return (r.teamColor(seatNo) + 1) % 2
|
||
}
|
||
|
||
// 判断对手队伍颜色
|
||
func (r *TrucoRoom) rivalColor2(color TeamColor) TeamColor {
|
||
return (color + 1) % 2
|
||
}
|
||
|
||
func (r *TrucoRoom) smallGameStart() {
|
||
r.smallGameCount++
|
||
log.Debug(r.Log("第%d小局,开始发牌", r.smallGameCount))
|
||
r.record.NewGame()
|
||
r.SetStatus(state.RsGaming)
|
||
for _, st := range r.Seats {
|
||
st.Player().Continue = GcNormal
|
||
if !st.Empty() {
|
||
// 俱乐部房间触发在玩通知
|
||
r.TriggerClubMemberPlaying(st.Player().UID, true)
|
||
}
|
||
}
|
||
// 重置本局数据
|
||
r.dealer = (r.dealer + 1) % len(r.Seats)
|
||
r.current = (r.dealer + 1) % len(r.Seats)
|
||
|
||
r.roundStartPos = r.current
|
||
r.round = 0
|
||
r.lastTrucoColor = TcUnknown
|
||
|
||
r.light = r.light[0:0]
|
||
r.point = r.pointType.GameStartPoint()
|
||
r.clearAllAct()
|
||
r.agreeStatus[TcRed] = AtUnknown
|
||
r.agreeStatus[TcGreen] = AtUnknown
|
||
|
||
r.dealPoker()
|
||
r.notifyDealPoker()
|
||
|
||
r.NewTimer(TtDealPoker, time.Duration(stub.GGlobal.TrucoDealPokerTime)*time.Second, r.CurrentPlayer())
|
||
}
|
||
|
||
// GameStart 开始游戏
|
||
func (r *TrucoRoom) GameStart() {
|
||
r.BaseRoom.GameStart()
|
||
RoomMgr.CreateClubRoom(r.ClubId(), r.Type(), NewTrucoRoom)
|
||
r.smallGameStart()
|
||
}
|
||
|
||
// 决胜局通知决胜方操作
|
||
func (r *TrucoRoom) decidingGame() {
|
||
for _, seat := range r.Seats {
|
||
if r.teamColor(seat.No()) == r.decidingTeam {
|
||
seat.SetCanAct(true)
|
||
log.Debug(r.SeatLog(seat, "玩家可以操作"))
|
||
}
|
||
}
|
||
r.gameStep = GsDecidingAct
|
||
r.notifyDecidingGame()
|
||
r.NewTimer(TtDecidingGame, time.Duration(stub.GGlobal.TrucoDecidingGameNtf+stub.GGlobal.TrucoActExTime)*time.Second, r.CurrentPlayer())
|
||
// 记录决胜局次数
|
||
r.gameLog.Teams[r.decidingTeam].Deciding++
|
||
}
|
||
|
||
// 发牌动画结束,如果决胜局,则决胜局广播,非决胜局则通知玩家行动,
|
||
func (r *TrucoRoom) dealPokerTimerOver() {
|
||
r.decidingTeam = r.decidingGameTeam()
|
||
if r.decidingTeam != TcUnknown {
|
||
r.decidingGame()
|
||
} else {
|
||
r.PlayerAct(r.CurrentPlayer())
|
||
}
|
||
}
|
||
|
||
// AutoDecidingAct 决胜手自动行动
|
||
func (r *TrucoRoom) AutoDecidingAct() {
|
||
teamAct := r.lastTeamAct(r.decidingTeam)
|
||
if teamAct == nil {
|
||
teamAct = &TeamAct{}
|
||
}
|
||
for _, seat := range r.Seats {
|
||
if r.teamColor(seat.No()) == r.decidingTeam {
|
||
if _, ok := teamAct.actType[seat.No()]; !ok {
|
||
msg := util.MakeMessage(proto.ReqPlayerActId, &proto.ReqPlayerAct{Raise: AtGiveUp.ToInt(r.PlayType())}, r.Seats[seat.No()].Player().UID, r.Id())
|
||
log.Debug(r.SeatLog(r.Seats[seat.No()], "决胜局自动放弃"))
|
||
r.OnMessage(proto.ReqPlayerActId, msg)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 决胜局广播
|
||
func (r *TrucoRoom) notifyDecidingGame() {
|
||
r.isActTeam = true
|
||
ntf := &proto.NtfDecidingGame{
|
||
TeamColor: int(r.decidingTeam),
|
||
Poker: nil,
|
||
Countdown: stub.GGlobal.TrucoDecidingGameNtf,
|
||
CountdownEx: stub.GGlobal.TrucoActExTime,
|
||
}
|
||
for _, seat := range r.Seats {
|
||
//ntf.Seat = seat.No()
|
||
ntf.Poker = ntf.Poker[0:0]
|
||
ntf.CanGiveUp = AtUnknown.ToInt(r.PlayType())
|
||
ntf.CanAgree = AtUnknown.ToInt(r.PlayType())
|
||
if r.teamColor(seat.No()) == r.decidingTeam {
|
||
ntf.CanGiveUp = AtGiveUp.ToInt(r.PlayType())
|
||
ntf.CanAgree = AtAgree.ToInt(r.PlayType())
|
||
// 决胜队伍
|
||
for _, st := range r.Seats {
|
||
if r.teamColor(seat.No()) == r.teamColor(st.No()) {
|
||
seatPoker := &proto.SeatPoker{Seat: st.No()}
|
||
for _, pk := range st.Pokers {
|
||
seatPoker.Poker = append(seatPoker.Poker, pk.ToInt())
|
||
}
|
||
ntf.Poker = append(ntf.Poker, seatPoker)
|
||
}
|
||
}
|
||
} else {
|
||
for _, st := range r.Seats {
|
||
if r.teamColor(seat.No()) != r.teamColor(st.No()) {
|
||
seatPoker := &proto.SeatPoker{Seat: st.No()}
|
||
seatPoker.Poker = append(seatPoker.Poker, 0, 0, 0)
|
||
ntf.Poker = append(ntf.Poker, seatPoker)
|
||
}
|
||
}
|
||
}
|
||
r.SendMsg(seat.Player(), proto.NtfDecidingGameId, ntf, false)
|
||
}
|
||
|
||
// 牌局回顾
|
||
ntf.Poker = ntf.Poker[0:0]
|
||
ntf.CanGiveUp = AtUnknown.ToInt(r.PlayType())
|
||
ntf.CanAgree = AtUnknown.ToInt(r.PlayType())
|
||
for _, seat := range r.Seats {
|
||
if r.teamColor(seat.No()) == r.decidingTeam {
|
||
// 决胜队伍
|
||
seatPoker := &proto.SeatPoker{Seat: seat.No()}
|
||
for _, pk := range seat.Pokers {
|
||
seatPoker.Poker = append(seatPoker.Poker, pk.ToInt())
|
||
}
|
||
ntf.Poker = append(ntf.Poker, seatPoker)
|
||
}
|
||
}
|
||
// 牌局回顾
|
||
r.record.AddAction(proto.NtfDecidingGameId, ntf)
|
||
}
|
||
|
||
// 检查是否决胜局以及决胜方颜色
|
||
func (r *TrucoRoom) decidingGameTeam() TeamColor {
|
||
if r.points[TcRed] == r.pointType.DecidingPoint() && r.points[TcGreen] != r.pointType.DecidingPoint() {
|
||
return TcRed
|
||
}
|
||
if r.points[TcGreen] == r.pointType.DecidingPoint() && r.points[TcRed] != r.pointType.DecidingPoint() {
|
||
return TcGreen
|
||
}
|
||
return TcUnknown
|
||
}
|
||
|
||
// 广播发牌
|
||
func (r *TrucoRoom) notifyDealPoker() {
|
||
// 向玩家发送消息
|
||
rsp := &proto.NtfDealPokers{
|
||
Time: 0,
|
||
CuttingPoker: 0,
|
||
Poker: nil,
|
||
Dealer: r.dealer,
|
||
GameCount: r.smallGameCount,
|
||
}
|
||
if r.pokers.GhostPoker() != nil {
|
||
rsp.CuttingPoker = r.pokers.GhostPoker().ToInt()
|
||
}
|
||
for _, seat := range r.Seats {
|
||
if seat.Player() != nil {
|
||
rsp.Seat = seat.No()
|
||
rsp.Poker = r.playerPokersToPorto(seat.No())
|
||
r.SendMsg(seat.Player(), proto.NtfDealPokersId, 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.Player() != nil {
|
||
var seatPokers []int
|
||
for _, pk := range seat.Pokers {
|
||
seatPokers = append(seatPokers, pk.ToInt())
|
||
}
|
||
rsp.Poker = append(rsp.Poker, seatPokers)
|
||
}
|
||
}
|
||
// 牌局回顾
|
||
r.record.AddAction(proto.NtfDealPokersId, rsp)
|
||
}
|
||
|
||
func (r *TrucoRoom) CurrentPlayer() *Player {
|
||
return r.Seats[r.current].Player()
|
||
}
|
||
|
||
func (r *TrucoRoom) CurrentSeat() *TrucoSeat {
|
||
return r.Seats[r.current]
|
||
}
|
||
|
||
func (r *TrucoRoom) BroadcastToColor(msgId string, msg interface{}, color TeamColor, save bool, exclude ...*Player) {
|
||
for _, seat := range r.Seats {
|
||
if !seat.Empty() && r.teamColor(seat.No()) == color {
|
||
in := false
|
||
for _, p := range exclude {
|
||
if seat.Player().UID == p.UID {
|
||
in = true
|
||
break
|
||
}
|
||
}
|
||
if !in {
|
||
r.SendMsg(seat.Player(), msgId, msg, save)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Teammate 队友
|
||
func (r *TrucoRoom) Teammate(seatNo int) (seats []*TrucoSeat) {
|
||
color := r.teamColor(seatNo)
|
||
for _, seat := range r.Seats {
|
||
if !seat.Empty() && seat.No() != seatNo && r.teamColor(seat.No()) == color {
|
||
seats = append(seats, seat)
|
||
}
|
||
}
|
||
if len(seats) == 0 {
|
||
log.Error(r.Log("seat:%d has not teammate", seatNo))
|
||
}
|
||
return
|
||
}
|
||
|
||
func (r *TrucoRoom) NextSeat() {
|
||
r.current = (r.current + 1) % len(r.Seats)
|
||
}
|
||
|
||
func (r *TrucoRoom) AutoPlayerOutPoker() {
|
||
if r.Seats[r.current].Player().IsRobot() {
|
||
log.Error(r.SeatLog(r.Seats[r.current], "robot can not trigger timer auto out poker"))
|
||
}
|
||
// 有牌则出牌
|
||
if len(r.Seats[r.current].Pokers) > 0 {
|
||
card := r.Seats[r.current].Pokers[0]
|
||
req := proto.ReqPlayerOutPoker{Poker: card.ToInt()}
|
||
log.Debug(r.SeatLog(r.Seats[r.current], "自动出牌:%v", poker.NewPoker(req.Poker).ToString()))
|
||
msg := util.MakeMessage(proto.ReqPlayerOutPokerId, req, r.CurrentPlayer().UID, r.Id())
|
||
r.OnMessage(proto.ReqPlayerOutPokerId, msg)
|
||
return
|
||
}
|
||
log.Error(r.SeatLog(r.Seats[r.current], "poker was empty"))
|
||
}
|
||
|
||
// AutoPlayerRspRaise 自动行动
|
||
func (r *TrucoRoom) AutoPlayerRspRaise(color TeamColor) {
|
||
teamAct := r.lastTeamAct(color)
|
||
for _, seat := range r.Seats {
|
||
if r.teamColor(seat.No()) == color {
|
||
if _, ok := teamAct.actType[seat.No()]; !ok {
|
||
msg := util.MakeMessage(proto.ReqPlayerActId, &proto.ReqPlayerAct{Raise: AtGiveUp.ToInt(r.PlayType())}, r.Seats[seat.No()].Player().UID, r.Id())
|
||
log.Debug(r.SeatLog(r.Seats[seat.No()], "自动放弃"))
|
||
r.OnMessage(proto.ReqPlayerActId, msg)
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
func (r *TrucoRoom) OnTimer(timerType TimerType, args ...interface{}) {
|
||
//log.Debug(r.Log("cancel timer:%v by on timer", timerType))
|
||
r.CancelTimer(timerType)
|
||
switch timerType {
|
||
case TtGameReadyStart:
|
||
if r.SeatPlayerNum() == r.RoomCnf.MinPlayers && r.Status() != state.RsGaming {
|
||
r.ReInit()
|
||
r.GameStart()
|
||
}
|
||
case TtDealPoker:
|
||
r.dealPokerTimerOver()
|
||
case TtDecidingGame:
|
||
// 设置队伍托管
|
||
r.setTeamHosting(r.decidingTeam, true)
|
||
r.AutoDecidingAct()
|
||
case TtPlayerAct:
|
||
user := args[0].(*Player)
|
||
if r.CurrentPlayer() == user {
|
||
// 设置玩家托管
|
||
r.setPlayerHosting(user, true)
|
||
r.AutoPlayerOutPoker()
|
||
}
|
||
case TtPlayerRspRaise:
|
||
color := args[0].(int)
|
||
// 设置队伍托管
|
||
r.setTeamHosting(TeamColor(color), true)
|
||
r.AutoPlayerRspRaise(TeamColor(color))
|
||
case TtCmpPoker:
|
||
user := args[0].(*Player)
|
||
r.PlayerAct(user)
|
||
case TtNextGame:
|
||
r.smallGameStart()
|
||
case TtDelDisbandRoomInfo:
|
||
r.disbandInfo = nil
|
||
r.disbandTime = 0
|
||
}
|
||
}
|
||
|
||
// PlayerAct 通知玩家行动
|
||
func (r *TrucoRoom) PlayerAct(user *Player) {
|
||
seat := r.GetSeat(user.UID)
|
||
if seat == nil {
|
||
log.Error(r.Log("user:%v is not in room", user.UID))
|
||
return
|
||
}
|
||
if seat.No() != r.current {
|
||
log.Error(r.SeatLog(r.GetSeat(user.UID), "is not current:%v", r.current))
|
||
return
|
||
}
|
||
seat.SetCanAct(true)
|
||
log.Debug(r.SeatLog(seat, "玩家可以操作"))
|
||
r.notifyPlayerAct()
|
||
r.NewTimer(TtPlayerAct, time.Duration(r.RoomCnf.ActTime+stub.GGlobal.TrucoActExTime)*time.Second, user)
|
||
}
|
||
|
||
// 设置队伍托管
|
||
func (r *TrucoRoom) setTeamHosting(color TeamColor, enable bool) {
|
||
for _, seat := range r.Seats {
|
||
if r.teamColor(seat.No()) == color {
|
||
r.setPlayerHosting(seat.Player(), enable)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设置玩家托管
|
||
func (r *TrucoRoom) setPlayerHosting(user *Player, enable bool) {
|
||
|
||
if user.IsRobot() {
|
||
log.Error(r.SeatLog(r.GetSeat(user.UID), "robot cannot set hosting"))
|
||
return
|
||
}
|
||
|
||
// 如果状态没有变化,直接返回
|
||
if user.IsHosting() == enable {
|
||
return
|
||
}
|
||
|
||
// 设置托管机器人
|
||
if enable {
|
||
user.Robot = NewRobotHosting(r, r.GetSeat(user.UID))
|
||
} else {
|
||
user.CleanRobot()
|
||
}
|
||
// 通知状态变更
|
||
r.Broadcast(proto.NtfHostingId, proto.NtfHosting{Seat: r.GetSeatNo(user.UID), Enable: enable}, false)
|
||
|
||
log.Debug(r.SeatLog(r.GetSeat(user.UID), "玩家托管状态变更: %s", util.Tie(enable, "启用", "关闭")))
|
||
|
||
}
|
||
|
||
// 通知玩家行动
|
||
func (r *TrucoRoom) notifyPlayerAct() {
|
||
// 向玩家发送消息
|
||
rsp := &proto.NtfPlayerAct{
|
||
RoomId: r.Id(),
|
||
Seat: r.current,
|
||
Countdown: r.RoomCnf.ActTime,
|
||
CountdownEx: stub.GGlobal.TrucoActExTime,
|
||
CanCall: 0,
|
||
CanGiveUp: 0,
|
||
}
|
||
color := r.teamColor(r.current)
|
||
if truco, code := r.canRaise(color, true, false); code == proto.Ok {
|
||
rsp.CanCall = truco.ToInt(r.PlayType())
|
||
}
|
||
if code := r.canGiveUp(color, true, false); code == proto.Ok {
|
||
rsp.CanGiveUp = 1
|
||
}
|
||
log.Debug(r.Log("seat:%v 通知出牌, 消息:%+v", r.current, rsp))
|
||
r.Broadcast(proto.NtfPlayerActId, rsp, true)
|
||
r.gameStep = GsPlayerAct
|
||
r.isActTeam = false
|
||
|
||
// 牌局回顾
|
||
r.record.AddAction(proto.NtfPlayerActId, rsp)
|
||
}
|
||
|
||
// 最近一轮的叫分状态
|
||
func (r *TrucoRoom) lastTeamAct(color TeamColor) *TeamAct {
|
||
if len(r.actTypes) == 0 {
|
||
return nil
|
||
}
|
||
if color == TcUnknown {
|
||
return r.actTypes[len(r.actTypes)-1]
|
||
}
|
||
for end := len(r.actTypes) - 1; end >= 0; end-- {
|
||
if r.actTypes[end].color == color {
|
||
return r.actTypes[end]
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 队伍的第一个操作
|
||
func (r *TrucoRoom) firstTeamAct(color TeamColor) *TeamAct {
|
||
if len(r.actTypes) == 0 {
|
||
return nil
|
||
}
|
||
if color == TcUnknown {
|
||
return r.actTypes[0]
|
||
}
|
||
for _, act := range r.actTypes {
|
||
if act.color == color {
|
||
return act
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 是否能放弃
|
||
// 一个回合里,一方喊过truco,就不能再放弃。另一方可以放弃
|
||
// 对方累积分数+当前分数>=12分则不能放弃
|
||
func (r *TrucoRoom) canGiveUp(color TeamColor, isTruco, isClient bool) proto.ErrorCode {
|
||
// 决胜手队伍在决胜手操作时没有放弃,之后第一回合行动时,不能放弃
|
||
if r.points[color] == r.pointType.DecidingPoint() && r.round == 0 {
|
||
if isClient {
|
||
log.Error(r.Log("can not sendRaise. our team record point:%v", r.points[color]))
|
||
}
|
||
return proto.BadAction
|
||
}
|
||
// 对方决胜手,我方不能放弃,不能truco,只能出牌
|
||
if r.points[r.rivalColor2(color)] == r.pointType.DecidingPoint() {
|
||
if isClient {
|
||
log.Error(r.Log("can not sendRaise. our team record point:%v", r.points[color]))
|
||
}
|
||
return proto.BadAction
|
||
}
|
||
if r.points[r.rivalColor2(color)]+r.point >= stub.GGlobal.TrucoWinPoint {
|
||
return proto.BadAction
|
||
}
|
||
// 最后操作是放弃或同意,则发起truco方不能再放弃
|
||
if act := r.lastTeamAct(TcUnknown); act != nil && (act.maxAct == AtGiveUp || act.maxAct == AtAgree) {
|
||
if firstAct := r.firstTeamAct(TcUnknown); firstAct != nil && firstAct.color == color {
|
||
return proto.BadAction
|
||
}
|
||
}
|
||
if isTruco && r.lastTrucoColor == color {
|
||
return proto.BadAction
|
||
}
|
||
return proto.Ok
|
||
}
|
||
|
||
// 判断是否能加分
|
||
func (r *TrucoRoom) canRaise(color TeamColor, isTruco, isClient bool) (ActType, proto.ErrorCode) {
|
||
// 决胜局不能truco
|
||
if r.decidingTeam != TcUnknown {
|
||
if isClient {
|
||
log.Error(r.Log("can not sendRaise. our team record point:%v", r.points[color]))
|
||
}
|
||
return AtUnknown, proto.BadAction
|
||
}
|
||
// 叫分不能超过12分
|
||
if r.points[color]+r.point >= stub.GGlobal.TrucoWinPoint {
|
||
if isClient {
|
||
log.Error(r.Log("can not sendRaise. our team record point:%v, current point:%v is error", r.points[color], r.point))
|
||
}
|
||
return AtUnknown, proto.BadAction
|
||
}
|
||
// 本局游戏,对方有同意,则我方不能再发起truco
|
||
rivalColor := r.rivalColor2(color)
|
||
if isTruco && r.agreeStatus[rivalColor] == AtAgree {
|
||
if isClient {
|
||
log.Error(r.Log("can not sendRaise. rival team was agree"))
|
||
}
|
||
return AtUnknown, proto.BadAction
|
||
}
|
||
|
||
// 一回合中只能有一次truco
|
||
if act := r.lastTeamAct(TcUnknown); act != nil && isTruco {
|
||
if isClient {
|
||
log.Error(r.Log("can not truco. lastTrucoRound==round:%v", r.round))
|
||
}
|
||
return AtUnknown, proto.BadAction
|
||
}
|
||
|
||
if r.point == r.pointType.GameStartPoint() {
|
||
return AtTruco3, proto.Ok
|
||
}
|
||
return IntToActType(r.pointType.NextPoint(r.point)), proto.Ok
|
||
}
|
||
|
||
// 判断是否能同意
|
||
func (r *TrucoRoom) canAgree(color TeamColor) proto.ErrorCode {
|
||
// 决胜手队伍在决胜手操作时没有放弃,之后第一回合行动时,不能放弃
|
||
if r.points[color] == r.pointType.DecidingPoint() && r.round == 0 {
|
||
return proto.Ok
|
||
}
|
||
if len(r.actTypes) <= 1 {
|
||
log.Error(r.Log("can not agree. rival team status was not sendRaise"))
|
||
return proto.BadAction
|
||
}
|
||
// 敌方颜色
|
||
rivalColor := r.rivalColor2(color)
|
||
rivalAct := r.lastTeamAct(rivalColor)
|
||
// 对方没有加分,则我方不能同意
|
||
if rivalAct.maxAct == AtAgree || rivalAct.maxAct == AtGiveUp {
|
||
log.Error(r.Log("can not agree. rival team status was not sendRaise"))
|
||
return proto.BadAction
|
||
}
|
||
return proto.Ok
|
||
}
|
||
|
||
// 判断是否能同意
|
||
func (r *TrucoRoom) canOutPoker() bool {
|
||
if len(r.actTypes) > 0 {
|
||
maxAct := r.lastTeamAct(TcUnknown).maxAct
|
||
if maxAct != AtGiveUp && maxAct != AtAgree {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
}
|
||
|
||
// 记录玩家叫分操作
|
||
func (r *TrucoRoom) gameLogAddAct(color TeamColor, act ActType, seatNo int) {
|
||
switch act {
|
||
case AtTruco3:
|
||
if len(r.actTypes) == 1 {
|
||
r.gameLog.TrucoPlayers[seatNo].Raise++
|
||
} else {
|
||
r.gameLog.TrucoPlayers[seatNo].ContinueRaise++
|
||
}
|
||
case AtGiveUp:
|
||
r.gameLog.TrucoPlayers[seatNo].GiveUp++
|
||
case AtAgree:
|
||
r.gameLog.TrucoPlayers[seatNo].Agree++
|
||
}
|
||
if len(r.actTypes) > 1 {
|
||
teamAct := r.lastTeamAct(color)
|
||
// 行动一致
|
||
concert := true
|
||
for _, otherAct := range teamAct.actType {
|
||
if otherAct != act {
|
||
concert = false
|
||
}
|
||
}
|
||
if concert {
|
||
r.gameLog.Teams[color].Concert++
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新队伍操作及队伍叫分状态
|
||
func (r *TrucoRoom) addTeamAct() *TeamAct {
|
||
teamAct := r.lastTeamAct(TcUnknown)
|
||
color := r.rivalColor2(teamAct.color)
|
||
teamAct = newTeamAct(color)
|
||
r.actTypes = append(r.actTypes, teamAct)
|
||
return teamAct
|
||
}
|
||
|
||
// 更新队伍操作及队伍叫分状态
|
||
func (r *TrucoRoom) getActTimeType() TimerType {
|
||
// 首个操作,且不是决胜局,则是玩家主动truco,不需要等待队友操作
|
||
if len(r.actTypes) == 1 && r.decidingTeam == TcUnknown {
|
||
return TtPlayerAct
|
||
}
|
||
teamAct := r.lastTeamAct(TcUnknown)
|
||
// 本队所有人都做出了选择
|
||
if len(teamAct.actType) == r.RoomCnf.MinPlayers/2 {
|
||
// 决胜局首个操作
|
||
if len(r.actTypes) == 1 && r.decidingTeam != TcUnknown {
|
||
return TtDecidingGame
|
||
} else {
|
||
return TtPlayerRspRaise
|
||
}
|
||
}
|
||
return TtUnknown
|
||
}
|
||
|
||
func (r *TrucoRoom) clearAllAct() {
|
||
r.actTypes = r.actTypes[0:0]
|
||
}
|
||
|
||
// 对方喊truco,我方同意,对方出牌,轮到我时,我可以放弃
|
||
func (r *TrucoRoom) canGiveUpAfterAgree(color TeamColor, act ActType, _ int) bool {
|
||
if act != AtGiveUp {
|
||
return false
|
||
}
|
||
// 最后操作是放弃或同意,则发起truco方不能再放弃
|
||
lastTeamAct := r.lastTeamAct(TcUnknown)
|
||
if lastTeamAct == nil || lastTeamAct.maxAct != AtAgree {
|
||
return false
|
||
}
|
||
if firstAct := r.firstTeamAct(TcUnknown); firstAct != nil && firstAct.color == color {
|
||
return false
|
||
}
|
||
// 同意后轮到,发起truco方出手,他只能出牌,换手后对方可以放弃,所以这里不需要检查同意与放弃之间是否有人出牌。逻辑上保证了中间一定有人出牌了
|
||
return true
|
||
}
|
||
|
||
// 更新队伍操作及队伍叫分状态
|
||
func (r *TrucoRoom) updateTeamAct(color TeamColor, act ActType, seatNo int) {
|
||
if len(r.actTypes) == 0 && act == AtAgree && r.points[color] != r.pointType.DecidingPoint() {
|
||
log.Error(r.SeatLog(r.Seats[seatNo], "第一次只能叫分或放弃,不能同意"))
|
||
return
|
||
}
|
||
// 更新叫分状态,第一个叫分或放弃,队友无需操作
|
||
if len(r.actTypes) == 0 {
|
||
teamAct := newTeamAct(color)
|
||
teamAct.maxAct = act
|
||
if r.IsMVM() && !r.isActTeam {
|
||
teammates := r.Teammate(seatNo)
|
||
for _, st := range teammates {
|
||
teamAct.actType[st.No()] = act
|
||
}
|
||
}
|
||
r.actTypes = append(r.actTypes, teamAct)
|
||
}
|
||
// 通知玩家回应加注时已经添加过teamAct,这里不会为nil
|
||
teamAct := r.lastTeamAct(color)
|
||
if teamAct == nil {
|
||
log.Error(r.SeatLog(r.Seats[seatNo], "team:%v act is nil", color))
|
||
return
|
||
}
|
||
if _, ok := teamAct.actType[seatNo]; ok {
|
||
if r.canGiveUpAfterAgree(color, act, seatNo) {
|
||
teamAct = newTeamAct(color)
|
||
r.actTypes = append(r.actTypes, teamAct)
|
||
for _, seat := range r.Seats {
|
||
if r.teamColor(seat.No()) == color {
|
||
teamAct.actType[seat.No()] = act
|
||
}
|
||
}
|
||
teamAct.maxAct = act
|
||
} else {
|
||
log.Error(r.SeatLog(r.Seats[seatNo], "team:%v repeat operation", color))
|
||
return
|
||
}
|
||
}
|
||
teamAct.actType[seatNo] = act
|
||
if teamAct.maxAct < act {
|
||
teamAct.maxAct = act
|
||
}
|
||
|
||
if len(teamAct.actType) == r.RoomCnf.MinPlayers/2 {
|
||
if len(r.actTypes) > 1 || r.decidingTeam != TcUnknown {
|
||
if teamAct.maxAct == AtAgree {
|
||
r.agreeStatus[teamAct.color] = AtAgree
|
||
}
|
||
if teamAct.maxAct != AtGiveUp {
|
||
oldPoint := r.point
|
||
r.point = r.pointType.NextPoint(r.point)
|
||
if oldPoint != r.point {
|
||
log.Debug(r.Log("point from:%v to %v", oldPoint, r.point))
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
r.gameLogAddAct(color, act, seatNo)
|
||
}
|
||
|
||
// 通知玩家回应对方的叫分
|
||
func (r *TrucoRoom) notifyPlayerRspRaise() {
|
||
r.isActTeam = true
|
||
teamAct := r.addTeamAct()
|
||
enemyAct := r.lastTeamAct(r.rivalColor2(teamAct.color))
|
||
// 向玩家发送消息
|
||
rsp := &proto.NtfPlayerRspRaise{
|
||
TeamColor: int(teamAct.color),
|
||
Countdown: r.RoomCnf.ActTime,
|
||
CountdownEx: stub.GGlobal.TrucoActExTime,
|
||
Enemy: AtUnknown.ToInt(r.PlayType()),
|
||
Ally: nil,
|
||
CanRaise: 0,
|
||
}
|
||
point := r.pointType.NextPoint(r.point)
|
||
log.Debug(r.Log("r.points[teamAct.color]:%v + point:%v<%v", r.points[teamAct.color], point, stub.GGlobal.TrucoWinPoint))
|
||
if r.points[teamAct.color]+point < stub.GGlobal.TrucoWinPoint {
|
||
rsp.CanRaise = IntToActType(r.pointType.NextPoint(point)).ToInt(r.PlayType())
|
||
}
|
||
if enemyAct != nil {
|
||
rsp.Enemy = enemyAct.maxAct.ToInt(r.PlayType())
|
||
}
|
||
log.Debug(r.Log("通知队伍回应:%v 消息:%+v", teamAct.color, rsp))
|
||
r.Broadcast(proto.NtfPlayerRspRaiseId, rsp, true)
|
||
|
||
// 牌局回顾
|
||
r.record.AddAction(proto.NtfPlayerRspRaiseId, rsp)
|
||
}
|
||
|
||
// 回合结束,判断是否需要进入比牌
|
||
func (r *TrucoRoom) isRoundOver() bool {
|
||
for _, seat := range r.Seats {
|
||
if seat.OutPoker == nil {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
}
|
||
|
||
// 比牌,返回最大牌的位置及队伍颜色,以及相同大牌的座位
|
||
// cmpResult只有相等才需要处理(平局)
|
||
func (r *TrucoRoom) cmpPoker() (maxPokerSeatNo int, maxColor TeamColor, cmpResult GameLight, maxPokerSeats []int) {
|
||
begin := r.roundStartPos
|
||
maxPokerSeatNo = begin
|
||
|
||
// 找出双方各自最大牌
|
||
maxSeats := make([]*TrucoSeat, 2)
|
||
for i := begin; i < begin+len(r.Seats); i++ {
|
||
seatNo := i % len(r.Seats)
|
||
if r.Seats[seatNo].Empty() {
|
||
continue
|
||
}
|
||
color := r.teamColor(seatNo)
|
||
if maxSeats[color] == nil {
|
||
maxSeats[color] = r.Seats[seatNo]
|
||
} else {
|
||
// Cmp p1<p2:CppSmall
|
||
cmpRet := r.pokers.Cmp(maxSeats[color].OutPoker, r.Seats[seatNo].OutPoker)
|
||
if cmpRet == poker.CppSmall {
|
||
maxSeats[color] = r.Seats[seatNo]
|
||
}
|
||
}
|
||
}
|
||
// 比较红绿双方谁大谁小
|
||
cmpRet := r.pokers.Cmp(maxSeats[TcRed].OutPoker, maxSeats[TcGreen].OutPoker)
|
||
// Cmp p1<p2:CppSmall
|
||
switch cmpRet {
|
||
case poker.CppSmall:
|
||
maxPokerSeatNo = r.Seats[TcGreen].No()
|
||
cmpResult = GlGreen
|
||
maxColor = r.teamColor(maxPokerSeatNo)
|
||
case poker.CppBig:
|
||
maxPokerSeatNo = r.Seats[TcRed].No()
|
||
cmpResult = GlRed
|
||
maxColor = r.teamColor(maxPokerSeatNo)
|
||
case poker.CppEqual:
|
||
/*
|
||
普通平/普通平/普通平,最终结果为平
|
||
普通平/普通平/(特殊平),最终要决胜负
|
||
普通平/特殊平/(普通平),最终要决胜负,需要拉取之前喊truco和接受的数据
|
||
普通平/特殊平/(特殊平),最终要决胜负
|
||
特殊平/普通平/(普通平),最终要决胜负,需要拉取之前喊truco和接受的数据
|
||
特殊平/普通平/(特殊平),最终要决胜负
|
||
特殊平/(特殊平),最终要决胜负
|
||
*/
|
||
switch r.round {
|
||
case 0:
|
||
/*
|
||
第一轮:
|
||
无限制,会出现普通平或者特殊平,即第一轮中无论是否喊了truco,如果双方出了一样的牌,就算平局
|
||
*/
|
||
switch r.lastTrucoColor {
|
||
case TcUnknown:
|
||
cmpResult = GlNormalYellow
|
||
default:
|
||
cmpResult = util.Tie(r.lastTrucoColor == TcGreen, GlGreenYellow, GlRedYellow)
|
||
}
|
||
case 1:
|
||
/*
|
||
第二轮:
|
||
假如双方出了一样的牌,那么需要首先检测【有没有发生过特殊平】,其次要检测【这轮有没有喊过truco】:
|
||
1.如果之前没有发生过特殊平且这轮也没有喊过,那这轮就是普通平
|
||
2.如果之前没有发生过特殊平但是这轮有喊过,那这轮就是特殊平
|
||
3.如果之前发生过特殊平但是本轮没有喊过,那这轮就是普通平
|
||
4.如果之前发生过特殊平并且本轮也喊过,那就一定要决胜负,就不会有第三轮了
|
||
*/
|
||
if r.light[0] == GlNormalYellow { // 第一轮普通平,本轮普通平或特殊平
|
||
switch r.lastTrucoColor {
|
||
case TcUnknown:
|
||
cmpResult = GlNormalYellow
|
||
default:
|
||
cmpResult = util.Tie(r.lastTrucoColor == TcGreen, GlGreenYellow, GlRedYellow)
|
||
}
|
||
} else if r.light[0] == GlGreenYellow || r.light[0] == GlRedYellow { // 第一轮特殊平,本轮要么普通平,要么决胜负
|
||
switch r.lastTrucoColor {
|
||
case TcUnknown:
|
||
cmpResult = GlNormalYellow
|
||
default:
|
||
// 特殊平时喊truco方判定输
|
||
cmpResult = util.Tie(r.lastTrucoColor == TcGreen, GlRed, GlGreen)
|
||
}
|
||
} else {
|
||
switch r.lastTrucoColor {
|
||
case TcUnknown:
|
||
cmpResult = GlNormalYellow
|
||
default:
|
||
cmpResult = util.Tie(r.lastTrucoColor == TcGreen, GlGreenYellow, GlRedYellow)
|
||
}
|
||
}
|
||
default:
|
||
/*
|
||
第三轮:
|
||
假如双方出了一样的牌,那么需要首先检测【有没有发生过特殊平】,其次要检测【这轮有没有喊过truco】:
|
||
1.如果之前没有发生过特殊平且这轮也没有喊过,那这轮就是普通平
|
||
2.如果之前没有发生过特殊平但是这轮有喊过,【那必须要决胜负】
|
||
3.如果之前发生过特殊平但是本轮没有喊过,【那必须要决胜负】
|
||
4.如果之前发生过特殊平并且本轮也喊过,那就一定要决胜负
|
||
*/
|
||
if r.light[0] == GlNormalYellow && r.light[1] == GlNormalYellow {
|
||
if r.lastTrucoColor == TcUnknown {
|
||
cmpResult = GlNormalYellow
|
||
} else {
|
||
cmpResult = util.Tie(r.lastTrucoColor == TcGreen, GlRed, GlGreen)
|
||
}
|
||
} else {
|
||
if r.lastTrucoColor == TcUnknown {
|
||
// 前两轮一定有一个特殊平,先找出特殊平
|
||
cmpResult = util.Tie(r.light[0] == GlNormalYellow, r.light[1], r.light[0])
|
||
// 特殊平时喊truco方判定输
|
||
cmpResult = util.Tie(cmpResult == GlGreenYellow, GlRed, GlGreen)
|
||
} else {
|
||
cmpResult = util.Tie(r.lastTrucoColor == TcGreen, GlRed, GlGreen)
|
||
}
|
||
}
|
||
}
|
||
if cmpResult.Color() == GlNormalYellow {
|
||
maxColor = r.teamColor(begin)
|
||
maxPokerSeatNo = r.Seats[maxColor].No()
|
||
} else {
|
||
maxColor = util.Tie(cmpResult == GlRed, TcRed, TcGreen)
|
||
maxPokerSeatNo = r.Seats[maxColor].No()
|
||
}
|
||
}
|
||
for _, seat := range r.Seats {
|
||
cmpRet = r.pokers.Cmp(r.Seats[maxPokerSeatNo].OutPoker, seat.OutPoker)
|
||
if cmpRet == poker.CppEqual {
|
||
maxPokerSeats = append(maxPokerSeats, seat.No())
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// 比牌时打印玩家牌
|
||
func (r *TrucoRoom) debugAllOutPoker() string {
|
||
begin := r.current
|
||
outPokers := "" // 各玩家出的牌
|
||
for i := begin; i < begin+len(r.Seats); i++ {
|
||
no := i % len(r.Seats)
|
||
if r.Seats[no].Empty() {
|
||
continue
|
||
}
|
||
outPokers += fmt.Sprintf("seat:%v poker:%v ", no, r.Seats[no].OutPoker.ToString())
|
||
}
|
||
return outPokers
|
||
}
|
||
|
||
// 回合结算广播
|
||
func (r *TrucoRoom) notifyRoundSettle(color TeamColor, cmpResult GameLight, maxSeatNo []int) {
|
||
//log.Debug(r.Log("比牌"))
|
||
r.gameStep = GsCmpPoker
|
||
r.light = append(r.light, cmpResult)
|
||
ntf := &proto.NtfRoundSettle{MaxSeat: maxSeatNo}
|
||
// (0:红灯 1:绿灯 2:黄灯)
|
||
switch cmpResult {
|
||
case GlGreen:
|
||
ntf.Settle = 1
|
||
case GlRed:
|
||
ntf.Settle = 0
|
||
default:
|
||
ntf.Settle = 2
|
||
}
|
||
log.Debug(r.Log("%v队胜率 广播比牌:%v", color, ntf))
|
||
r.Broadcast(proto.NtfRoundSettleId, ntf, false)
|
||
r.round++
|
||
r.lastTrucoColor = TcUnknown
|
||
|
||
// 牌局回顾
|
||
r.record.AddAction(proto.NtfRoundSettleId, ntf)
|
||
}
|
||
|
||
// 回合结算,返回true则小结算后进入大结算
|
||
func (r *TrucoRoom) roundSettle() bool {
|
||
seatNo, color, cmpResult, maxSeatNos := r.cmpPoker()
|
||
// 比牌打印
|
||
log.Debug(r.Log("比牌,所有出牌:%v, 比牌规则:%v", r.debugAllOutPoker(), r.pokers.DebugSortPoker()))
|
||
|
||
r.current = seatNo
|
||
r.roundStartPos = r.current
|
||
r.notifyRoundSettle(color, cmpResult, maxSeatNos)
|
||
|
||
if len(r.light) == 2 {
|
||
// 2红或2绿则直接本局结算
|
||
if r.light[0] == r.light[1] && r.light[0].Color() != GlNormalYellow {
|
||
return true
|
||
}
|
||
// 1胜1平则直接本局结算
|
||
if r.light[0].Color() != GlNormalYellow && r.light[1].Color() == GlNormalYellow {
|
||
return true
|
||
}
|
||
// 1平1胜则直接本局结算
|
||
if r.light[0].Color() == GlNormalYellow && r.light[1].Color() != GlNormalYellow {
|
||
return true
|
||
}
|
||
}
|
||
if len(r.Seats[seatNo].Pokers) == 0 {
|
||
return true
|
||
}
|
||
log.Debug(r.Log("清理所有出牌"))
|
||
// 清理所有玩家出的牌
|
||
for _, seat := range r.Seats {
|
||
seat.OutPoker = nil
|
||
}
|
||
// 清理本回合所有叫分操作
|
||
r.clearAllAct()
|
||
r.NewTimer(TtCmpPoker, time.Duration(stub.GGlobal.TrucoCmpPokerTime)*time.Second, r.Seats[seatNo].Player())
|
||
return false
|
||
}
|
||
|
||
// 保存战绩
|
||
func (r *TrucoRoom) SaveRecord(gameRecordPlayerInfos []*proto.GameRecordPlayerInfo) {
|
||
// 为nil表示解散房间保存的战绩
|
||
if len(gameRecordPlayerInfos) == 0 {
|
||
for _, seat := range r.Seats {
|
||
if seat.Empty() {
|
||
continue
|
||
}
|
||
gameRecordPlayerInfos = append(gameRecordPlayerInfos, &proto.GameRecordPlayerInfo{UId: seat.Player().UID, Win: 0, Disband: int(seat.disband)})
|
||
}
|
||
}
|
||
|
||
for _, seat := range r.Seats {
|
||
if seat.Empty() {
|
||
continue
|
||
}
|
||
var playerInfo *proto.GameRecordPlayerInfo
|
||
for _, info := range gameRecordPlayerInfos {
|
||
if info.UId == seat.Player().UID {
|
||
playerInfo = info
|
||
break
|
||
}
|
||
}
|
||
if playerInfo != nil {
|
||
// 牌局回顾
|
||
r.record.AddPlayerRecord(r, seat.Player().UID, r.GetTakeCoin(seat.Player()), playerInfo.Win, gameRecordPlayerInfos)
|
||
if r.ClubId() == 0 {
|
||
r.gameLog.TrucoPlayers[seat.No()].EndCoin = r.GetTakeCoin(seat.Player())
|
||
} else {
|
||
sumScore, _, _, _ := r.GetUserClubScore(seat.Player().UID)
|
||
r.gameLog.TrucoPlayers[seat.No()].EndCoin = sumScore
|
||
}
|
||
|
||
r.gameLog.TrucoPlayers[seat.No()].WinCoin = playerInfo.Win
|
||
}
|
||
}
|
||
|
||
r.gameLog.EndTime = r.endTime.Unix()
|
||
|
||
r.record.Flush()
|
||
r.gameLog.Flush()
|
||
}
|
||
|
||
// 破产判断
|
||
func (r *TrucoRoom) isBankrupt(seat *TrucoSeat, myWin int64) (*proto.NtfBankrupt, bool) {
|
||
if seat.Player().IsRobot() {
|
||
return nil, false
|
||
}
|
||
if r.ClubId() > 0 {
|
||
return nil, false
|
||
}
|
||
uid := seat.Player().UID
|
||
if !model.UserIsBankrupt(uid, myWin) {
|
||
return nil, false
|
||
}
|
||
ntf, err := model.NewBankruptNtfMsg(uid)
|
||
if err != nil {
|
||
log.Error(fmt.Sprintf("生成破产通知失败:%v", err))
|
||
return nil, false
|
||
}
|
||
return ntf, true
|
||
}
|
||
|
||
// 按座位结算
|
||
func (r *TrucoRoom) bigSettlementBySeat(seat *TrucoSeat, myWin, tip, inoutAdd, moneyAdd int64) (moneyCost, freeCost, inoutCost int64) {
|
||
r.addResource(seat.Player(), myWin, model.ResTakeCoins, model.ReasonGame)
|
||
if r.ClubId() > 0 {
|
||
if myWin < 0 {
|
||
moneyCost, freeCost, inoutCost = r.CostUserClubScore(seat.Player().UID, -myWin)
|
||
moneyCost = -moneyCost
|
||
freeCost = -freeCost
|
||
inoutCost = -inoutCost
|
||
log.Debug(r.SeatLog(seat, "净胜分:%v 其中免费积分:%v 可提现积分:%v 充值积分:%v", myWin, freeCost, inoutCost, moneyCost))
|
||
} else {
|
||
// tip先扣可提现积分
|
||
inoutTip := util.Tie(inoutAdd < tip, inoutAdd, tip)
|
||
inoutAdd -= inoutTip
|
||
tip -= inoutTip
|
||
// 最后扣俱乐部积分
|
||
moneyAdd -= tip
|
||
r.AddUserResource(seat.Player().UID, moneyAdd, model.ResClubUserScore, model.ReasonGame)
|
||
r.AddUserResource(seat.Player().UID, inoutAdd, model.ResClubUserInOutFreeScore, model.ReasonGame)
|
||
moneyCost = moneyAdd
|
||
inoutCost = inoutAdd
|
||
log.Debug(r.SeatLog(seat, "净胜分:%v 其中免费积分:%v 可提现积分:%v 充值积分:%v", myWin, freeCost, inoutCost, moneyCost))
|
||
}
|
||
} else {
|
||
r.addResource(seat.Player(), myWin, model.ResCoins, model.ReasonGame)
|
||
}
|
||
return
|
||
}
|
||
|
||
// 按队伍颜色结算 cost:扣除金币 tip:台费
|
||
func (r *TrucoRoom) bigSettlementByColor(winColor TeamColor, cost, tip int64) []*proto.GameRecordPlayerInfo {
|
||
gameRecordPlayerInfos := make([]*proto.GameRecordPlayerInfo, 0)
|
||
var inoutAdd, moneyAdd, myWin int64
|
||
// 先结算输家
|
||
for _, seat := range r.Seats {
|
||
if seat.Empty() || r.teamColor(seat.No()) == winColor {
|
||
continue
|
||
}
|
||
myWin = -cost
|
||
aMoneyAdd, aFreeAdd, aInoutAdd := r.bigSettlementBySeat(seat, myWin, 0, 0, 0)
|
||
inoutAdd -= aFreeAdd + aInoutAdd
|
||
moneyAdd -= aMoneyAdd
|
||
gameRecordPlayerInfos = append(gameRecordPlayerInfos, &proto.GameRecordPlayerInfo{UId: seat.Player().UID, Win: myWin, Disband: int(seat.disband)})
|
||
r.gameLog.TrucoPlayers[seat.No()].FreeScore = aFreeAdd
|
||
r.gameLog.TrucoPlayers[seat.No()].InoutScore = aInoutAdd
|
||
r.gameLog.TrucoPlayers[seat.No()].MoneyScore = aMoneyAdd
|
||
}
|
||
|
||
dividend := int64(len(r.Seats) / 2) // 每人能分多少分 1v1分对方的全部,2v2每人分总数的1/2
|
||
|
||
// 再结算赢家
|
||
for _, seat := range r.Seats {
|
||
if seat.Empty() || r.teamColor(seat.No()) != winColor {
|
||
continue
|
||
}
|
||
myWin = cost - tip
|
||
aInoutAdd, aMoneyAdd := inoutAdd/dividend, moneyAdd/dividend
|
||
aMoneyAdd, _, aInoutAdd = r.bigSettlementBySeat(seat, myWin, tip, aInoutAdd, aMoneyAdd)
|
||
gameRecordPlayerInfos = append(gameRecordPlayerInfos, &proto.GameRecordPlayerInfo{UId: seat.Player().UID, Win: myWin, Disband: int(seat.disband)})
|
||
r.gameLog.TrucoPlayers[seat.No()].InoutScore = aInoutAdd
|
||
r.gameLog.TrucoPlayers[seat.No()].MoneyScore = aMoneyAdd
|
||
}
|
||
return gameRecordPlayerInfos
|
||
}
|
||
|
||
func (r *TrucoRoom) bigSettlement() {
|
||
winColor := util.Tie[TeamColor](r.points[GlRed] > r.points[GlGreen], TcRed, TcGreen)
|
||
// 扣除金币
|
||
cost := r.RoomCnf.Blind * int64(r.star)
|
||
// 台费
|
||
tip := cost * int64(r.RoomCnf.Rate) / int64(100)
|
||
gameRecordPlayerInfos := r.bigSettlementByColor(winColor, cost, tip)
|
||
|
||
var teamMembers []*proto.TeamMember
|
||
bankruptSeats := map[int]*proto.NtfBankrupt{}
|
||
allTip := int64(0)
|
||
for _, seat := range r.Seats {
|
||
if seat.Empty() {
|
||
continue
|
||
}
|
||
// 净胜分
|
||
myWin := util.Tie(r.teamColor(seat.No()) == winColor, cost-tip, -cost)
|
||
if myWin > 0 {
|
||
allTip += tip
|
||
}
|
||
r.gameLog.TrucoPlayers[seat.No()].Tip = tip
|
||
//log.Info(r.SeatLog(seat, "赢取金币:%v", myWin))
|
||
// 机器人输赢汇入总池
|
||
if seat.Player().IsRobot() {
|
||
model.AddRobotResourcePool(r.Type(), myWin, util.Tie[string](r.ClubId() <= 0, model.ResCoins, model.ResClubUserScore))
|
||
}
|
||
|
||
if ntf, ok := r.isBankrupt(seat, myWin); ok {
|
||
bankruptSeats[seat.No()] = ntf
|
||
}
|
||
|
||
//r.addResource(seat.Player(), myWin, model.ResTakeCoins, model.ReasonGame)
|
||
//r.addResource(seat.Player(), myWin, model.ResCoins, model.ReasonGame)
|
||
color := r.teamColor(seat.No())
|
||
teamMembers = append(teamMembers, &proto.TeamMember{
|
||
Seat: seat.No(),
|
||
WinCoin: myWin,
|
||
Color: int(color),
|
||
Fee: util.Tie(myWin > 0, tip, 0),
|
||
})
|
||
|
||
log.Info(r.SeatLog(seat, "净胜分:%v take coin:%v", myWin, r.GetTakeCoin(seat.Player())))
|
||
}
|
||
for _, seat := range r.Seats {
|
||
if seat.Empty() {
|
||
continue
|
||
}
|
||
r.notifySettlement(teamMembers, seat, winColor)
|
||
if ntf, ok := bankruptSeats[seat.No()]; ok {
|
||
r.SendMsg(seat.Player(), proto.NtfBankruptId, ntf, false)
|
||
sum, err := model.NewUserStreakOp().UpdateBankruptStreak(seat.Player().UID)
|
||
if sum >= 3 {
|
||
// TODO 可以提取到stub
|
||
// 连续破产三次
|
||
_, err = model.NewUserLuckyPointOp().Add(seat.Player().UID, 20)
|
||
log.Debug(fmt.Sprintf("连续破产%d次,增加幸运值", sum))
|
||
}
|
||
if err != nil {
|
||
log.Error(fmt.Sprintf("更新连续破产失败:%v", err))
|
||
}
|
||
|
||
}
|
||
}
|
||
r.ClubSettlement(allTip)
|
||
r.SaveRecord(gameRecordPlayerInfos)
|
||
}
|
||
|
||
func (r *TrucoRoom) notifySettlement(members []*proto.TeamMember, seat *TrucoSeat, winColor TeamColor) {
|
||
ntf := &proto.NtfGameBigSettle{
|
||
Team: members,
|
||
Star: r.star,
|
||
Seat: seat.No(),
|
||
Color: int(r.teamColor(seat.No())),
|
||
Rate: r.RoomCnf.Rate,
|
||
Blind: r.RoomCnf.Blind,
|
||
Win: util.Tie(winColor == r.teamColor(seat.No()), 1, 0),
|
||
Points: r.points,
|
||
}
|
||
//log.Debug(r.Log("NtfGameBigSettle:%+v", ntf))
|
||
r.SendMsg(seat.Player(), proto.NtfGameBigSettleId, ntf, false)
|
||
r.record.AddAction(proto.NtfGameBigSettleId, ntf)
|
||
var err error
|
||
if ntf.Win == 1 {
|
||
// 赢了,清除连败
|
||
err = model.NewUserStreakOp().SetLossStreak(seat.Player().UID, stub.Truco, 0)
|
||
} else {
|
||
// 记录连败
|
||
var loss int64
|
||
loss, err = model.NewUserStreakOp().IncLossStreak(seat.Player().UID, stub.Truco, 1)
|
||
if loss >= 3 {
|
||
// 连续输掉三次,增加幸运值
|
||
// TODO 可以提取到stub
|
||
_, err = model.NewUserLuckyPointOp().Add(seat.Player().UID, 20)
|
||
log.Debug(fmt.Sprintf("连续输掉%d次,增加幸运值", loss))
|
||
}
|
||
}
|
||
if err != nil {
|
||
log.Error(fmt.Sprintf("更新连败失败:%v", err))
|
||
}
|
||
|
||
}
|
||
|
||
// 广播结算
|
||
func (r *TrucoRoom) notifyGameSettle(redWin, greenWin int, nextGame bool) {
|
||
ng := 0
|
||
if nextGame {
|
||
ng = 1
|
||
}
|
||
// 向玩家发送消息
|
||
rsp := &proto.NtfGameSettle{Settle: make([]int, 2), NextGame: ng}
|
||
rsp.Settle[GlRed] = redWin
|
||
rsp.Settle[GlGreen] = greenWin
|
||
r.Broadcast(proto.NtfGameSettleId, rsp, false)
|
||
|
||
// 牌局回顾
|
||
r.record.AddAction(proto.NtfGameSettleId, rsp)
|
||
}
|
||
|
||
func (r *TrucoRoom) settlePoint() (redWin, greenWin int) {
|
||
redLightCount := 0
|
||
greenLightCount := 0
|
||
for _, light := range r.light {
|
||
if light == GlRed {
|
||
redLightCount++
|
||
} else if light == GlGreen {
|
||
greenLightCount++
|
||
}
|
||
}
|
||
|
||
if redLightCount > greenLightCount {
|
||
redWin = r.point
|
||
} else if redLightCount == greenLightCount {
|
||
// 平平平,双方不得分
|
||
if redLightCount == 0 {
|
||
return
|
||
} else {
|
||
// 胜负平,先胜为胜
|
||
if r.light[0] == GlRed {
|
||
redWin = r.point
|
||
} else {
|
||
greenWin = r.point
|
||
}
|
||
}
|
||
} else {
|
||
greenWin = r.point
|
||
}
|
||
return
|
||
}
|
||
|
||
// 是否显示按钮
|
||
func (r *TrucoRoom) notifyDisplayShowPoker() int {
|
||
_ = stub.GGlobal.TrucoNextGameTime
|
||
|
||
cd := stub.GGlobal.TrucoNextGameTime
|
||
for _, seat := range r.Seats {
|
||
if len(seat.Pokers) > 0 {
|
||
cd = stub.GGlobal.TrucoNextGameTime + stub.GGlobal.TrucoShowPoker
|
||
break
|
||
}
|
||
}
|
||
//display := 0
|
||
//for _, seat := range r.Seats {
|
||
// display = util.Tie(len(seat.handPoker) > 0, 1, 0)
|
||
// r.SendMsg(seat.Player(), proto.NtfCanShowPokerId, &proto.NtfCanShowPoker{Display: display, CountDown: cd}, false)
|
||
//}
|
||
return cd
|
||
}
|
||
|
||
// GameOver 本局游戏结束,会清理部分数据
|
||
func (r *TrucoRoom) GameOver(seat *TrucoSeat) {
|
||
r.gameStep = GsGameSettle
|
||
//log.Debug(r.Log("cancel timer:all timer"))
|
||
r.CancelAllTimer()
|
||
clear(r.LastMsg)
|
||
|
||
redWin := 0
|
||
greenWin := 0
|
||
if seat == nil {
|
||
redWin, greenWin = r.settlePoint()
|
||
} else {
|
||
// 投降
|
||
color := r.teamColor(seat.No())
|
||
if color == TcRed {
|
||
greenWin = r.point
|
||
} else {
|
||
redWin = r.point
|
||
}
|
||
}
|
||
|
||
//log.Debug(r.Log("清理所有出牌"))
|
||
// 清理玩家出牌
|
||
for _, st := range r.Seats {
|
||
st.OutPoker = nil
|
||
}
|
||
|
||
r.points[GlRed] += redWin
|
||
r.points[GlGreen] += greenWin
|
||
if r.points[GlRed] > stub.GGlobal.TrucoWinPoint {
|
||
r.points[GlRed] = stub.GGlobal.TrucoWinPoint
|
||
}
|
||
if r.points[GlGreen] > stub.GGlobal.TrucoWinPoint {
|
||
r.points[GlGreen] = stub.GGlobal.TrucoWinPoint
|
||
}
|
||
log.Debug(r.Log("对局结束,双方比分:%v", r.points))
|
||
|
||
nextGame := false
|
||
if r.points[GlRed] < stub.GGlobal.TrucoWinPoint && r.points[GlGreen] < stub.GGlobal.TrucoWinPoint {
|
||
nextGame = true
|
||
nextGameCd := r.notifyDisplayShowPoker()
|
||
r.notifyGameSettle(r.points[GlRed], r.points[GlGreen], nextGame)
|
||
// 开启下一局
|
||
r.NewTimer(TtNextGame, time.Duration(nextGameCd)*time.Second)
|
||
return
|
||
}
|
||
// 游戏结束
|
||
r.endTime = time.Now()
|
||
r.notifyGameSettle(r.points[GlRed], r.points[GlGreen], nextGame)
|
||
// 大结算
|
||
r.bigSettlement()
|
||
|
||
r.gameStep = GsWaitGame
|
||
|
||
// 清理玩家信息
|
||
for _, st := range r.Seats {
|
||
if !st.Empty() {
|
||
r.leaveRoom(st)
|
||
}
|
||
}
|
||
r.TryReleaseRoom()
|
||
}
|
||
|
||
// 大牌
|
||
func (r *TrucoRoom) isBigPoker(pk *poker.Poker) bool {
|
||
return r.pokers.IsBigPoker(pk, stub.GGlobalAI.TrucoBiggerPoker)
|
||
}
|
||
|
||
// 离开房间
|
||
func (r *TrucoRoom) 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 *TrucoRoom) notifyFakeLeave(seat *TrucoSeat) {
|
||
ntf := &proto.NtfFakeLeave{
|
||
RoomId: r.Id(),
|
||
CurrentSeat: seat.No(),
|
||
FakeLeave: util.Tie(seat.FakeLeave(), 0, 1),
|
||
}
|
||
r.Broadcast(proto.NtfFakeLeaveId, ntf, false)
|
||
}
|
||
|
||
// 推送房间信息给玩家
|
||
func (r *TrucoRoom) notifyRoomInfo(user *Player) {
|
||
ntf := r.makeProtoRoomInfo()
|
||
r.SendMsg(user, proto.NtfRoomInfoId, ntf, false)
|
||
}
|
||
|
||
// 推送玩家信息给房间里的玩家
|
||
func (r *TrucoRoom) notifyMeToOthers(user *Player) {
|
||
ntf := proto.NtfPlayerInfo{Players: make([]*proto.Player, 0)}
|
||
ntf.Players = append(ntf.Players, r.makePlayerToProto(r.GetSeat(user.UID), true))
|
||
for _, seat := range r.Seats {
|
||
if seat.Player() != nil && seat.Player().UID != user.UID {
|
||
r.SendMsg(seat.Player(), proto.NtfPlayerInfoId, ntf, false)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 推送玩家信息给房间里的玩家
|
||
func (r *TrucoRoom) notifyOthersToMe(user *Player) {
|
||
ntf := proto.NtfPlayerInfo{Players: make([]*proto.Player, 0)}
|
||
for _, seat := range r.Seats {
|
||
if seat.Player() != nil {
|
||
ntf.Players = append(ntf.Players, r.makePlayerToProto(seat, true))
|
||
}
|
||
}
|
||
r.SendMsg(user, proto.NtfPlayerInfoId, ntf, false)
|
||
}
|
||
|
||
// 推送玩家信息给房间里的玩家
|
||
func (r *TrucoRoom) notifyPlayerInfo(user *Player, isReentry bool) {
|
||
if !isReentry {
|
||
r.notifyMeToOthers(user)
|
||
}
|
||
r.notifyOthersToMe(user)
|
||
}
|
||
|
||
func (r *TrucoRoom) SetGmPokers(uid int64, pokers [][]int, ghostPoker int) bool {
|
||
no := 0
|
||
for _, seat := range r.Seats {
|
||
if seat.Player() != nil && seat.Player().UID == uid {
|
||
no = seat.No()
|
||
break
|
||
}
|
||
}
|
||
log.Debug(r.SeatLog(r.Seats[no], "玩家:%v seat:%v 配牌:%+v 鬼牌:%v", uid, no, pokers, ghostPoker))
|
||
r.pokers.SetGmPoker(pokers, ghostPoker, no)
|
||
r.pokers.Pokers()
|
||
return true
|
||
}
|
||
|
||
func (r *TrucoRoom) 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()))
|
||
}
|
||
}
|