game_sync/gamesrv/thirteen/scene.go

1456 lines
41 KiB
Go
Raw 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 thirteen
import (
"fmt"
"math"
"math/rand"
"sort"
"strings"
"time"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/game/common"
rule "mongo.games.com/game/gamerule/thirteen"
"mongo.games.com/game/gamesrv/base"
"mongo.games.com/game/proto"
"mongo.games.com/game/protocol/thirteen"
)
type PlayerData struct {
SnId int32
cards [13]int //手牌信息
cardsO *rule.Group //确定的牌型信息
isDP bool // 是否倒排
gainCoin int64 //本局赢的金币
taxCoin int64 //本局税收
clubPump int64 //俱乐部抽水
deterMine bool //玩家是否确定牌
score [7]int64 //玩家每墩的得分 0:头 1中 2尾 3:特殊牌型分数 4打枪 5全垒打 6离场补偿分
tableScore [6]int64 // 客户端展示
winThreePos map[int]int64 //只包含打枪玩家位置和总赢分
winAllPlayers map[int]int64 //玩家位置和输赢分
isStand bool //玩家站起 true打开 本局结束后自动离开房间 false未打开
isBilled bool // 是否结算
IsRob bool
Pos int
Coin int64
StartCoin int64
Head int32 //头像
flag int
Platform string //平台
Channel string //渠道信息
PackageID string //推广包标识 对应客户端的packagetag
PromoterTree int32
InviterId int32 //邀请人Id
WBLevel int32 //黑白名单 白:[1,10] 黑:[-1,-10]
CurIsWin int64 //当局输赢 负数:输 0平局 正数:赢
BeUnderAgentCode string //隶属经销商(推广人)
Name string //名字
Sex int32 //性别
City string //城市
Longitude int32 //经纬度
Latitude int32 //经纬度
AgentCode string //代理商编号
HeadOutLine int32 //头像框
VIP int32 //VIP帐号 等级
allGroup map[int]*rule.Group
TestLog []string
RoleId int32
PlayerPool int // 个人水池分
SkinId int32
}
type SceneEx struct {
*base.Scene //场景
poker *rule.Pokers // 扑克牌对象
logic *rule.Logic // 十三张算法
players map[int32]*PlayerEx // 玩家信息
seats []*PlayerEx // 本局游戏中的玩家状态数据
isCanAllHitPos int // 全垒打玩家坐标 =4人 并且没有特殊牌型
currOpPos int // 当前操作的玩家
hitTime time.Duration // 打枪阶段按打枪人数加时间
specialTime time.Duration // 亮牌阶段有特殊牌型增加时间
specialTypeNum int // 玩家有特殊牌的个数
entryHitState bool // 是否可以进入打枪阶段
robotNum int // 参与游戏的机器人数量
gamePlayerNum int // 参与游戏的人数量
r int // 体验场测试数据
cardsSlice [][13]int // 从大到小排列四副牌
nowMaxCardsIsIn bool // 现在最大牌是否还在
PlayerBackup map[int32]*PlayerData // 本局离场玩家数据备份
LeaveNum int // 离场扣分人数
testPokers []int64 // 测试牌堆
logid string
ctrlType int // 1控赢 2控输 0不控
}
func NewThirteenWaterSceneData(s *base.Scene) *SceneEx {
sceneEx := &SceneEx{
Scene: s,
logic: new(rule.Logic),
players: make(map[int32]*PlayerEx),
seats: make([]*PlayerEx, s.GetPlayerNum()),
PlayerBackup: make(map[int32]*PlayerData),
}
if s.GetPlayerNum() > 4 { // 两幅牌
sceneEx.poker = rule.NewPokers(2, sceneEx.HasLaiZi())
} else {
sceneEx.poker = rule.NewPokers(1, sceneEx.HasLaiZi())
}
if sceneEx.HasLaiZi() {
sceneEx.logic.LaiZi = []int{52, 53} // 目前只有大小王为癞子
}
return sceneEx
}
func (this *SceneEx) init() bool {
this.Clear()
return true
}
func (this *SceneEx) Clear() {
this.poker.Init()
this.isCanAllHitPos = -1
this.currOpPos = -1
this.hitTime = rule.ThirteenWaterHitTimeout
this.specialTypeNum = 0
this.entryHitState = false
this.robotNum = 0
this.gamePlayerNum = 0
this.r = 1
this.cardsSlice = nil
this.nowMaxCardsIsIn = true
this.PlayerBackup = make(map[int32]*PlayerData)
this.LeaveNum = 0
this.ctrlType = 0
for i := 0; i < this.GetPlayerNum(); i++ {
if this.seats[i] != nil {
this.seats[i].Clear()
}
}
}
func (this *SceneEx) delPlayer(p *base.Player) {
if p, exist := this.players[p.SnId]; exist {
this.seats[p.GetPos()] = nil
delete(this.players, p.SnId)
}
}
func (this *SceneEx) BroadcastPlayerLeave(p *base.Player, reason int) {
scLeavePack := &thirteen.SCThirteenPlayerLeave{
Pos: proto.Int(p.GetPos()),
}
proto.SetDefaults(scLeavePack)
this.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerLeave), scLeavePack, p.GetSid())
}
func (this *SceneEx) OnPlayerLeave(p *base.Player, reason int) {
this.delPlayer(p)
this.BroadcastPlayerLeave(p, reason)
}
func (this *SceneEx) SceneDestroy(force bool) {
//销毁房间
this.Scene.Destroy(force)
}
func (this *SceneEx) CanStart() bool {
//房间人数>=2自动开始,并且有真人或者是预创建房间
if len(this.players) >= 2 && (this.GetRealPlayerNum() > 0 || this.IsPreCreateScene()) {
return true
}
return false
}
func (this *SceneEx) ThirteenWaterCreateRoomInfoPacket(s *base.Scene, p *base.Player) interface{} {
pack := &thirteen.SCThirteenRoomInfo{
RoomId: proto.Int(s.GetSceneId()),
Creator: proto.Int32(s.GetCreator()),
GameId: proto.Int(s.GetGameId()),
RoomMode: proto.Int(s.GetSceneMode()),
SceneType: s.GetDBGameFree().SceneType,
State: proto.Int(s.GetSceneState().GetState()),
TimeOut: proto.Int(s.GetSceneState().GetTimeout(s)),
DisbandGen: proto.Int(this.GetDisbandGen()),
BaseScore: int32(this.GetBaseScore()),
LeaveDeduct: this.GetDBGameFree().GetLeaveDeduct(),
LeaveCombat: this.GetDBGameFree().GetLeaveCombat(),
Params: common.CopySliceInt64ToInt32(s.Params),
}
// 玩家信息
for _, playerEx := range this.players {
pd := &thirteen.ThirteenPlayerData{
SnId: proto.Int32(playerEx.SnId),
Name: proto.String(playerEx.Name),
Head: proto.Int32(playerEx.Head),
Sex: proto.Int32(playerEx.Sex),
Coin: proto.Int64(playerEx.Coin),
Pos: proto.Int(playerEx.Pos),
Flag: proto.Int(playerEx.GetFlag()),
Longitude: proto.Int32(playerEx.Longitude),
Latitude: proto.Int32(playerEx.Latitude),
City: proto.String(playerEx.City),
AgentCode: proto.String(playerEx.AgentCode),
HeadOutLine: proto.Int32(playerEx.HeadOutLine),
VIP: proto.Int32(playerEx.VIP),
IsStand: proto.Bool(playerEx.isStand),
IsConfirm: proto.Bool(playerEx.deterMine),
RoleId: playerEx.PlayerData.GetRoleId(),
Level: proto.Int64(playerEx.PlayerData.Level),
Exp: proto.Int64(playerEx.PlayerData.Exp),
}
if playerEx.Skin != nil {
pd.SkinId = playerEx.Skin.ModId
}
ppp := &thirteen.Poker{}
ppp.IndexType = -1
pd.CardsO = ppp
if playerEx.cardsO != nil {
if playerEx.cardsO.PokerType > 0 {
//确定之后为特殊牌型
ppp := &thirteen.Poker{}
ppp.Head = common.CopySliceIntToInt32(playerEx.cards[:3])
ppp.Mid = common.CopySliceIntToInt32(playerEx.cards[3:8])
ppp.End = common.CopySliceIntToInt32(playerEx.cards[8:])
ppp.IndexType = proto.Int32(int32(playerEx.cardsO.PokerType * 1000000))
pd.CardsO = ppp
pd.IsDP = playerEx.isDP
} else if playerEx.cardsO.PokerType == 0 {
//确定之后为普通牌型
ppp := &thirteen.Poker{}
ppp.Head = common.CopySliceIntToInt32(playerEx.cardsO.Head[:])
ppp.Mid = common.CopySliceIntToInt32(playerEx.cardsO.Mid[:])
ppp.End = common.CopySliceIntToInt32(playerEx.cardsO.End[:])
ppp.IndexType = proto.Int32(int32(this.FormatCards(playerEx.cardsO)))
pd.CardsO = ppp
pd.IsDP = playerEx.isDP
}
}
if playerEx.cards[0] != -1 {
pd.Cards = common.CopySliceIntToInt32(playerEx.cards[:])
}
if playerEx.allGroup != nil {
pd.AllCardsO, _ = AllGroupToProto(playerEx.allGroup)
}
if p == nil || playerEx.SnId != p.SnId {
if s.SceneState.GetState() == rule.ThirteenWaterSceneStateSendCards ||
s.SceneState.GetState() == rule.ThirteenWaterSceneStateOptCard {
pd.Cards = nil
pd.AllCardsO = nil
if pd.CardsO.IndexType > 0 {
ppp := &thirteen.Poker{}
ppp.IndexType = 0
pd.CardsO = ppp
pd.IsDP = false
}
}
}
if s.SceneState.GetState() == rule.ThirteenWaterSceneStateShowCards ||
s.SceneState.GetState() == rule.ThirteenWaterSceneStateHit ||
s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled {
pd.Score = playerEx.score[:]
pd.TableScore = playerEx.tableScore[:]
var hitScore []*thirteen.HitScore
for k, v := range playerEx.winThreePos {
pck := &thirteen.HitScore{
Pos: proto.Int32(int32(k)),
Score: proto.Int64(v),
}
hitScore = append(hitScore, pck)
}
pd.Hit = hitScore
}
if s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled {
pd.WinCoin = playerEx.gainCoin
}
pack.Players = append(pack.Players, pd)
}
// 备份的玩家信息
for _, playerEx := range this.PlayerBackup {
if playerEx != nil || !playerEx.isBilled {
continue
}
pd := &thirteen.ThirteenPlayerData{
SnId: proto.Int32(playerEx.SnId),
Name: proto.String(playerEx.Name),
Head: proto.Int32(playerEx.Head),
Sex: proto.Int32(playerEx.Sex),
Coin: proto.Int64(playerEx.Coin),
Pos: proto.Int(playerEx.Pos),
Flag: proto.Int(playerEx.flag),
Longitude: proto.Int32(playerEx.Longitude),
Latitude: proto.Int32(playerEx.Latitude),
City: proto.String(playerEx.City),
AgentCode: proto.String(playerEx.AgentCode),
HeadOutLine: proto.Int32(playerEx.HeadOutLine),
VIP: proto.Int32(playerEx.VIP),
IsStand: proto.Bool(playerEx.isStand),
IsConfirm: proto.Bool(playerEx.deterMine),
IsLeave: true,
RoleId: playerEx.RoleId,
SkinId: playerEx.SkinId,
}
ppp := &thirteen.Poker{}
ppp.IndexType = -1
pd.CardsO = ppp
if playerEx.cardsO != nil {
if playerEx.cardsO.PokerType > 0 {
//确定之后为特殊牌型
ppp := &thirteen.Poker{}
ppp.Head = common.CopySliceIntToInt32(playerEx.cards[:3])
ppp.Mid = common.CopySliceIntToInt32(playerEx.cards[3:8])
ppp.End = common.CopySliceIntToInt32(playerEx.cards[8:])
ppp.IndexType = proto.Int32(int32(playerEx.cardsO.PokerType * 1000000))
pd.CardsO = ppp
pd.IsDP = playerEx.isDP
} else if playerEx.cardsO.PokerType == 0 {
//确定之后为普通牌型
ppp := &thirteen.Poker{}
ppp.Head = common.CopySliceIntToInt32(playerEx.cardsO.Head[:])
ppp.Mid = common.CopySliceIntToInt32(playerEx.cardsO.Mid[:])
ppp.End = common.CopySliceIntToInt32(playerEx.cardsO.End[:])
ppp.IndexType = proto.Int32(int32(this.FormatCards(playerEx.cardsO)))
pd.CardsO = ppp
pd.IsDP = playerEx.isDP
}
}
if playerEx.cards[0] != -1 {
pd.Cards = common.CopySliceIntToInt32(playerEx.cards[:])
}
if playerEx.allGroup != nil {
pd.AllCardsO, _ = AllGroupToProto(playerEx.allGroup)
}
if p == nil || playerEx.SnId != p.SnId {
if s.SceneState.GetState() == rule.ThirteenWaterSceneStateSendCards ||
s.SceneState.GetState() == rule.ThirteenWaterSceneStateOptCard {
pd.Cards = nil
pd.AllCardsO = nil
if pd.CardsO.IndexType > 0 {
ppp := &thirteen.Poker{}
ppp.IndexType = 0
pd.CardsO = ppp
pd.IsDP = false
}
}
}
if s.SceneState.GetState() == rule.ThirteenWaterSceneStateShowCards ||
s.SceneState.GetState() == rule.ThirteenWaterSceneStateHit ||
s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled {
pd.Score = playerEx.score[:]
pd.TableScore = playerEx.tableScore[:]
var hitScore []*thirteen.HitScore
for k, v := range playerEx.winThreePos {
pck := &thirteen.HitScore{
Pos: proto.Int32(int32(k)),
Score: proto.Int64(v),
}
hitScore = append(hitScore, pck)
}
pd.Hit = hitScore
}
if s.SceneState.GetState() == rule.ThirteenWaterSceneStateBilled {
pd.WinCoin = playerEx.gainCoin
}
pack.Players = append(pack.Players, pd)
}
proto.SetDefaults(pack)
if p != nil {
p.SyncFlag()
}
logger.Logger.Trace("SCThirteenWaterRoomInfo:", pack)
return pack
}
func (this *SceneEx) GetBaseScore() int64 { //游戏底分
if this.GetDBGameFree().FreeMode == 1 {
baseScore := this.GetParam(rule.ParamBaseScore)
if baseScore > 0 {
return baseScore
}
}
if this.GetDBGameFree() != nil {
return int64(this.GetDBGameFree().GetBaseScore())
}
return 1
}
func (this *SceneEx) GetBaiPai() time.Duration {
s := this.GetParam(rule.ParamBaiPai)
if s > 0 {
return time.Duration(s) * time.Second
}
return rule.ThirteenWaterOptCardTimeout
}
func (this *SceneEx) HasLaiZi() bool {
s := this.GetParam(rule.ParamLaiZi)
if s >= 0 {
return s == 1
}
return false
}
func (this *SceneEx) AutoCombine() bool {
s := this.GetParam(rule.ParamAuto)
if s >= 0 {
return s == 0
}
return true
}
// GetLeaveDeductCoin 离场扣分
func (this *SceneEx) GetLeaveDeductCoin() int64 {
return int64(this.GetDBGameFree().GetLeaveDeduct()) * int64(this.GetBaseScore())
}
func (this *SceneEx) GetScore(player *PlayerEx) {
if player == nil || player.isDP {
return
}
// 计算特殊牌型分数
ptRate := int64(0)
//清龙* 一条龙* 十二皇族 三同花顺* 三分天下 全大 全小 凑一色* 四套三条 五对三条 六对半* 三顺子* 三同花
if player.cardsO.PokerType != 0 {
this.specialTypeNum++
//特殊牌处理
if player.cardsO.PokerType >= 1 && player.cardsO.PokerType <= 13 {
ptRate = rule.SpecialScore[player.cardsO.PokerType]
}
}
if this.specialTypeNum > 0 {
for _, p := range this.players {
if p != nil && p.IsGameing() && player.cardsO.PokerType != 0 {
if player.Pos == p.Pos {
continue
}
if p.cardsO.PokerType == 0 || p.isDP {
player.score[3] += ptRate
p.score[3] -= ptRate
player.winAllPlayers[p.Pos] += ptRate
p.winAllPlayers[player.Pos] -= ptRate
} else if p.cardsO.PokerType != 0 {
//多个特殊牌型处理
if player.cardsO.PokerType < p.cardsO.PokerType {
player.score[3] += ptRate
p.score[3] -= ptRate
player.winAllPlayers[p.Pos] += ptRate
p.winAllPlayers[player.Pos] -= ptRate
}
}
}
}
}
// 计算普通牌型分数
for _, p := range this.players {
if p != nil && p.IsGameing() && player.cardsO.PokerType == 0 {
if player.Pos == p.Pos || p.cardsO.PokerType != 0 {
continue
}
s := 0
score := int64(0) //赢的分数
//头墩
rate := int64(1)
n := this.logic.CompareHead(player.cardsO.Head, p.cardsO.Head)
h := this.logic.GetType(player.cardsO.Head[:])
if h == rule.PokersTypeThree {
rate += 2
}
if n == 1 || p.isDP {
player.score[0] += rate
p.score[0] -= rate
score += rate
s++
player.winAllPlayers[p.Pos] += rate
p.winAllPlayers[player.Pos] -= rate
player.tableScore[3] += rate - 1
}
//中墩
rate = int64(1)
n = this.logic.CompareFive(player.cardsO.Mid, p.cardsO.Mid)
m := this.logic.GetType(player.cardsO.Mid[:])
if m == rule.PokersTypeFullHouse {
rate += 1
} else if m == rule.PokersTypeFour {
rate += 6
} else if m == rule.PokersTypeStraightFlush {
rate += 8
} else if m == rule.PokersTypeFive {
rate += 10
}
if n == 1 || p.isDP {
player.score[1] += rate
p.score[1] -= rate
score += rate
s++
player.winAllPlayers[p.Pos] += rate
p.winAllPlayers[player.Pos] -= rate
player.tableScore[4] += rate - 1
}
//尾墩
rate = int64(1)
n = this.logic.CompareFive(player.cardsO.End, p.cardsO.End)
e := this.logic.GetType(player.cardsO.End[:])
if e == rule.PokersTypeFour {
rate += 3
} else if e == rule.PokersTypeStraightFlush {
rate += 4
} else if e == rule.PokersTypeFive {
rate += 5
}
if n == 1 || p.isDP {
player.score[2] += rate
p.score[2] -= rate
score += rate
s++
player.winAllPlayers[p.Pos] += rate
p.winAllPlayers[player.Pos] -= rate
player.tableScore[5] += rate - 1
}
if s == 3 {
player.winThreePos[p.Pos] = score
}
}
}
}
// 发送玩家的所有牌和所有牌型
func (this *SceneEx) SendToPlayerCards(s *base.Scene) {
for _, player := range this.players {
if player != nil && player.IsGameing() {
all, k := AllGroupToProto(player.allGroup)
pack := &thirteen.SCThirteenPlayerCards{
Cards: common.CopySliceIntToInt32(player.cards[:]),
Pos: proto.Int32(int32(player.Pos)),
AllCardsO: all,
}
// 记录默认牌型
if k > 0 {
player.defGroup = player.allGroup[k]
}
if len(pack.AllCardsO) == 0 {
logger.Logger.Warnf("no poker suggest: %v %v", player.cards, rule.PokersShow(player.cards[:]))
// 没有推荐牌,随便给个数据
pack.AllCardsO = []*thirteen.Poker{
{
IndexType: 90909,
Head: common.CopySliceIntToInt32(player.cards[:3]),
Mid: common.CopySliceIntToInt32(player.cards[3:8]),
End: common.CopySliceIntToInt32(player.cards[8:]),
},
}
}
proto.SetDefaults(pack)
logger.Logger.Trace("SCThirteenWaterPlayerCards:", pack)
player.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerCards), pack)
Send := &thirteen.SCThirteenPlayerCards{
Pos: proto.Int32(int32(player.Pos)),
}
proto.SetDefaults(Send)
logger.Logger.Trace("SCThirteenWaterPlayerCards:", Send)
s.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerCards), Send, player.GetSid())
}
}
}
func AllGroupToProto(allGroup map[int]*rule.Group) ([]*thirteen.Poker, int) {
var pack []*thirteen.Poker
for k, v := range allGroup {
p := &thirteen.Poker{
Head: common.CopySliceIntToInt32(v.Head[:]),
Mid: common.CopySliceIntToInt32(v.Mid[:]),
End: common.CopySliceIntToInt32(v.End[:]),
IndexType: proto.Int32(int32(k)),
}
pack = append(pack, p)
}
sort.Slice(pack, func(i, j int) bool {
ii := pack[i]
jj := pack[j]
// 特殊牌在前面
if ii.IndexType >= 1000000 && jj.IndexType >= 1000000 {
return ii.IndexType < jj.IndexType
}
if ii.IndexType >= 1000000 {
return true
}
if jj.IndexType >= 1000000 {
return false
}
// 普通牌型,从尾墩到头墩大的在前面
if ii.IndexType%100 < jj.IndexType%100 {
return true
} else if ii.IndexType%100 > jj.IndexType%100 {
return false
}
if ii.IndexType%10000/100 < jj.IndexType%10000/100 {
return true
} else if ii.IndexType%10000/100 > jj.IndexType%10000/100 {
return false
}
if ii.IndexType/10000 < jj.IndexType/10000 {
return true
} else if ii.IndexType/10000 > jj.IndexType/10000 {
return false
}
return false
})
//for _, v := range pack {
// logger.Logger.Tracef("AllGroupToProto: %v %v %v %v", v.IndexType, rule.PokersShow(common.CopySliceInt32ToInt(v.Head)), rule.PokersShow(common.CopySliceInt32ToInt(v.Mid)), rule.PokersShow(common.CopySliceInt32ToInt(v.End)))
//}
if len(pack) > 0 {
return pack, int(pack[0].IndexType)
}
return pack, 0
}
// CheckIsCanHit 检查是否可以打枪
func (this *SceneEx) CheckIsCanHit() bool {
pt := 0 //特殊牌型数量
isHit := 0 //几个人可以打枪
for _, v := range this.players {
if v != nil && v.IsGameing() {
if v.cardsO.PokerType != 0 {
pt++
}
//全垒打: 打枪所有人并且至少打3人
if len(v.winThreePos) >= 3 && len(v.winThreePos) == this.gamePlayerNum-1 {
this.isCanAllHitPos = v.Pos
}
if len(v.winThreePos) > 0 {
isHit++
}
}
}
// 人数至少2人
if /*pt == 0 &&*/ this.gamePlayerNum >= 2 && isHit > 0 {
return true
}
this.isCanAllHitPos = -1
return false
}
func (this *SceneEx) SelectCards(p *PlayerEx, indexType int) *rule.Group {
switch indexType {
case -1: // 使用特殊牌型
for k, v := range p.allGroup {
if k >= 1000000 {
p.cardsO = v
break
}
}
case -2: // 使用牌值最大的牌型
this.GetMaxCardsO(p)
// 真人默认选牌规则
if !p.IsRob && p.defGroup != nil {
p.cardsO = p.defGroup
}
}
if indexType > 10000 { // 从推荐牌中选一个
c := p.allGroup[indexType]
if c != nil {
p.cardsO = c
}
}
// 还没有确认就随机推荐一个
if p.cardsO == nil || p.cardsO.PokerType == -1 {
for k, v := range p.allGroup {
p.cardsO = v
if k >= 1000000 {
break
}
}
logger.Logger.Tracef("随机推荐SnId(%v) %v", p.SnId, p.cardsO)
}
return p.cardsO
}
// SendSelectCards 玩家选择特定的牌显示
func (this *SceneEx) SendSelectCards(player *PlayerEx, indexType int, opcode int64) {
ShowCardsO := this.SelectCards(player, indexType)
pack := &thirteen.SCThirteenPlayerOp{
OpRetCode: thirteen.OpResultCode_OPRC_Sucess,
OpCode: int32(opcode),
Pos: proto.Int32(int32(player.Pos)),
Cards: &thirteen.Poker{},
}
if indexType == -1 || indexType >= 1000000 { // 特殊牌
pack.Cards.Head = common.CopySliceIntToInt32(player.cards[:3])
pack.Cards.Mid = common.CopySliceIntToInt32(player.cards[3:8])
pack.Cards.End = common.CopySliceIntToInt32(player.cards[8:])
} else {
// 自动组牌或玩家自选
pack.Cards.Head = common.CopySliceIntToInt32(ShowCardsO.Head[:])
pack.Cards.Mid = common.CopySliceIntToInt32(ShowCardsO.Mid[:])
pack.Cards.End = common.CopySliceIntToInt32(ShowCardsO.End[:])
pack.Cards.IsDP = this.logic.IsDP(ShowCardsO.Head, ShowCardsO.Mid, ShowCardsO.End)
}
pack.Cards.IndexType = proto.Int32(int32(this.FormatCards(ShowCardsO)))
pack.Cards.Pos = int32(player.GetPos())
proto.SetDefaults(pack)
logger.Logger.Trace("SCThirteenPlayerOp1:", pack)
player.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack)
pack.Cards.Head = nil
pack.Cards.Mid = nil
pack.Cards.End = nil
pack.Cards.IndexType = 0
pack.Cards.IsDP = false
logger.Logger.Trace("SCThirteenPlayerOp2:", pack)
this.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack, player.GetSid())
for _, v := range this.seats {
if v == nil {
continue
}
if v.SnId != player.SnId && v.IsRobot() {
logger.Logger.Trace("SCThirteenPlayerOpRobot:", pack)
v.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack)
}
}
}
func (this *SceneEx) FormatCards(cardsO *rule.Group) int {
num := 0
if cardsO != nil && cardsO.PokerType != 0 {
num = cardsO.PokerType * 1000000
} else if cardsO != nil && cardsO.PokerType == 0 && cardsO.Head[0] != -1 {
num += this.logic.GetType(cardsO.Head[:]) * 10000
num += this.logic.GetType(cardsO.Mid[:]) * 100
num += this.logic.GetType(cardsO.End[:])
}
return num
}
// GetMinCards 默认获取玩家最小牌值的类型
func (this *SceneEx) GetMinCards(player *PlayerEx) {
min := 1000000
for v, m := range player.allGroup {
sum := 0
if v >= 1000000 {
continue
}
a := v / 10000
b := (v - a*10000) / 100
c := v - a*10000 - b*100
s := []int{a, b, c}
for _, k := range s {
if k >= 1 && k <= 20 {
sum += 20 - k
}
}
if min >= sum {
min = sum
player.cardsO = m
}
}
}
func (this *SceneEx) GetRandsType() (playerCards [13]int) {
//r := rand.Intn(15) + 1
//全垒打
//playerCards = [13]int{9, 9 + 13, 9 + 13*2, 2, 3, 4, 5, 6, 3 + 13, 4 + 13, 5 + 13, 6 + 13, 7 + 13}
//return
c := [][13]int{
//清龙
{39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51},
//一条龙
{13, 14, 28, 29, 30, 44, 45, 7, 34, 9, 23, 11, 51},
//十二皇族
{9, 10, 23, 36, 49, 11, 24, 37, 50, 12, 25, 38, 51},
//三同花顺
{1, 2, 3, 4, 5, 15, 16, 17, 18, 19, 27, 28, 29},
//三分天下
{10, 23, 36, 49, 11, 24, 37, 50, 12, 25, 38, 51, 13},
//全大
{7, 21, 35, 23, 11, 38, 51, 33, 48, 49, 50, 12, 25},
//全小
{14, 27, 40, 15, 28, 41, 4, 17, 5, 18, 6, 19, 32},
//凑一色
{13, 14, 40, 16, 42, 18, 44, 19, 46, 47, 23, 49, 25},
//四套三条
{5, 18, 44, 6, 19, 32, 7, 33, 46, 10, 23, 36, 50},
//五对三条
{17, 30, 5, 31, 6, 32, 8, 47, 23, 36, 12, 25, 38},
//六对半
{17, 30, 5, 31, 6, 32, 8, 47, 23, 36, 38, 51, 39},
//三顺子
{1, 28, 16, 17, 18, 30, 31, 45, 20, 8, 36, 50, 12},
//三同花
{2, 3, 6, 4 + 13, 8 + 13, 9 + 13, 13, 25, 31, 34, 27, 28, 29},
}
if this.r < 12 {
this.r++
} else {
this.r = 1
}
playerCards = c[this.r]
return
}
// SortCards 把所有牌排序
//func (this *SceneEx) SortCards() {
// //确定所有玩家拿可以拿到的最大牌型
// for _, player := range this.players {
// if player != nil && player.IsGameing() {
// this.GetMaxCardsO(player)
// }
// }
// //计算总分数
// this.CountScore()
// scoreMap := make(map[int]int64)
// for _, player := range this.seats {
// if player != nil && player.IsGameing() {
// score := int64(0)
// //计算玩家输赢的分数
// for _, v := range player.score {
// score += v
// }
// scoreMap[player.Pos] = score
// }
// }
// for i := 0; i < 6; i++ {
// max := int64(-1000)
// pos := -1
// for k, v := range scoreMap {
// if max <= v {
// max = v
// pos = k
// }
// }
// if pos != -1 {
// delete(scoreMap, pos)
// this.cardsSlice = append(this.cardsSlice, this.seats[pos].cards)
// this.seats[pos].cards = [13]int{-1}
// if len(scoreMap) == 0 {
// break
// }
// }
// }
//}
// GetMaxCardsO 一副牌中拿最大牌值的方案
func (this *SceneEx) GetMaxCardsO(p *PlayerEx) {
if p != nil {
p.cardsO = rule.GetMaxCard(p.allGroup)
}
}
// cardsSort 按从大到小的排列发牌
func (this *SceneEx) cardsSort(cardArr [][13]int, cardGroup []map[int]*rule.Group) {
type P struct {
i int
score [6]int64
cardsO *rule.Group
cards [13]int
group map[int]*rule.Group
winThreePos map[int]int64
winAllPlayers map[int]int64
}
var ps []*P
for i := 0; i < len(cardArr); i++ {
p := &P{
i: i,
score: [6]int64{0, 0, 0, 0, 0, 0},
cardsO: rule.GetMaxCard(cardGroup[i]),
cards: cardArr[i],
group: cardGroup[i],
winThreePos: map[int]int64{},
winAllPlayers: map[int]int64{},
}
ps = append(ps, p)
}
var specialTypeNum int
for i := 0; i < len(cardArr); i++ {
player := ps[i]
// 计算特殊牌型分数
ptRate := int64(0)
if player.cardsO.PokerType != 0 {
specialTypeNum++
//特殊牌处理
if player.cardsO.PokerType >= 1 && player.cardsO.PokerType <= 13 {
ptRate = rule.SpecialScore[player.cardsO.PokerType]
}
}
if specialTypeNum > 0 {
for _, p := range ps {
if player.cardsO.PokerType != 0 {
if player.i == p.i {
continue
}
if p.cardsO.PokerType == 0 {
player.score[3] += ptRate
p.score[3] -= ptRate
player.winAllPlayers[p.i] += ptRate
p.winAllPlayers[player.i] -= ptRate
} else if p.cardsO.PokerType != 0 {
//多个特殊牌型处理
if player.cardsO.PokerType < p.cardsO.PokerType {
player.score[3] += ptRate
p.score[3] -= ptRate
player.winAllPlayers[p.i] += ptRate
p.winAllPlayers[player.i] -= ptRate
}
}
}
}
}
// 计算普通牌型分数
for _, p := range ps {
if player.cardsO.PokerType == 0 {
if player.i == p.i || p.cardsO.PokerType != 0 {
continue
}
s := 0
score := int64(0) //赢的分数
//头墩
rate := int64(1)
n := this.logic.CompareHead(player.cardsO.Head, p.cardsO.Head)
h := this.logic.GetType(player.cardsO.Head[:])
if h == rule.PokersTypeThree {
rate += 2
}
if n == 1 {
player.score[0] += rate
p.score[0] -= rate
score += rate
player.winAllPlayers[p.i] += rate
p.winAllPlayers[player.i] -= rate
s++
}
//中墩
rate = int64(1)
n = this.logic.CompareFive(player.cardsO.Mid, p.cardsO.Mid)
m := this.logic.GetType(player.cardsO.Mid[:])
if m == rule.PokersTypeFullHouse {
rate += 1
} else if m == rule.PokersTypeFour {
rate += 6
} else if m == rule.PokersTypeStraightFlush {
rate += 8
} else if m == rule.PokersTypeFive {
rate += 10
}
if n == 1 {
player.score[1] += rate
p.score[1] -= rate
score += rate
player.winAllPlayers[p.i] += rate
p.winAllPlayers[player.i] -= rate
s++
}
//尾墩
rate = int64(1)
n = this.logic.CompareFive(player.cardsO.End, p.cardsO.End)
e := this.logic.GetType(player.cardsO.End[:])
if e == rule.PokersTypeFour {
rate += 3
} else if e == rule.PokersTypeStraightFlush {
rate += 4
} else if e == rule.PokersTypeFive {
rate += 5
}
if n == 1 {
player.score[2] += rate
p.score[2] -= rate
score += rate
player.winAllPlayers[p.i] += rate
p.winAllPlayers[player.i] -= rate
s++
}
if s == 3 {
player.winThreePos[p.i] = score
}
}
}
}
// 打枪分
isCanAllHitPos := -1
pt := 0 //特殊牌型数量
isHit := 0 //几个人可以打枪
for _, v := range ps {
if v.cardsO.PokerType != 0 {
pt++
}
//全垒打: 打枪所有人并且至少打3人
if len(v.winThreePos) >= 3 && len(v.winThreePos) == this.gamePlayerNum-1 {
isCanAllHitPos = v.i
}
if len(v.winThreePos) > 0 {
isHit++
}
}
// 可以打枪:没有特殊牌型人数至少2人
if pt == 0 && this.gamePlayerNum >= 2 && isHit > 0 {
for _, playerEx := range ps {
if len(playerEx.winThreePos) > 0 {
for k, v := range playerEx.winThreePos {
// 打枪
ps[k].score[4] -= v
ps[k].winAllPlayers[playerEx.i] -= v
playerEx.score[4] += v
playerEx.winAllPlayers[k] += v
// 全垒打分数
if playerEx.i == isCanAllHitPos {
ps[k].score[5] -= v
ps[k].winAllPlayers[playerEx.i] -= v
playerEx.score[5] += v
playerEx.winAllPlayers[k] += v
}
}
}
}
}
sort.Slice(ps, func(i, j int) bool {
var a, b int64
for _, v := range ps[i].score {
a += v
}
for _, v := range ps[j].score {
b += v
}
return a > b
})
for i := 0; i < len(cardArr); i++ {
cardArr[i] = ps[i].cards
cardGroup[i] = ps[i].group
}
}
// CountScore 计算总分数
func (this *SceneEx) CountScore() {
//计算头、中、尾道、特殊牌分数
for _, player := range this.seats {
if player != nil && player.IsGameing() {
this.GetScore(player)
// 离场补偿分
if this.LeaveNum > 0 {
player.score[6] = int64(this.LeaveNum) * int64(this.GetDBGameFree().GetLeaveCombat())
}
}
}
for _, player := range this.seats {
if player != nil && player.IsGameing() {
for i := 0; i < 3; i++ {
player.tableScore[i] = player.score[i] - player.tableScore[i+3]
}
}
}
this.entryHitState = this.CheckIsCanHit()
if !this.entryHitState {
//如果不能进入打枪阶段 不计算打枪和全垒打
return
}
//计算打枪分数
for _, playerEx := range this.players {
if playerEx != nil && playerEx.IsGameing() {
if len(playerEx.winThreePos) > 0 {
for k, v := range playerEx.winThreePos {
// 并且都不是特殊牌型
if playerEx.cardsO.PokerType != 0 || this.seats[k].cardsO.PokerType != 0 {
continue
}
// 打枪
this.seats[k].score[4] -= v
this.seats[k].winAllPlayers[playerEx.Pos] -= v
playerEx.score[4] += v
playerEx.winAllPlayers[k] += v
// 全垒打分数
if playerEx.Pos == this.isCanAllHitPos {
this.seats[k].score[5] -= v
this.seats[k].winAllPlayers[playerEx.Pos] -= v
playerEx.score[5] += v
playerEx.winAllPlayers[k] += v
}
}
}
}
}
}
func (this *SceneEx) GetInGameNum() {
for _, v := range this.players {
if v != nil && v.IsGameing() {
this.gamePlayerNum++
if v.IsRob {
this.robotNum++
}
}
}
}
// 获取最小牌
func (this *SceneEx) GetAllMinCards() (a [13]int) {
for i := len(this.cardsSlice) - 1; i >= 0; i-- {
a = this.cardsSlice[i]
this.cardsSlice[i] = [13]int{-1}
this.cardsSlice = append(this.cardsSlice[:i], this.cardsSlice[i+1:]...)
break
}
return [13]int{-1}
}
// 获取最大牌
func (this *SceneEx) GetAllMaxCards() (a [13]int) {
if this.nowMaxCardsIsIn {
this.nowMaxCardsIsIn = false
}
for i := 0; i < len(this.cardsSlice); i++ {
a = this.cardsSlice[i]
this.cardsSlice = append(this.cardsSlice[:i], this.cardsSlice[i+1:]...)
break
}
return [13]int{-1}
}
// 随机拿牌
func (this *SceneEx) GetRandCards(b bool) (a [13]int) {
n := len(this.cardsSlice)
if n == 0 {
return [13]int{-1}
}
r := rand.Intn(n)
if !b {
if this.nowMaxCardsIsIn {
//最大牌还在
//不带最大牌随机
if n == 1 {
//就剩一副牌
return [13]int{-1}
}
if r == 0 {
//随到最大牌
r++
}
}
} else {
//带最大牌随机
if this.nowMaxCardsIsIn {
if r == 0 {
this.nowMaxCardsIsIn = false
}
}
}
a = this.cardsSlice[r]
this.cardsSlice = append(this.cardsSlice[:r], this.cardsSlice[r+1:]...)
return
}
func (this *SceneEx) ShowCards() {
var allCards []*thirteen.Poker
for _, p := range this.players {
if p != nil && p.IsGameing() && p.cardsO != nil {
var hitScore []*thirteen.HitScore
for k, v := range p.winThreePos {
pck := &thirteen.HitScore{
Pos: proto.Int32(int32(k)),
Score: proto.Int64(v),
}
hitScore = append(hitScore, pck)
}
pk := &thirteen.Poker{
IndexType: proto.Int32(int32(this.FormatCards(p.cardsO))),
Head: common.IntSliceToInt32(p.cardsO.Head[:]),
Mid: common.IntSliceToInt32(p.cardsO.Mid[:]),
End: common.IntSliceToInt32(p.cardsO.End[:]),
IsDP: p.isDP,
Pos: int32(p.GetPos()),
Score: p.score[:],
Hit: hitScore,
TableScore: p.tableScore[:],
Cards: common.IntSliceToInt32(p.cards[:]),
}
allCards = append(allCards, pk)
}
}
opCode := 0
if this.GetSceneState().GetState() == rule.ThirteenWaterSceneStateHit {
opCode = 1 // 打枪
}
pc := &thirteen.SCThirteenShowCards{
OpCode: proto.Int32(int32(opCode)),
AllCards: allCards,
}
proto.SetDefaults(pc)
logger.Logger.Trace("SCThirteenWaterShowCards is pc: ", pc)
this.Broadcast(int(thirteen.TWMmoPacketID_PACKET_SCThirteenShowCards), pc, 0)
}
func (this *SceneEx) CountBilled() {
var totalWinScore, totalLoseScore int64 // 总赢分
for _, v := range this.players {
if v != nil && v.IsGameing() {
// 玩家总分
v.totalScore = 0
for _, vv := range v.score[:6] {
v.totalScore += vv
}
v.totalScore *= int64(this.GetBaseScore())
if v.totalScore > 0 {
if v.totalScore > v.Coin {
v.totalScore = v.Coin
}
} else if v.totalScore < 0 {
if v.totalScore < -v.Coin {
v.totalScore = -v.Coin
}
}
// 总输赢分
if v.totalScore > 0 {
totalWinScore += v.totalScore
} else if v.totalScore < 0 {
totalLoseScore += -v.totalScore
}
logger.Logger.Tracef("玩家[%d]总赢分: %d", v.GetPos(), v.totalScore)
}
}
if totalWinScore > totalLoseScore {
// 赢分大,输分玩家分数不需要修改
for _, v := range this.players {
if v != nil && v.IsGameing() {
if v.totalScore > 0 {
v.gainCoin = int64(float64(v.totalScore) * float64(totalLoseScore) / float64(totalWinScore))
} else if v.totalScore < 0 {
v.gainCoin = v.totalScore
}
}
}
} else if totalWinScore < totalLoseScore {
// 输分大,赢分玩家分数不需要修改
for _, v := range this.players {
if v != nil && v.IsGameing() {
if v.totalScore > 0 {
v.gainCoin = v.totalScore
} else if v.totalScore < 0 {
v.gainCoin = int64(float64(v.totalScore) * float64(totalLoseScore) / float64(totalWinScore))
}
}
}
} else {
for _, v := range this.players {
if v != nil && v.IsGameing() {
v.gainCoin = v.totalScore
}
}
}
for _, playerEx := range this.players {
if playerEx == nil || !playerEx.IsGameing() {
continue
}
if playerEx.gainCoin > 0 {
gainCoin := playerEx.gainCoin
playerEx.gainCoin = playerEx.gainCoin * int64(10000-this.GetDBGameFree().GetTaxRate()) / 10000
playerEx.taxCoin = gainCoin - playerEx.gainCoin
}
logger.Logger.Tracef("玩家分数 %v, coin:%v tax:%v win:%v", playerEx.SnId, playerEx.gainCoin, playerEx.taxCoin, playerEx.winAllPlayers)
}
}
func (this *SceneEx) BackupPlayer(p *PlayerEx, isBilled bool) {
testLog := make([]string, len(p.TestLog))
copy(testLog, p.TestLog)
skinId := int32(0)
if p.Skin != nil {
skinId = p.Skin.ModId
}
this.PlayerBackup[p.SnId] = &PlayerData{
SnId: p.SnId,
cards: p.cards,
cardsO: p.cardsO,
isDP: p.isDP,
gainCoin: p.gainCoin,
taxCoin: p.taxCoin,
deterMine: p.deterMine,
score: p.score,
tableScore: p.tableScore,
winThreePos: p.winThreePos,
winAllPlayers: p.winAllPlayers,
isStand: p.isStand,
isBilled: isBilled,
IsRob: p.IsRob,
Pos: p.Pos,
Coin: p.Coin,
StartCoin: p.StartCoin,
Head: p.Head,
flag: p.GetFlag(),
Platform: p.Platform,
Channel: p.Channel,
PackageID: p.PackageID,
PromoterTree: p.PromoterTree,
InviterId: p.InviterId,
WBLevel: p.WBLevel,
CurIsWin: p.CurIsWin,
BeUnderAgentCode: p.BeUnderAgentCode,
Name: p.Name,
Sex: p.Sex,
City: p.City,
Longitude: p.Longitude,
Latitude: p.Latitude,
AgentCode: p.AgentCode,
HeadOutLine: p.HeadOutLine,
VIP: p.VIP,
allGroup: p.allGroup,
TestLog: testLog,
RoleId: p.PlayerData.GetRoleId(),
PlayerPool: p.playerPool,
SkinId: skinId,
}
}
func (this *SceneEx) SendHandCardOdds() {
var realPlayersGood, realPlayersBad, realPlayers, robotPlayers []*PlayerEx
var G, B int32
for _, seat := range this.seats {
if seat != nil && seat.IsGameing() {
if seat.IsRob {
robotPlayers = append(robotPlayers, seat)
} else {
seat.odds = this.GetPlayerOdds(seat.Player, int(this.GameId), this.robotNum > 0)
seat.playerPool = int(this.PlayerPoolOdds(seat.Player))
if seat.odds > 0 {
realPlayersGood = append(realPlayersGood, seat)
G += seat.odds
} else if seat.odds < 0 {
realPlayersBad = append(realPlayersBad, seat)
B -= seat.odds
} else {
realPlayers = append(realPlayers, seat)
}
}
}
}
this.poker.Init()
cardsArr := make([][13]int, this.poker.N*4)
cardsGroup := make([]map[int]*rule.Group, this.poker.N*4)
for k := range cardsArr {
cardsArr[k] = this.poker.Get13Crads()
cardsGroup[k] = this.logic.Suggest(cardsArr[k])
}
f := func(players *[]*PlayerEx) {
if players == nil || len(*players) == 0 {
return
}
var p *PlayerEx // 发牌给这个玩家
var a int
for _, v := range *players {
a += int(math.Abs(float64(v.odds)))
}
n := this.RandInt(a)
total := 0
for k, v := range *players {
total += int(math.Abs(float64(v.odds)))
if n < total {
p = (*players)[k]
*players = append((*players)[:k], (*players)[k+1:]...)
break
}
}
var cards [13]int
var group map[int]*rule.Group
if p.odds > 0 {
// 拿好牌
cards = cardsArr[0]
cardsArr = cardsArr[1:]
group = cardsGroup[0]
cardsGroup = cardsGroup[1:]
} else {
// 拿坏牌
cards = cardsArr[len(cardsArr)-1]
cardsArr = cardsArr[:len(cardsArr)-1]
group = cardsGroup[len(cardsGroup)-1]
cardsGroup = cardsGroup[:len(cardsGroup)-1]
}
p.cards = cards
p.allGroup = group
}
// 需要换牌
isGood := len(realPlayersGood) > 0 && int32(this.RandInt(1000)) < G
isBad := len(realPlayersBad) > 0 && int32(this.RandInt(1000)) < B
logger.Logger.Tracef("Thirteen SendHandCardOdds Good:%v G:%v Bad:%v B:%v", isGood, G, isBad, B)
if isBad {
this.ctrlType = 2
}
if isGood && !isBad {
this.ctrlType = 1
}
if isGood || isBad {
// 按从大到小排序
this.cardsSort(cardsArr, cardsGroup)
// 发好牌
if isGood {
l := len(realPlayersGood)
for i := 0; i < l; i++ {
f(&realPlayersGood)
}
}
// 发坏牌
if isBad {
l := len(realPlayersBad)
for i := 0; i < l; i++ {
f(&realPlayersBad)
}
}
}
// 随机拿牌
for _, v := range this.players { // map随机
if v == nil || !v.IsGameing() || v.cards[0] != -1 {
continue
}
v.cards = cardsArr[0]
v.allGroup = cardsGroup[0]
cardsArr = cardsArr[1:]
cardsGroup = cardsGroup[1:]
}
for _, player := range this.players {
if player.IsGameing() && !player.IsRob {
logger.Logger.Trace("snid:", player.SnId)
player.TestLog = append(player.TestLog, fmt.Sprintf("随机换牌 Good:%v G:%v Bad:%v B:%v", isGood, G, isBad, B))
for _, v := range player.TestLog {
logger.Logger.Trace(v)
}
pack := &thirteen.SCThirteenTest{}
player.TestLog = append(player.TestLog, fmt.Sprintf("随机换牌 Good:%v G:%v Bad:%v B:%v", isGood, G, isBad, B))
pack.Data = strings.Join(player.TestLog, "\n")
proto.SetDefaults(pack)
player.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenTest), pack)
logger.Logger.Trace("SnId: ", player.SnId, ";SCThirteenTest: ", pack)
}
}
}