diff --git a/gamesrv/tienlen/scenedata_tienlen.go b/gamesrv/tienlen/scenedata_tienlen.go index f5daa4b..28b20e9 100644 --- a/gamesrv/tienlen/scenedata_tienlen.go +++ b/gamesrv/tienlen/scenedata_tienlen.go @@ -174,6 +174,10 @@ func (this *TienLenSceneData) CanStart() bool { return false } +func (this *TienLenSceneData) IsFirst(pos int) bool { + return int32(pos) == this.lastOpPos || this.lastOpPos == rule.InvalidePos +} + func (this *TienLenSceneData) GetPlayerCnt() int { var cnt int for i := 0; i < this.GetPlayerNum(); i++ { diff --git a/gamesrv/tienlen/scenepolicy_tienlen.go b/gamesrv/tienlen/scenepolicy_tienlen.go index 2f29da4..47f7416 100644 --- a/gamesrv/tienlen/scenepolicy_tienlen.go +++ b/gamesrv/tienlen/scenepolicy_tienlen.go @@ -1160,242 +1160,270 @@ func (this *ScenePlayerOpStateTienLen) OnPlayerOp(s *base.Scene, p *base.Player, return true } - sceneEx, _ := s.GetExtraData().(*TienLenSceneData) - if sceneEx != nil { - playerEx, _ := p.GetExtraData().(*TienLenPlayerData) - if playerEx != nil { - if sceneEx.GetCurOpPos() != int32(playerEx.GetPos()) { - return false + sceneEx, ok := s.GetExtraData().(*TienLenSceneData) + if !ok { + return false + } + playerEx, ok := p.GetExtraData().(*TienLenPlayerData) + if !ok { + return false + } + + if sceneEx.GetCurOpPos() != int32(playerEx.GetPos()) { + return false + } + + opRetCode := tienlen.OpResultCode_OPRC_Error + + finishFunc := func() { + switch opRetCode { + case tienlen.OpResultCode_OPRC_Sucess: + this.BroadcastPlayerSToCOp(s, playerEx.SnId, playerEx.GetPos(), opcode, opRetCode, params) + + delCardNum := 0 + for _, hcard := range playerEx.cards { + if hcard == rule.InvalideCard { + delCardNum++ + } } - - opRetCode := tienlen.OpResultCode_OPRC_Error - switch int32(opcode) { - case rule.TienLenPlayerOpPlay: //出牌 - - delCards := []int32{} - for _, card := range params { - isHave := false - for _, hcard := range playerEx.cards { //去手牌里找找看有没有 - if int32(card) == hcard && hcard != rule.InvalideCard { - isHave = true - } - } - if isHave { - delCards = append(delCards, int32(card)) - } else { - opRetCode = tienlen.OpResultCode_OPRC_Error - break - } + if delCardNum == rule.Hand_CardNum { //牌出完了 + sceneEx.TrySmallGameBilled() + if !common.InSliceInt32(sceneEx.winSnids, playerEx.SnId) { + sceneEx.winSnids = append(sceneEx.winSnids, playerEx.SnId) } - if len(delCards) == len(params) && len(delCards) > 0 { - isRule, _ := rule.RulePopEnable(delCards) - ruleType := rule.Tienlen_Pass - if sceneEx.IsTienLenYule() { - isRule, ruleType = rule.RulePopEnable_yl(delCards) - } - //logger.Logger.Trace("ScenePlayerOpStateTienLen,2params:", params, " isRule:", isRule) - if isRule { //符合出牌规则 - if int32(playerEx.GetPos()) == sceneEx.lastOpPos || sceneEx.lastOpPos == rule.InvalidePos { //当前操作者和上一个操作者是同一个人,必出牌 - if ruleType == rule.Plane_Single { //飞机带单只能最后一手出 - haveCardNum := 0 - for _, hcard := range playerEx.cards { - if hcard != rule.InvalideCard { - haveCardNum++ - } - } - if len(delCards) != haveCardNum { - isRule = false - opRetCode = tienlen.OpResultCode_OPRC_Error - logger.Logger.Trace("Plane_Single, delCards:", delCards, " haveCardNum:", haveCardNum) - } - } - if isRule { - if sceneEx.lastOpPos == rule.InvalidePos { //首出玩家 - //有赢家,赢家先出,出牌不受限制 - //无赢家,手持最小牌先出,最小牌必先出 - winPos := sceneEx.FindWinPos() - //logger.Logger.Trace("ScenePlayerOpStateTienLen,8params:", params, " winPos:", winPos) - if winPos == -1 { //无赢家 - haveMinCard := false - for _, card := range delCards { - if card == sceneEx.curMinCard { //最小牌必先出 - haveMinCard = true - } - } - //logger.Logger.Trace("ScenePlayerOpStateTienLen,9params:", params, " curMinCard:", sceneEx.curMinCard, " haveMinCard", haveMinCard) - if haveMinCard { - isDel := sceneEx.DelCards(playerEx, delCards) - //logger.Logger.Trace("ScenePlayerOpStateTienLen,3params:", params, " isDel:", isDel) - if isDel { - - playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) - - sceneEx.DoNext(int32(playerEx.GetPos())) - opRetCode = tienlen.OpResultCode_OPRC_Sucess - sceneEx.SetLastOpPos(int32(playerEx.GetPos())) - sceneEx.RefreshPlayerHandLimitTimeOut() - } - } - } else { - isDel := sceneEx.DelCards(playerEx, delCards) - //logger.Logger.Trace("ScenePlayerOpStateTienLen,10params:", params, " isDel:", isDel) - if isDel { - - playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) - - sceneEx.DoNext(int32(playerEx.GetPos())) - opRetCode = tienlen.OpResultCode_OPRC_Sucess - sceneEx.SetLastOpPos(int32(playerEx.GetPos())) - sceneEx.RefreshPlayerHandLimitTimeOut() - } - } - } else { - isDel := sceneEx.DelCards(playerEx, delCards) - //logger.Logger.Trace("ScenePlayerOpStateTienLen,4params:", params, " isDel:", isDel) - if isDel { - - playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) - - nextPos := sceneEx.DoNext(int32(playerEx.GetPos())) - //logger.Logger.Trace("ScenePlayerOpStateTienLen,4paramssss:", params, " nextPos:", nextPos) - if sceneEx.IsTienLenToEnd() && nextPos == rule.InvalidePos { - sceneEx.UnmarkPass() - nextPos = sceneEx.DoNext(int32(playerEx.GetPos())) - //logger.Logger.Trace("ScenePlayerOpStateTienLen,4paramssss:", params, " nextPos:", nextPos) - } - opRetCode = tienlen.OpResultCode_OPRC_Sucess - sceneEx.SetLastOpPos(int32(playerEx.GetPos())) - sceneEx.RefreshPlayerHandLimitTimeOut() - } - } - if opRetCode == tienlen.OpResultCode_OPRC_Sucess { - isBomb := rule.IsFourBomb(delCards) - if isBomb { - sceneEx.isKongBomb = true - } - } - sceneEx.UnmarkPass() - } - } else { //当前操作者和上一个操作者不是同一个人,必压制 - if !playerEx.isPass { - lastOpPlayer := sceneEx.GetLastOpPlayer() - //logger.Logger.Trace("ScenePlayerOpStateTienLen,5params:", params, " lastOpPlayer:", lastOpPlayer) - if lastOpPlayer != nil && len(lastOpPlayer.delCards) != 0 { - lastDelCards := lastOpPlayer.delCards[len(lastOpPlayer.delCards)-1] - canDel, isBomb, bombScore := rule.CanDel(lastDelCards, delCards, sceneEx.IsTienLenToEnd()) - if sceneEx.IsTienLenYule() { - canDel, isBomb, bombScore = rule.CanDel_yl(lastDelCards, delCards, sceneEx.IsTienLenToEnd()) - } - //logger.Logger.Trace("ScenePlayerOpStateTienLen,6params:", params, " canDel:", canDel, " lastDelCards:", lastDelCards) - if canDel { - if isBomb { - sceneEx.curBombPos = int32(playerEx.GetPos()) - sceneEx.lastBombPos = sceneEx.lastOpPos - sceneEx.roundScore += bombScore - } else { - sceneEx.curBombPos = rule.InvalidePos - sceneEx.lastBombPos = rule.InvalidePos - sceneEx.roundScore = 0 - } - isDel := sceneEx.DelCards(playerEx, delCards) - //logger.Logger.Trace("ScenePlayerOpStateTienLen,7params:", params, " isDel:", isDel) - if isDel { - - playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) - - nextPos := sceneEx.DoNext(int32(playerEx.GetPos())) - if sceneEx.IsTienLenToEnd() && nextPos == rule.InvalidePos { - sceneEx.UnmarkPass() - sceneEx.DoNext(int32(playerEx.GetPos())) - } - sceneEx.SetLastOpPos(int32(playerEx.GetPos())) - sceneEx.RefreshPlayerHandLimitTimeOut() - opRetCode = tienlen.OpResultCode_OPRC_Sucess - sceneEx.isKongBomb = false - } - } - } - } - } - } - } - case rule.TienLenPlayerOpPass: //过牌 - if int32(playerEx.GetPos()) == sceneEx.lastOpPos { //当前操作者和上一个操作者是同一个人,必出牌,不能过牌 - opRetCode = tienlen.OpResultCode_OPRC_Error - } else { - if sceneEx.lastOpPos != rule.InvalidePos { - - playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) - - sceneEx.card_play_action_seq = append(sceneEx.card_play_action_seq, fmt.Sprintf("%v-过", playerEx.GetPos())) - sceneEx.card_play_action_seq_int32 = append(sceneEx.card_play_action_seq_int32, []int32{-1}) - nextPos := sceneEx.DoNext(int32(playerEx.GetPos())) - - if sceneEx.IsTienLenToEnd() && nextPos == rule.InvalidePos { - sceneEx.UnmarkPass() - nextPos = sceneEx.DoNext(int32(playerEx.GetPos())) - sceneEx.SetLastOpPos(int32(nextPos)) - } - - sceneEx.RefreshPlayerHandLimitTimeOut() - opRetCode = tienlen.OpResultCode_OPRC_Sucess - playerEx.isPass = true - if nextPos == sceneEx.lastOpPos { //一轮都不出牌 - sceneEx.TrySmallGameBilled() - } - } - } - case rule.TienLenPlayerClientHintCards: - if int32(playerEx.GetPos()) == sceneEx.lastOpPos || sceneEx.lastOpPos == rule.InvalidePos { - logger.Logger.Trace("ScenePlayerOpStateTienLen,107 OPRC_Error:", params, " opcode:", opcode, " snid:", p.SnId, " pos:", playerEx.GetPos()) - } else { - if len(params) > 0 { - sceneEx.cHintCards = make([]int32, len(params)+1) - sceneEx.cHintCards[0] = p.SnId - copy(sceneEx.cHintCards[1:], common.Int64ToInt32(params)) - opRetCode = tienlen.OpResultCode_OPRC_Hint - } - } - default: - opRetCode = tienlen.OpResultCode_OPRC_Error - } - - //next - if opRetCode == tienlen.OpResultCode_OPRC_Sucess { - this.BroadcastPlayerSToCOp(s, playerEx.SnId, playerEx.GetPos(), opcode, opRetCode, params) - - delCardNum := 0 - for _, hcard := range playerEx.cards { - if hcard == rule.InvalideCard { - delCardNum++ - } - } - if delCardNum == rule.Hand_CardNum { //牌出完了 - sceneEx.TrySmallGameBilled() - if !common.InSliceInt32(sceneEx.winSnids, playerEx.SnId) { - sceneEx.winSnids = append(sceneEx.winSnids, playerEx.SnId) - } - if sceneEx.IsTienLenToEnd() { //打到底 - if sceneEx.GetGameingPlayerCnt()-1 == len(sceneEx.winSnids) { - sceneEx.ChangeSceneState(rule.TienLenSceneStateBilled) - } else { - playerEx.isDelAll = true - sceneEx.BroadcastOpPos() - } - } else { + if sceneEx.IsTienLenToEnd() { //打到底 + if sceneEx.GetGameingPlayerCnt()-1 == len(sceneEx.winSnids) { sceneEx.ChangeSceneState(rule.TienLenSceneStateBilled) + } else { + playerEx.isDelAll = true + sceneEx.BroadcastOpPos() } } else { - sceneEx.BroadcastOpPos() + sceneEx.ChangeSceneState(rule.TienLenSceneStateBilled) } - } else if opRetCode == tienlen.OpResultCode_OPRC_Error { - this.OnPlayerSToCOp(s, p, playerEx.GetPos(), opcode, opRetCode, params) - - logger.Logger.Trace("ScenePlayerOpStateTienLen,100 OPRC_Error:", params, " opcode:", opcode, " snid:", p.SnId, " pos:", playerEx.GetPos()) + } else { + sceneEx.BroadcastOpPos() } + case tienlen.OpResultCode_OPRC_Error: + this.OnPlayerSToCOp(s, p, playerEx.GetPos(), opcode, opRetCode, params) + logger.Logger.Trace("ScenePlayerOpStateTienLen,100 OPRC_Error:", params, " opcode:", opcode, " snid:", p.SnId, " pos:", playerEx.GetPos()) } } + switch int32(opcode) { + case rule.TienLenPlayerOpPlay: //出牌 + + var delCards []int32 + checkCardsFunc := func() bool { + for _, card := range params { + isHave := false + for _, card := range playerEx.cards { //去手牌里找找看有没有 + if card == card && card != rule.InvalideCard { + isHave = true + } + } + if isHave { + delCards = append(delCards, int32(card)) + } else { + return false + } + } + + return len(delCards) == len(params) && len(delCards) > 0 + } + + if !checkCardsFunc() { + logger.Logger.Errorf("出牌错误 snid:%v, pos:%v, cards:%v", p.SnId, playerEx.GetPos(), params) + finishFunc() + return true + } + + isRule, _ := rule.RulePopEnable(delCards) + ruleType := rule.Tienlen_Pass + if sceneEx.IsTienLenYule() { + isRule, ruleType = rule.RulePopEnable_yl(delCards) + } + + if !isRule { + logger.Logger.Errorf("出牌牌型错误 snid:%v, pos:%v, cards:%v", p.SnId, playerEx.GetPos(), params) + finishFunc() + return true + } + + switch { + case sceneEx.IsFirst(playerEx.GetPos()): + //当前操作者和上一个操作者是同一个人,必出牌 + if ruleType == rule.Plane_Single { //飞机带单只能最后一手出 + haveCardNum := 0 + for _, card := range playerEx.cards { + if card != rule.InvalideCard { + haveCardNum++ + } + } + if len(delCards) != haveCardNum { + logger.Logger.Trace("飞机带单只能最后一手出 Plane_Single, delCards:", delCards, " haveCardNum:", haveCardNum) + finishFunc() + return true + } + } + + if sceneEx.lastOpPos == rule.InvalidePos { //首出玩家 + //有赢家,赢家先出,出牌不受限制 + //无赢家,手持最小牌先出,最小牌必先出 + winPos := sceneEx.FindWinPos() + //logger.Logger.Trace("ScenePlayerOpStateTienLen,8params:", params, " winPos:", winPos) + if winPos == -1 { //无赢家 + haveMinCard := false + for _, card := range delCards { + if card == sceneEx.curMinCard { //最小牌必先出 + haveMinCard = true + } + } + //logger.Logger.Trace("ScenePlayerOpStateTienLen,9params:", params, " curMinCard:", sceneEx.curMinCard, " haveMinCard", haveMinCard) + if !haveMinCard { + finishFunc() + return true + } + } + isDel := sceneEx.DelCards(playerEx, delCards) + //logger.Logger.Trace("ScenePlayerOpStateTienLen,3params:", params, " isDel:", isDel) + if isDel { + playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) + + sceneEx.DoNext(int32(playerEx.GetPos())) + opRetCode = tienlen.OpResultCode_OPRC_Sucess + sceneEx.SetLastOpPos(int32(playerEx.GetPos())) + + sceneEx.RefreshPlayerHandLimitTimeOut() + } + } else { + isDel := sceneEx.DelCards(playerEx, delCards) + //logger.Logger.Trace("ScenePlayerOpStateTienLen,4params:", params, " isDel:", isDel) + if isDel { + playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) + + nextPos := sceneEx.DoNext(int32(playerEx.GetPos())) + //logger.Logger.Trace("ScenePlayerOpStateTienLen,4paramssss:", params, " nextPos:", nextPos) + if sceneEx.IsTienLenToEnd() && nextPos == rule.InvalidePos { + // 新一轮 + sceneEx.UnmarkPass() + nextPos = sceneEx.DoNext(int32(playerEx.GetPos())) + //logger.Logger.Trace("ScenePlayerOpStateTienLen,4paramssss:", params, " nextPos:", nextPos) + } + opRetCode = tienlen.OpResultCode_OPRC_Sucess + sceneEx.SetLastOpPos(int32(playerEx.GetPos())) + + sceneEx.RefreshPlayerHandLimitTimeOut() + } + } + if opRetCode == tienlen.OpResultCode_OPRC_Sucess { + isBomb := rule.IsFourBomb(delCards) + if isBomb { + sceneEx.isKongBomb = true + } + } + sceneEx.UnmarkPass() + + default: + //当前操作者和上一个操作者不是同一个人,必压制 + if playerEx.isPass { + finishFunc() + return true + } + + lastOpPlayer := sceneEx.GetLastOpPlayer() + //logger.Logger.Trace("ScenePlayerOpStateTienLen,5params:", params, " lastOpPlayer:", lastOpPlayer) + if lastOpPlayer == nil || len(lastOpPlayer.delCards) == 0 { + finishFunc() + return true + } + + lastDelCards := lastOpPlayer.delCards[len(lastOpPlayer.delCards)-1] + canDel, isBomb, bombScore := rule.CanDel(lastDelCards, delCards, sceneEx.IsTienLenToEnd()) + if sceneEx.IsTienLenYule() { + canDel, isBomb, bombScore = rule.CanDel_yl(lastDelCards, delCards, sceneEx.IsTienLenToEnd()) + } + //logger.Logger.Trace("ScenePlayerOpStateTienLen,6params:", params, " canDel:", canDel, " lastDelCards:", lastDelCards) + + if !canDel { + finishFunc() + return true + } + + if isBomb { + sceneEx.curBombPos = int32(playerEx.GetPos()) + sceneEx.lastBombPos = sceneEx.lastOpPos + sceneEx.roundScore += bombScore + } else { + sceneEx.curBombPos = rule.InvalidePos + sceneEx.lastBombPos = rule.InvalidePos + sceneEx.roundScore = 0 + } + + isDel := sceneEx.DelCards(playerEx, delCards) + //logger.Logger.Trace("ScenePlayerOpStateTienLen,7params:", params, " isDel:", isDel) + if !isDel { + finishFunc() + return true + } + + playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) + + nextPos := sceneEx.DoNext(int32(playerEx.GetPos())) + if sceneEx.IsTienLenToEnd() && nextPos == rule.InvalidePos { + sceneEx.UnmarkPass() + sceneEx.DoNext(int32(playerEx.GetPos())) + } + sceneEx.SetLastOpPos(int32(playerEx.GetPos())) + opRetCode = tienlen.OpResultCode_OPRC_Sucess + sceneEx.isKongBomb = false + + sceneEx.RefreshPlayerHandLimitTimeOut() + } + + case rule.TienLenPlayerOpPass: //过牌 + //当前操作者和上一个操作者是同一个人,必出牌,不能过牌 + if int32(playerEx.GetPos()) == sceneEx.lastOpPos || sceneEx.lastOpPos != rule.InvalidePos { + finishFunc() + return true + } + + playerEx.RefreshThinkLongCnt(time.Now().Sub(sceneEx.StateStartTime), false) + + sceneEx.card_play_action_seq = append(sceneEx.card_play_action_seq, fmt.Sprintf("%v-过", playerEx.GetPos())) + sceneEx.card_play_action_seq_int32 = append(sceneEx.card_play_action_seq_int32, []int32{-1}) + nextPos := sceneEx.DoNext(int32(playerEx.GetPos())) + + if sceneEx.IsTienLenToEnd() && nextPos == rule.InvalidePos { + sceneEx.UnmarkPass() + nextPos = sceneEx.DoNext(int32(playerEx.GetPos())) + sceneEx.SetLastOpPos(nextPos) + } + + sceneEx.RefreshPlayerHandLimitTimeOut() + opRetCode = tienlen.OpResultCode_OPRC_Sucess + playerEx.isPass = true + if nextPos == sceneEx.lastOpPos { //一轮都不出牌 + sceneEx.TrySmallGameBilled() + } + + case rule.TienLenPlayerClientHintCards: + if int32(playerEx.GetPos()) == sceneEx.lastOpPos || sceneEx.lastOpPos == rule.InvalidePos { + logger.Logger.Trace("ScenePlayerOpStateTienLen,107 OPRC_Error:", params, " opcode:", opcode, " snid:", p.SnId, " pos:", playerEx.GetPos()) + } else { + if len(params) > 0 { + sceneEx.cHintCards = make([]int32, len(params)+1) + sceneEx.cHintCards[0] = p.SnId + copy(sceneEx.cHintCards[1:], common.Int64ToInt32(params)) + opRetCode = tienlen.OpResultCode_OPRC_Hint + } + } + default: + opRetCode = tienlen.OpResultCode_OPRC_Error + } + + finishFunc() + return true }