samba/server/cacheta/room/cathetaRoomHandler.go
2025-06-04 09:51:39 +08:00

717 lines
20 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package room
import (
"fmt"
"samba/pkg/log"
"samba/proto"
"samba/server/cacheta/poker"
. "samba/server/cacheta/service"
"samba/server/game/baseroom"
. "samba/server/game/player"
"samba/stub"
"samba/util/model"
"samba/util/state"
"samba/util/util"
"sort"
"time"
)
func (r *GameRoom) loadRobot(user *Player, seat *GameSeat) {
if user.IsRobot() {
init := false
for _, s := range r.Seats {
if !s.Empty() && s.Player().IsRobot() && s.Player().Robot != nil {
r.SetRobotTemper(seat.No(), s.Player().Robot.Cnf())
init = true
break
}
}
if !init {
if cnf := r.RandRobotCnf(); cnf != stub.RteUnknown {
//cnf = r.RobotCnfByTemper(stub.RteAplomb)
r.SetRobotTemper(seat.No(), cnf)
} else {
log.Error(r.SeatLog(seat, "rand robot error. cnf is nil"))
}
}
}
}
func (r *GameRoom) makePlayerToProto(seat *GameSeat, hidePoker bool) *proto.CachetaPlayer {
user := seat.Player()
protoPlayer := &proto.CachetaPlayer{
UserId: user.UID,
Mnick: user.MNick,
HeadUrl: user.HeadURL,
IconId: user.IconId,
AvatarFrame: user.AvatarFrame,
Sex: user.Sex,
TakeCoin: user.TakeCoin,
ClubTakeCoin: user.TakeClubCoin,
Poker: proto.CachetaHandPoker{},
Seat: seat.No(),
State: util.Tie(seat.FakeLeave(), 0, 1),
Point: seat.Point,
}
if r.ClubId() == 0 {
protoPlayer.Coin = r.getCoin(user.UID)
} else {
protoPlayer.ClubCoin = r.getCoin(user.UID)
}
if !hidePoker {
protoPlayer.Poker = seat.handPoker
} else {
for i := 0; i < len(seat.pokers); i++ {
protoPlayer.Poker.Pokers = append(protoPlayer.Poker.Pokers, 0)
}
}
return protoPlayer
}
func (r *GameRoom) makeProtoRoomInfo() *proto.NtfCachetaRoomInfo {
protoRoom := &proto.NtfCachetaRoomInfo{
RoomId: r.Id(),
RoomType: r.Type(),
ClubId: r.ClubId(),
Blind: r.RoomCnf.Blind,
CuttingPoker: 0,
WildPoker: nil,
PickPokerNum: len(r.pickPokers),
OutPokers: nil,
State: int(r.gameStep),
GameCount: r.smallGameCount,
}
if r.pokers.CutPoker() != nil {
protoRoom.CuttingPoker = r.pokers.CutPoker().ToInt()
}
for _, pk := range r.pokers.WildPokers() {
protoRoom.WildPoker = append(protoRoom.WildPoker, pk.ToInt())
}
for _, pk := range r.outPokers {
protoRoom.OutPokers = append(protoRoom.OutPokers, pk.ToInt())
}
return protoRoom
}
// 重进入
func (r *GameRoom) checkEnterRoom(user *Player) (code proto.ErrorCode, seat *GameSeat, isReentry bool) {
code = proto.RoomFull
for _, st := range r.Seats {
if !st.Empty() && st.Player().UID == user.UID {
seat = st
isReentry = true
code = proto.Ok
st.SetFakeLeave(false)
break
}
}
if !isReentry {
if r.Status() > state.RsWait {
return proto.GameStarted, nil, false
}
for _, st := range r.Seats {
if st.Empty() {
seat = st
code = proto.Ok
st.SetPlayer(user)
st.SetFakeLeave(false)
break
}
}
}
return code, seat, isReentry
}
// 进入房间
func (r *GameRoom) onEnterRoom(msg map[string]interface{}) {
_, _, uid, _ := ParseMsg(msg)
seat := r.FindSeat(uid)
if seat != nil {
r.OnEnterRoom(seat.Player())
} else {
if player, err := NewPlayer(uid); err == nil {
r.OnEnterRoom(player)
} else {
log.Error(r.Log(err.Error()))
}
}
}
// 加入房间
func (r *GameRoom) OnEnterRoom(user *Player) {
code, seat, isReentry := r.checkEnterRoom(user)
if code != proto.Ok {
r.SendMsg(user, proto.RspEnterRoomId, &proto.RspEnterRoom{Code: code}, false)
return
}
if !isReentry {
if user.IsRobot() {
r.loadRobot(user, seat)
}
r.addResource(seat.Player(), r.RoomCnf.TakeCoin, model.ResTakeCoins, model.ReasonEnter)
log.Info(r.SeatLog(seat, "进入房间,携带金币:%v", r.getTakeCoin(seat.Player())))
}
// 向玩家发送消息
rsp := &proto.RspEnterRoom{
Code: proto.Ok,
RoomId: r.Id(),
RoomType: r.Type(),
PlayType: r.PlayType(),
ClubId: r.ClubId(),
GameInfo: r.MakeClubPlayGameInfo(),
IsReentry: util.Tie(isReentry, 1, 0),
}
r.SendMsg(user, proto.RspEnterRoomId, rsp, false)
r.notifyRoomInfo(user)
r.notifyPlayerInfo(user, isReentry)
// 首个真人进房间,开启等待定时器
if r.RealPlayerNum() == 1 {
r.StartWaitTimer()
}
// 发送游戏开始消息
if !isReentry && r.SeatPlayerNum() == r.RoomCnf.MinPlayers {
ntf := &proto.NtfGameStart{Time: time.Now().Unix()}
r.Broadcast(proto.NtfStartCachetaGameId, ntf, false)
r.SetStatus(state.RsReadyStart)
r.gameStep = GsReadyGame
r.NewTimer(baseroom.TtGameReadyStart, time.Duration(stub.GGlobal.TrucoGameStartTime)*time.Second)
}
}
// kickOut:true踢掉玩家小局结束分数不足时强制踢掉
func (r *GameRoom) leaveRoom(seat *GameSeat, kickOut bool) {
if r.gameStep == GsWaitGame || kickOut {
r.addResource(seat.Player(), -seat.Player().TakeCoin, model.ResTakeCoins, model.ReasonLeave)
log.Info(r.SeatLog(seat, "归还携带金币:%v", -seat.Player().TakeCoin))
model.SetUserPlayingRoom(seat.Player().UID, r.Id(), false)
// 回收机器人
if seat.Player().IsRobot() {
log.Debug(r.SeatLog(seat, "清理并归还机器人"))
seat.Player().CleanRobot()
seat.Player().Robot = nil
RobotMgr.Push(seat.Player())
} else {
playingNum, err := model.DelRoomTypePlayerNum(r.RoomCnf, seat.Player().UID)
if err == nil && r.RoomCnf.Mode != int(stub.RmClub) {
// 金币场 广播虚假在玩人数
BroadcastMsg(proto.NtfPlayingNumId, &proto.NtfPlayingNum{RoomType: r.RoomCnf.Id, PlayingNum: model.CalculateFakeCount(playingNum)})
}
}
r.TriggerClubMemberPlaying(seat.Player().UID, false)
r.Broadcast(proto.NtfLeaveRoomId, &proto.NtfLeaveRoom{CurrentSeat: seat.No(), RoomId: r.Id()}, false, seat.Player())
seat.SetPlayer(nil)
r.TryReleaseRoom()
} else {
seat.SetFakeLeave(true)
}
}
// 离开房间
func (r *GameRoom) onLeaveRoom(msg map[string]interface{}) {
_, _, uid, _ := ParseMsg(msg)
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
log.Debug(r.SeatLog(seat, "玩家申请离开房间, room status:%v", r.gameStep))
// 向玩家发送消息
rsp := &proto.NtfLeaveRoom{
CurrentSeat: seat.No(),
RoomId: r.Id(),
}
r.SendMsg(seat.Player(), proto.RspLeaveRoomId, &proto.RspLeaveRoom{Code: proto.Ok, RoomId: r.Id(), CurrentSeat: seat.No()}, false)
if r.gameStep == GsWaitGame {
r.Broadcast(proto.NtfLeaveRoomId, rsp, false, seat.Player())
} else {
seat.SetFakeLeave(true)
r.notifyFakeLeave(seat)
}
r.leaveRoom(seat, false)
}
func (r *GameRoom) checkPickPoker(seat *GameSeat) proto.ErrorCode {
if r.gameStep != GsPlayerAct {
log.Error(r.SeatLog(seat, "不是玩家行动期. game step:%v", r.gameStep))
return proto.BadAction
}
if seat.No() != r.current {
log.Error(r.SeatLog(seat, "is not current:%v", r.current))
return proto.NotCurrent
}
if seat.ActType != SatPickPokerOrWin {
log.Error(r.SeatLog(seat, "is not out poker act type:%v", seat.ActType))
return proto.BadAction
}
return proto.Ok
}
// 玩家摸牌
func (r *GameRoom) onPickPoker(msg map[string]interface{}) {
_, _, uid, data := ParseMsg(msg)
req, err := util.MapToStructT[proto.ReqCachetaPickPoker](data)
if err != nil {
log.Error(err.Error())
return
}
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
if code := r.checkPickPoker(seat); code != proto.Ok {
r.SendMsg(seat.Player(), proto.RspCachetaPickPokerId, proto.RspCachetaPickPoker{Code: code}, false)
return
}
r.CancelTimer(baseroom.TtPlayerAct)
seat.ActType = SatOutPoker
var pickPk *poker.Poker
rsp := &proto.RspCachetaPickPoker{Code: proto.Ok, IsDrop: req.IsDrop}
rsp.DropPoker = r.outPokers[len(r.outPokers)-1].ToInt()
// 摸牌区摸牌
if req.IsDrop == 0 {
if len(r.pickPokers) == 0 {
r.pickPokers = r.pickPokers[0:0]
for i := len(r.outPokers) - 1; i >= 0; i-- {
r.pickPokers = append(r.pickPokers, r.outPokers[i])
}
r.outPokers = r.outPokers[0:0]
rsp.IsTurnOver = 1
}
pickPk = r.pickPokers[len(r.pickPokers)-1]
r.pickPokers = r.pickPokers[:len(r.pickPokers)-1]
} else {
if len(r.outPokers) == 0 {
log.Error(r.SeatLog(seat, "弃牌区为空,异常"))
return
}
pickPk = r.outPokers[len(r.outPokers)-1]
r.outPokers = r.outPokers[:len(r.outPokers)-1]
if len(r.outPokers) != 0 {
rsp.DropPoker = r.outPokers[len(r.outPokers)-1].ToInt()
} else {
rsp.DropPoker = 0
}
}
seat.pokers = append(seat.pokers, pickPk)
seat.handPoker.Pokers = append(seat.handPoker.Pokers, pickPk.ToInt())
rsp.Poker = pickPk.ToInt()
r.SendMsg(seat.Player(), proto.RspCachetaPickPokerId, rsp, false)
log.Debug(r.SeatLog(seat, "申请摸牌:%v玩家手牌:%v", pickPk.ToString(), poker.PokersToString(seat.pokers)))
ntf := &proto.NtfCachetaPickPoker{CurrentSeat: seat.No(), IsTurnOver: 0, IsDrop: rsp.IsDrop, DropPoker: rsp.DropPoker}
if len(r.pickPokers) == 0 {
for i := len(r.outPokers) - 1; i >= 0; i-- {
r.pickPokers = append(r.pickPokers, r.outPokers[i])
}
for _, pk := range r.pickPokers {
ntf.PickPokers = append(ntf.PickPokers, pk.ToInt())
}
r.outPokers = nil
ntf.IsTurnOver = 1
}
ntf.PickPokerNum = len(r.pickPokers)
r.Broadcast(proto.NtfCachetaPickPokerId, ntf, true)
r.PlayerAct(seat.Player())
// 牌局回顾
ntf.Poker = pickPk.ToInt()
r.record.AddAction(proto.NtfCachetaPickPokerId, ntf)
}
func (r *GameRoom) checkOutPoker(seat *GameSeat, req *proto.ReqCachetaOutPoker) (proto.ErrorCode, *poker.Poker) {
if r.gameStep != GsPlayerAct {
log.Error(r.SeatLog(seat, "不是玩家行动期. game step:%v", r.gameStep))
return proto.BadAction, nil
}
if seat.No() != r.current {
log.Error(r.SeatLog(seat, "is not current:%v", r.current))
return proto.NotCurrent, nil
}
if seat.ActType != SatOutPoker {
log.Error(r.SeatLog(seat, "is not out poker act type:%v", seat.ActType))
return proto.BadAction, nil
}
var pk *poker.Poker
var ok bool
if ok, pk = seat.Remove(req.Poker); !ok {
log.Error(r.SeatLog(seat, "has not poker:%v 手牌:%v", poker.NewPoker(req.Poker).ToString(), poker.PokersToString(seat.pokers)))
return proto.BadParam, nil
}
seat.ActType = SatNone
return proto.Ok, pk
}
// 出完牌后监测是否听牌
func (r *GameRoom) checkTingHu(seat *GameSeat) proto.ErrorCode {
if seat.TingHu {
return proto.BadAction
}
var tmpPokers []*poker.Poker
tmpPokers = append(tmpPokers, seat.pokers...)
tmpPokers = append(tmpPokers, r.pokers.WildPoker())
groups, high := poker.FindBestGroupsAndRemains(r.pokers.WildPoker(), tmpPokers)
log.Debug(r.SeatLog(seat, "检查听牌:%s", poker.DebugGroupsHigh(groups, high, nil)))
// 添加一张万能牌后散牌数为0或1即可听牌
return util.Tie[proto.ErrorCode](len(high) < 2, proto.Ok, proto.BadAction)
}
// 玩家出牌
func (r *GameRoom) onOutPoker(msg map[string]interface{}) {
_, _, uid, data := ParseMsg(msg)
req, err := util.MapToStructT[proto.ReqCachetaOutPoker](data)
if err != nil {
log.Error(r.Log(err.Error()))
return
}
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
//log.Debug(r.SeatLog(seat, "申请出牌:%v玩家手牌:%v", poker.NewPoker(req.Poker).ToString(), poker.PokersToString(seat.pokers)))
code, pk := r.checkOutPoker(seat, req)
if code != proto.Ok {
rsp := &proto.RspCachetaOutPoker{Code: code, Poker: req.Poker}
r.SendMsg(seat.Player(), proto.RspCachetaOutPokerId, rsp, false)
return
}
r.outPokers = append(r.outPokers, pk)
ntf := &proto.NtfCachetaOutPoker{CurrentSeat: seat.No(), Poker: req.Poker}
r.Broadcast(proto.NtfCachetaOutPokerId, ntf, false)
// 牌局回顾
r.record.AddAction(proto.NtfPlayerOutPokerId, ntf)
if r.checkTingHu(seat) == proto.Ok {
log.Debug(r.SeatLog(seat, "听牌"))
seat.TingHu = true
ntf1 := &proto.NtfCachetaTingHu{Seat: seat.No()}
r.Broadcast(proto.NtfCachetaTingHuId, ntf1, false)
// 牌局回顾
r.record.AddAction(proto.NtfCachetaTingHuId, ntf1)
}
log.Debug(r.SeatLog(seat, "出牌:%v 玩家手牌:%v", poker.NewPoker(req.Poker).ToString(), poker.PokersToString(seat.pokers)))
//log.Debug(r.Log("cancel timer:TtPlayerAct"))
r.CancelTimer(baseroom.TtPlayerAct)
//r.NotifyCutLine()
}
func (r *GameRoom) checkTidyPoker(seat *GameSeat, req *proto.ReqCachetaTidyPoker) proto.ErrorCode {
if r.gameStep >= GsGameSettle {
log.Error(r.SeatLog(seat, "game is over"))
return proto.BadAction
}
var clientPks []int
for _, g := range req.HandPoker.Groups {
for _, p := range g.Pokers {
clientPks = append(clientPks, p)
}
}
clientPks = append(clientPks, req.HandPoker.Pokers...)
var serverPks []int
for _, p := range seat.pokers {
serverPks = append(serverPks, p.ToInt())
}
sort.Ints(clientPks)
sort.Ints(serverPks)
if len(clientPks) != len(serverPks) {
return proto.BadParam
}
for i, p := range clientPks {
if p != serverPks[i] {
return proto.BadParam
}
}
return proto.Ok
}
// 客户端主动调整手牌
func (r *GameRoom) onTidyPoker(msg map[string]interface{}) {
_, _, uid, data := ParseMsg(msg)
req, err := util.MapToStructT[proto.ReqCachetaTidyPoker](data)
if err != nil {
log.Error(r.Log(err.Error()))
return
}
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
rsp := proto.RspCachetaTidyPoker{}
rsp.Code = r.checkTidyPoker(seat, req)
if rsp.Code != proto.Ok {
rsp.HandPoker = seat.handPoker
} else {
rsp.HandPoker = req.HandPoker
seat.handPoker = req.HandPoker
}
log.Debug(r.SeatLog(seat, "调整后手牌:%v", seat.HandPokerString()))
r.SendMsg(seat.Player(), proto.RspCachetaTidyPokerId, rsp, false)
}
func (r *GameRoom) checkHu(seat *GameSeat, req *proto.ReqCachetaHu) (proto.ErrorCode, int) {
// 不是当前玩家
if seat.No() != r.current {
// 也没有插队
if r.gameStep != GsCutLine || !seat.TingHu {
log.Error(r.SeatLog(seat, "is not current:%v", r.current))
return proto.NotCurrent, 0
}
if r.gameStep == GsCutLine && seat.CutLineNum < 1 {
log.Error(r.SeatLog(seat, "插队次数已用完"))
return proto.CutLineZero, 0
}
}
var pokers []*poker.Poker
pokers = append(pokers, seat.pokers...)
if req.DropPoker > 0 {
pokers = append(pokers, poker.NewPoker(req.DropPoker))
}
gs, highPokers := poker.FindBestGroupsAndRemains(r.pokers.WildPoker(), pokers)
log.Debug(r.SeatLog(seat, "检查胡牌:%s", poker.DebugGroupsHigh(gs, highPokers, nil)))
if len(highPokers) == 0 || len(highPokers) == 1 {
return proto.Ok, len(highPokers)
}
return proto.BadAction, 0
}
// 玩家胡牌
func (r *GameRoom) onHu(msg map[string]interface{}) {
_, _, uid, data := ParseMsg(msg)
req, err := util.MapToStructT[proto.ReqCachetaHu](data)
if err != nil {
log.Error(r.Log(err.Error()))
return
}
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
log.Debug(r.SeatLog(seat, "申请胡牌,玩家手牌:%v", poker.PokersToString(seat.pokers)))
code, highNum := r.checkHu(seat, req)
if r.gameStep == GsCutLine {
seat.CutLineNum = 0
}
ntf := &proto.NtfCachetaHu{Code: code, Seat: seat.No()}
r.Broadcast(proto.NtfCachetaHuId, ntf, true)
// 牌局回顾
r.record.AddAction(proto.NtfCachetaHuId, ntf)
log.Debug(r.SeatLog(seat, "申请胡牌:%v", code))
if code == proto.Ok {
r.GameOver(seat, highNum)
}
}
// 玩家断线重连
func (r *GameRoom) onReconnect(msg map[string]interface{}) {
_, _, uid, _ := ParseMsg(msg)
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
seat.SetFakeLeave(false)
r.notifyFakeLeave(seat)
//log.Debug(r.SeatLog(seat, "seat:%v 重连", seat.No()))
rsp := &proto.RspCachetaReconnect{
Code: proto.Ok,
RoomInfo: r.makeProtoRoomInfo(),
Players: nil,
Dealer: r.dealer,
}
for _, st := range r.Seats {
if st.Empty() {
continue
}
rsp.Players = append(rsp.Players, r.makePlayerToProto(st, st.Player().UID != seat.Player().UID))
}
r.SendMsg(seat.Player(), proto.RspCachetaReconnectId, rsp, false)
if lastMsg, ok := r.LastMsg[uid]; ok {
ilm := lastMsg.Msg
if lm, ok1 := lastMsg.Msg.(*proto.NtfPlayerAct); ok1 && lastMsg.Tm.Unix() != 0 {
lm.Countdown -= int(time.Now().Unix() - lastMsg.Tm.Unix())
lm.Countdown = util.Tie(lm.Countdown < 0, 0, lm.Countdown)
} else if lm, ok1 := lastMsg.Msg.(*proto.NtfPlayerRspRaise); ok1 && lastMsg.Tm.Unix() != 0 {
lm.Countdown -= int(time.Now().Unix() - lastMsg.Tm.Unix())
lm.Countdown = util.Tie(lm.Countdown < 0, 0, lm.Countdown)
}
r.SendMsg(seat.Player(), lastMsg.MsgId, ilm, false)
log.Debug(r.SeatLog(seat, "重连补发消息:%v", lastMsg.MsgId))
}
}
// 服务器维护中
func (r *GameRoom) onMaintain(msg map[string]interface{}) {
_, _, _, data := ParseMsg(msg)
req, err := util.MapToStructT[proto.NtfMaintain](data)
if err != nil {
log.Error(err.Error())
return
}
r.CancelAllTimer()
r.gameStep = GsWaitGame
r.Broadcast(proto.NtfMaintainId, req, false)
for _, st := range r.Seats {
if !st.Empty() {
msgL := util.MakeMessage(proto.ReqLeaveRoomId, &proto.ReqLeaveRoom{RoomId: r.Id()}, st.Player().UID, r.Id())
r.OnMessage(proto.ReqLeaveRoomId, msgL)
}
}
}
// gm解散房间
func (r *GameRoom) onDisbandRoom(_ map[string]interface{}) {
//_, _, _, data := ParseMsg(msg)
//req, err := util.MapToStructT[proto.NtfMaintain](data)
//if err != nil {
// log.Error(err.Error())
// return
//}
ntf := &proto.NtfMaintain{Code: proto.DisbandRoom}
r.CancelAllTimer()
r.gameStep = GsWaitGame
r.Broadcast(proto.NtfMaintainId, ntf, false)
for _, st := range r.Seats {
if !st.Empty() {
msgL := util.MakeMessage(proto.ReqLeaveRoomId, &proto.ReqLeaveRoom{RoomId: r.Id()}, st.Player().UID, r.Id())
r.OnMessage(proto.ReqLeaveRoomId, msgL)
}
}
}
func (r *GameRoom) checkEmote(user *Player, req *proto.ReqEmote, rsp *proto.NtfEmote) {
rsp.Code = proto.Ok
rsp.EmoteId = req.EmoteId
rsp.DestSeat = req.DestSeat
it, ok := stub.GPayEmote[req.EmoteId]
if !ok {
// 免费表情
return
}
if it.Value < 1 {
rsp.Code = proto.Ok
return
}
resType, err := model.IntToRes(it.Type)
if err != nil {
log.Error(err.Error())
rsp.Code = proto.BadParam
return
}
rsp.ResType = it.Type
rsp.CostValue = it.Value
if resType == model.ResCoins {
op := model.NewUserResourceOp()
coins, err := op.Get(user.UID, model.ResCoins)
takeCoins, err1 := op.GetTakeCoin(user.UID)
if err1 != nil || err != nil {
rsp.Code = proto.Internal
log.Error(fmt.Sprintf("err:%v err1:%v", err, err1))
return
}
if coins-takeCoins < it.Value {
rsp.Code = proto.NotEnough
log.Debug(fmt.Sprintf("coins:%v takeCoins:%v emote cost:%v not enough", coins, takeCoins, it.Value))
return
}
r.addResource(user, -it.Value, model.ResCoins, model.ReasonEmote)
coins -= it.Value
rsp.ResVal = coins
} else {
op := model.NewUserResourceOp()
value, err := op.Get(user.UID, resType)
if err != nil {
rsp.Code = proto.Internal
log.Error(fmt.Sprintf("err:%v", err))
return
}
if value < it.Value {
rsp.Code = proto.NotEnough
log.Debug(fmt.Sprintf("resType:%v resValue:%v emote cost:%v not enough", resType, value, it.Value))
return
}
r.addResource(user, -it.Value, resType, model.ReasonEmote)
value -= it.Value
rsp.ResVal = value
}
return
}
// 玩家使用表情
func (r *GameRoom) onEmote(msg map[string]interface{}) {
_, _, uid, data := ParseMsg(msg)
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
req, err := util.MapToStructT[proto.ReqEmote](data)
if err != nil {
log.Error(err.Error())
return
}
rsp := &proto.NtfEmote{Seat: seat.No()}
r.checkEmote(seat.Player(), req, rsp)
log.Debug(r.SeatLog(seat, "第%d小局, 使用表情:%v", r.smallGameCount, Emote(req.EmoteId)))
if rsp.Code == proto.Ok {
r.Broadcast(proto.NtfEmoteId, rsp, false)
} else {
r.SendMsg(seat.Player(), proto.NtfEmoteId, rsp, false)
}
}
// 玩家准备
func (r *GameRoom) onReady(msg map[string]interface{}) {
_, _, uid, _ := ParseMsg(msg)
seat := r.GetSeat(uid)
if seat == nil {
log.Error(r.Log("player:%d seat is nil", uid))
return
}
log.Debug(r.SeatLog(seat, "收到玩家准备"))
seat.SetReady(true)
allReady := true
for _, st := range r.Seats {
if !st.Ready() {
allReady = false
break
}
}
if allReady {
r.CancelTimer(baseroom.TtGameReadyStart)
if r.SeatPlayerNum() == r.RoomCnf.MinPlayers && r.Status() != state.RsGaming {
r.ReInit()
r.GameStart()
}
}
// 游戏中,重连玩家发送准备后,设置为假离开后返回
if r.Status() == state.RsGaming {
r.SetFakeLeave(uid, false)
}
}