| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183 |
- package gamelogic
- import (
- "encoding/json"
- "fmt"
- "sort"
- "time"
- "bet24.com/log"
- "bet24.com/servers/games/masharie_table/common"
- "bet24.com/servers/games/masharie_table/config"
- userservices "bet24.com/servers/micros/userservices/proto"
- waterpool "bet24.com/servers/micros/waterpool/proto"
- "bet24.com/servers/transaction"
- "bet24.com/servers/user"
- "bet24.com/utils"
- )
- func (ts *tablesink) startPeriod() {
- delaySecond := 0
- switch ts.roomInfo.State {
- case common.GameState_Open:
- //开奖阶段结束了
- ts.lock.RLock()
- var prizeArea = ts.prizeArea
- ts.lock.RUnlock()
- //判断是否有彩池
- if prizeArea >= 0 {
- delaySecond = ts.roomInfo.PrizesTime
- ts.roomInfo.State = common.GameState_Prizes
- } else {
- delaySecond = ts.roomInfo.BetTime
- ts.finishOpenState()
- }
- case common.GameState_Bet:
- delaySecond = ts.roomInfo.OpenTime
- ts.roomInfo.State = common.GameState_Open
- if ts.bankerInfo.UserId != 0 {
- ts.bankerInfo.SetCount++
- }
- //开奖时刷新配置
- common.ResetProjectMultiple(ts.roomInfo.ProjectMultiple)
- case common.GameState_Prizes:
- delaySecond = ts.roomInfo.BetTime
- ts.finishOpenState()
- default:
- log.Release("startPeriod failed state = %d", ts.roomInfo.State)
- return
- }
- ts.LastStateTick = time.Now()
- ts.onStateChanged()
- time.AfterFunc(time.Duration(delaySecond)*time.Second, ts.startPeriod)
- log.Debug("tablesink.startPeriod %v:%d,State = %d", ts.roomInfo.RoomName, delaySecond, ts.roomInfo.State)
- }
- func (ts *tablesink) getStateSecond() int {
- return int(time.Since(ts.LastStateTick).Seconds())
- }
- // 下注剩余时间
- func (ts *tablesink) getBetRemainingSecond() int {
- return ts.roomInfo.BetTime - ts.getStateSecond()
- }
- // 完成开奖阶段后
- func (ts *tablesink) finishOpenState() {
- ts.roomInfo.TotalBet = 0
- ts.roomInfo.State = common.GameState_Bet
- ts.lock.Lock()
- // 洗牌,发牌
- ts.logic.shuffle(false, 0)
- ts.trumpCard = ts.logic.trumpCard
- ts.bankerCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- ts.diamondCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- ts.clubCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- ts.heartCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- ts.spadeCards = common.GetInvalidHandCards(HAND_CARD_COUNT, CARD_COUNT)
- ts.areaResult = make([]int, 0)
- ts.bankerSettle = 0
- ts.score_users.PrizeLuckyStarUsers = []common.ScoreUser{}
- ts.lock.Unlock()
- }
- func (ts *tablesink) onStateChanged() {
- switch ts.roomInfo.State {
- case common.GameState_Bet:
- now := time.Now()
- serialNumber := now.Minute() + now.Hour()*100 + now.Day()*10000 + int(now.Month())*1000000 + (now.Year()%10)*100000000
- serialNumber = serialNumber*100 + now.Second()
- ts.lock.Lock()
- ts.userBetList = make(map[int][]common.Bet)
- ts.roomInfo.SerialNumber = serialNumber
- ts.diamondAmount = 0
- ts.clubAmount = 0
- ts.heartAmount = 0
- ts.spadeAmount = 0
- ts.prizeArea = -1
- ts.lock.Unlock()
- log.Debug("onStateChanged SerialNumber = %d", ts.roomInfo.SerialNumber)
- go ts.arrangeRobotActions()
- case common.GameState_Open:
- go ts.stopRobotPoll()
- // 如果是开奖阶段
- controlType := 0
- //必须是系统庄家
- if ts.bankerInfo.UserId == -1 {
- controlType = waterpool.GetControlType(0, false, common.GAMEID)
- log.Release("onStateChanged waterpool.GetControlType 控制类型:%v", controlType)
- }
- ts.enterOpenState(controlType, false)
- case common.GameState_Prizes:
- ts.enterPrizeState()
- default:
- log.Release("onStateChanged failed state = %d", ts.roomInfo.State)
- return
- }
- ts.table.NotifySceneChanged(-1)
- //ts.refreshRoomInfo()
- }
- func (ts *tablesink) getStateData() string {
- var state common.GameState
- state.Sec = ts.getStateSecond()
- ts.lock.RLock()
- state.State = ts.roomInfo.State
- ts.roomInfo.StateSec = state.Sec
- state.TrumpCard = ts.trumpCard // 主牌(投注阶段下发)
- state.BankerCards = ts.bankerCards // 庄家手牌
- state.DiamondCards = ts.diamondCards // 方块手牌
- state.ClubCards = ts.clubCards // 梅花手牌
- state.HeartCards = ts.heartCards // 红心手牌
- state.SpadeCards = ts.spadeCards // 黑桃手牌
- state.AreaResult = ts.areaResult // 区域结果
- state.BankerSettle = ts.bankerSettle
- state.Historys = ts.roomInfo.Historys
- state.TableUser = *ts.score_users
- state.PrizePool = ts.prizePool.getPrizePool()
- state.PrizeArea = ts.prizeArea
- state.BankerInfo = ts.bankerInfo
- //state.RichList = ts.richList
- //state.BetList = ts.betList
- state.SerialNumber = ts.roomInfo.SerialNumber
- if len(ts.scores) > 0 {
- state.Scores = append(state.Scores, ts.scores...)
- } else {
- state.Scores = []common.UserSetScore{}
- }
- if state.State == common.GameState_Bet {
- for _, v := range ts.userBetList {
- state.BetCmds = append(state.BetCmds, v...)
- }
- }
- ts.lock.RUnlock()
- data, _ := json.Marshal(state)
- return string(data)
- }
- func (ts *tablesink) isCanBet(bet common.Bet) (bool, string) {
- amount := bet.Amount
- userId := bet.UserId
- betId := bet.BetId
- if ts.roomInfo.State != common.GameState_Bet {
- return false, "Bet failed,Please wait for next round"
- }
- if amount < ts.roomInfo.MinBet || amount > ts.roomInfo.MaxBet {
- return false, "Bet amount exceeded"
- }
- bidType := common.BidType(betId)
- if bidType >= common.BidType_Max || bidType < common.BidType_Diamond {
- log.Release("isCanBet invalid bet %d,%d", bidType, common.BidType_Max)
- return false, "invalid bet"
- }
- // 检查已下注金额
- myAmount := 0
- ts.lock.RLock()
- betList, ok := ts.userBetList[userId]
- if ok {
- for _, v := range betList {
- myAmount += v.Amount
- }
- }
- ts.lock.RUnlock()
- maxBet := ts.roomInfo.MaxBet
- totalMaxBet := ts.roomInfo.TotalMax
- //如果不是系统庄 则金额不能超过当前玩家携带金币
- if ts.bankerInfo.UserId != -1 {
- bankerGold := ts.bankerInfo.Gold
- totalMaxBet = bankerGold / ts.roomInfo.MaxBetRate
- }
- totalBet := ts.roomInfo.TotalBet
- if myAmount+amount > maxBet {
- return false, "Bet amount user exceeded"
- }
- // 检查全体下注
- if amount+totalBet > totalMaxBet {
- return false, "Bet amount section exceeded"
- }
- //目前上庄也不考虑赔付
- return true, ""
- }
- // 检查个人下注
- func (ts *tablesink) checkGold(bet common.Bet) (bool, string) {
- amount := bet.Amount
- userId := bet.UserId
- myAmount := 0
- ts.lock.RLock()
- betList, ok := ts.userBetList[userId]
- if ok {
- for _, v := range betList {
- myAmount += v.Amount
- }
- }
- ts.lock.RUnlock()
- personalBetRatio := ts.roomInfo.PersonalBetRatio
- freeChip := 0
- userGold := ts.table.GetUserChipOrGoldByUserId(userId)
- //下注金额+已经下注金额 /(以下注金额+身上的钱) = 是否超过限制
- if bet.IsFree {
- //如果是免费下注则加上剩余免费卷的钱
- //检查免费筹码数量
- freeChip, _ = ts.freeChips.checkFreeChipsNum(userId)
- if freeChip < amount {
- log.Debug("checkGold.checkFreeChipsNum Not enough free chip amount:%v,freeChip:%v", amount, freeChip)
- return false, "Not enough free chip!"
- }
- userGold += freeChip
- }
- if myAmount+userGold == 0 {
- return false, "Bet failure, user has no gold"
- }
- if (amount+myAmount)/(myAmount+userGold) > personalBetRatio {
- return false, "Bet failure exceeds the limit"
- }
- if ts.bankerInfo.UserId == -1 {
- return true, ""
- }
- //目前上庄也不考虑赔付
- return true, ""
- }
- func (ts *tablesink) addBet(bet common.Bet) (bool, string) {
- ok, errMsg := ts.isCanBet(bet)
- if !ok {
- return ok, errMsg
- }
- ts.lock.Lock()
- ts.roomInfo.TotalBet += bet.Amount
- betList, ok := ts.userBetList[bet.UserId]
- // 合并之前下注
- found := false
- if ok {
- for i := 0; i < len(betList); i++ {
- if !betList[i].IsSameBet(&bet) {
- continue
- }
- betList[i].Amount += bet.Amount
- // 合并下注
- found = true
- break
- }
- }
- //log.Debug("tablesink.addBet %v", ts.userBetList)
- if !found {
- ts.userBetList[bet.UserId] = append(ts.userBetList[bet.UserId], bet)
- }
- ts.lock.Unlock()
- betAmount := bet.Amount
- if !bet.IsFree {
- ts.userList.addBet(bet.UserId, betAmount, bet.BetId)
- }
- return true, ""
- }
- // 开奖 controlType 1表示扣减,2表示放水
- func (ts *tablesink) enterOpenState(controlType int, isReset bool) {
- //默认按顺序获取结果
- ts.logic.curDeckIndex = 0
- var areaDeck []common.CardDeck
- for i := 0; i < CARD_DECK_COUNT; i++ {
- deck := ts.logic.getHandCardsByIndex()
- areaDeck = append(areaDeck, deck)
- }
- if areaDeck == nil {
- log.Error("tableSink.enterOpenState areaDeck == nil")
- return
- }
- if areaDeck[common.Area_Banker].Ranking == 1 && isReset && ts.isBankerAllKill {
- ts.logic.shuffle(false, 0)
- ts.enterOpenState(controlType, false)
- }
- if areaDeck[common.Area_Banker].Ranking == 1 {
- ts.isBankerAllKill = true
- } else {
- ts.isBankerAllKill = false
- }
- //按顺序分配手牌
- settlementOrder, areaResult := ts.assignAreaCards(areaDeck)
- bankerBetAmount := 0
- areaTotalBet := make(map[int]int)
- realAreaTotalBet := make(map[int]int) //剔除机器人的
- ts.lock.RLock()
- bankerCards := ts.bankerCards
- bankerOdds := common.GetMultiple(bankerCards.Project)
- //计算所有区域的下注总额
- for _, betList := range ts.userBetList {
- if len(betList) == 0 {
- continue
- }
- for _, v := range betList {
- areaTotalBet[v.BetId] += v.Amount
- bankerBetAmount += v.Amount
- if v.IsRobot && !ts.roomInfo.Test {
- //机器人跳过
- continue
- }
- realAreaTotalBet[v.BetId] += v.Amount
- }
- }
- ts.lock.RUnlock()
- //只重置一次
- if controlType != 0 && !isReset {
- //1表示扣减,2表示放水
- // 检查非机器人的下注结果
- simulateBetResults := 0
- for _, betBid := range settlementOrder {
- simulateBetResults += realAreaTotalBet[betBid]
- if areaResult[betBid] == common.Win {
- odds := common.GetMultiple(areaDeck[betBid].Project) + 1
- simulateBetResults -= int(odds * float64(realAreaTotalBet[betBid]))
- } else if bankerOdds > 1 {
- simulateBetResults += int((bankerOdds - 1) * float64(realAreaTotalBet[betBid]))
- }
- }
- log.Release("tableSink.enterOpenState controlType:%v,isReset:%v,simulateBetResults:%v", controlType, isReset, simulateBetResults)
- if controlType == 1 && simulateBetResults < 0 {
- ts.logic.shuffle(false, 0)
- ts.enterOpenState(controlType, false)
- return
- } else if controlType == 2 && simulateBetResults > 0 {
- // 放水不出翻倍牌型
- ts.logic.shuffle(false, 1)
- ts.enterOpenState(controlType, false)
- return
- }
- }
- //写历史记录
- ts.addHistory()
- bankerLoseRate := 1.0
- bankerDeck := areaDeck[common.Area_Banker]
- ts.lock.RLock()
- bankerId := ts.bankerInfo.UserId
- trumpCard := ts.trumpCard
- ts.lock.RUnlock()
- //基础投注备注
- baseBetDesc := fmt.Sprintf("B:[%v,R:%v]M:%v", getHandCardsHex(bankerDeck.HandCards, true), bankerDeck.Ranking, getCardHex(trumpCard, true))
- bankerBetDesc := baseBetDesc
- ts.lock.RLock()
- settleInfo := make(map[int]*common.SettleInfo)
- for userId, betList := range ts.userBetList {
- if len(betList) == 0 {
- continue
- }
- //判断一下之前有没有创建
- if settleInfo[userId] == nil {
- settleInfo[userId] = &common.SettleInfo{}
- //BetDesc 初始化时加入庄家的牌
- settleInfo[userId].BetDesc = baseBetDesc
- }
- }
- ts.lock.RUnlock()
- bankerTotalBet := []int{0, 0, 0, 0}
- bankerTotalWin := []int{0, 0, 0, 0}
- bankerTotalLose := []int{0, 0, 0, 0}
- prizeTotalBet := 0
- var refreshFreeChips = make([]int, 0)
- //处理玩家输的部分
- settleInfo, prizeTotalBet, refreshFreeChips, bankerTotalBet, bankerTotalWin = ts.handleLoss(areaDeck, settlementOrder, settleInfo, prizeTotalBet, bankerTotalBet, bankerTotalWin)
- if bankerId != -1 {
- //如果不是系统庄 则需要预估赔付比例
- bankerWin := 0
- //计算庄家实际赢的
- for _, win := range bankerTotalWin {
- bankerWin += win
- }
- ts.lock.RLock()
- bankerGold := ts.bankerInfo.Gold
- ts.lock.RUnlock()
- bankerLoseRate = ts.calcBankerLoseRate(bankerGold, areaTotalBet, areaDeck, areaResult, settlementOrder, bankerWin)
- } else {
- bankerBetAmount = 0 //系统庄不统计
- }
- // 处理玩家赢的部分
- settleInfo, prizeTotalBet, bankerTotalBet, bankerTotalLose = ts.handleWin(areaDeck, settlementOrder, settleInfo, prizeTotalBet, bankerTotalBet, bankerTotalLose, bankerLoseRate)
- bankerSettle := ts.settleResults(settleInfo, bankerLoseRate)
- ts.lock.RLock()
- delaySecond := ts.roomInfo.OpenTime - 1 //换庄等待时间
- if prizeTotalBet > 0 {
- ts.prizeTotalBet = prizeTotalBet
- delaySecond += ts.roomInfo.PrizesTime - 1
- }
- ts.lock.RUnlock()
- checkBankerTime := time.Duration(delaySecond) * time.Second
- // 写庄家投注日志
- for betId, amount := range bankerTotalBet {
- betDesc := fmt.Sprintf("[%s:%s]", common.GetBetDesc(betId), utils.FormatScore(amount))
- winDesc := fmt.Sprintf("[%s:%s]", common.GetBetDesc(betId), utils.FormatScore(bankerTotalWin[betId]))
- loseDesc := fmt.Sprintf("[%s:%s]", common.GetBetDesc(betId), utils.FormatScore(bankerTotalLose[betId]))
- bankerBetDesc = fmt.Sprintf("%s %s,win:%s lose:%s", bankerBetDesc, betDesc, winDesc, loseDesc)
- }
- bankerSettle = ts.calculateBankerScore(bankerId, bankerBetAmount, bankerSettle, bankerBetDesc)
- ts.dayBetRank.betPoolToRedis()
- ts.weekBetRank.betPoolToRedis()
- //ts.userList.dump()
- // 结算完毕,计算连胜榜
- ts.lock.Lock()
- ts.bankerSettle = bankerSettle
- // ts.richList = ts.refreshRichList(20)
- //先清空数据
- ts.score_users.LuckyStarUsers = []common.ScoreUser{}
- ts.score_users.BetGoldRankingUsers = []common.ScoreUser{}
- ts.score_users.WinGoldRankingUsers = []common.ScoreUser{}
- ts.score_users.LuckyStarUsers = ts.userList.getLuckyStarUsers(1, ts.bankerInfo.UserId)
- ts.score_users.BetGoldRankingUsers = ts.userList.getBetGoldRankingUsers(7)
- ts.score_users.WinGoldRankingUsers = ts.userList.getWinGoldRankingUsers(1, ts.bankerSettle, ts.bankerInfo.UserId, ts.bankerInfo.FaceId, ts.bankerInfo.FaceUrl)
- ts.userList.clearBetStatus(ts.roomInfo.SerialNumber)
- ts.lock.Unlock()
- if len(refreshFreeChips) > 0 {
- //刷新免费筹码
- for _, userId := range refreshFreeChips {
- usr := ts.table.GetUserByUserId(userId)
- if usr == nil {
- continue
- }
- go ts.onCheckFreeChip(usr.GetUserIndex(), userId, FreeChip, "")
- }
- }
- if prizeTotalBet <= 0 {
- ts.clearLeaveUser()
- }
- // 下庄
- time.AfterFunc(checkBankerTime, ts.checkBankerQuality)
- }
- // 根据类型洗牌 HACK:删除这部分逻辑控制不在因为调控修改牌
- func (ts *tablesink) handleControlType(controlType int) []common.CardDeck {
- //HACK: 删除这部分逻辑控制不在因为调控修改牌
- var areaDeck []common.CardDeck
- maxAmount, minAmount, maxType := ts.getBetMaxAndMin()
- if controlType == 0 {
- //必须是系统庄家
- if ts.bankerInfo.UserId == -1 && (maxAmount > 0 || minAmount > 0) {
- controlType = waterpool.GetControlType(0, false, common.GAMEID)
- log.Release("tableSink.handleControlType waterpool.GetControlType 控制类型:%v", controlType)
- }
- //不需要控制
- // else if ts.bankerInfo.UserId != -1 {
- // //非系统庄时 不触发奖池牌型
- // if ts.logic.checkAwardCardDeck() {
- // ts.logic.shuffle(false, 3)
- // ts.enterOpenState(controlType)
- // return nil
- // }
- // }
- }
- //根据情况判断是否需要重新开奖
- if controlType == 1 {
- //全部等级,不去重
- ranking := ts.logic.getAllRanking()
- // 1.收水允许有翻倍的情况存在
- // 2.最大下注区域给排名最小的牌,其他3个区域和庄家随机获取名次
- min := 2
- min, ranking = getRanking(ranking, Min)
- for i := 0; i < CARD_DECK_COUNT; i++ {
- if common.AreaHandCards(i) == maxType {
- deck := ts.logic.getHandCardsByRanking(min)
- areaDeck = append(areaDeck, deck)
- } else {
- randomRank, newRanking := getRanking(ranking, Random)
- ranking = newRanking
- deck := ts.logic.getHandCardsByRanking(randomRank)
- areaDeck = append(areaDeck, deck)
- }
- }
- return areaDeck
- } else if controlType == 2 {
- //重洗
- //判断是否还有翻倍
- if ts.logic.checkMultipleCardDeck() {
- ts.logic.shuffle(false, 1)
- ts.enterOpenState(controlType, true)
- return nil
- }
- ranking := ts.logic.getAllRanking()
- //1.放水时所有牌不能有翻倍,如果遇到有翻倍则重新洗
- //2.放水区域给排名最大的牌,其他3个区域和庄家随机获取名次
- max := 1
- max, ranking = getRanking(ranking, Max)
- for i := 0; i < CARD_DECK_COUNT; i++ {
- if common.AreaHandCards(i) == maxType {
- deck := ts.logic.getHandCardsByRanking(max)
- areaDeck = append(areaDeck, deck)
- } else {
- randomRank, newRanking := getRanking(ranking, Random)
- ranking = newRanking
- deck := ts.logic.getHandCardsByRanking(randomRank)
- areaDeck = append(areaDeck, deck)
- }
- }
- return areaDeck
- }
- //默认按顺序获取结果
- ts.logic.curDeckIndex = 0
- for i := 0; i < CARD_DECK_COUNT; i++ {
- deck := ts.logic.getHandCardsByIndex()
- areaDeck = append(areaDeck, deck)
- }
- return areaDeck
- }
- // 给每个区域分配手牌
- func (ts *tablesink) assignAreaCards(areaDeck []common.CardDeck) ([]int, []int) {
- var areaResult []int
- var prizeProject = common.Project_Base
- bankerRanking := areaDeck[common.Area_Banker].Ranking
- bankerDeck := areaDeck[common.Area_Banker]
- ts.bankerCards = bankerDeck.HandCards
- diamondDeck := areaDeck[common.Area_Diamond]
- ts.diamondCards = diamondDeck.HandCards
- clubDeck := areaDeck[common.Area_Club]
- ts.clubCards = clubDeck.HandCards
- heartDeck := areaDeck[common.Area_Heart]
- ts.heartCards = heartDeck.HandCards
- spadeDeck := areaDeck[common.Area_Spade]
- ts.spadeCards = spadeDeck.HandCards
- winAreas := make([]int, 0) // Areas where banker won
- loseAreas := make([]int, 0) // Areas where banker lost
- prizeArea := -1
- for i := 0; i < CARD_DECK_COUNT-1; i++ {
- result := common.Lose
- //排名小于庄家的则算赢
- if areaDeck[i].Ranking < bankerRanking {
- result = common.Win
- winAreas = append(winAreas, i)
- } else {
- loseAreas = append(loseAreas, i)
- }
- areaResult = append(areaResult, result)
- if areaDeck[i].Project >= common.Project_Fifty && areaDeck[i].Project >= prizeProject {
- //如果相同则取最大的
- if prizeArea != -1 && areaDeck[i].Project == prizeProject && areaDeck[i].Ranking > areaDeck[prizeArea].Ranking {
- continue
- }
- prizeArea = i
- prizeProject = areaDeck[i].Project
- }
- }
- // 开奖
- ts.lock.Lock()
- ts.areaResult = areaResult
- ts.prizeArea = prizeArea
- ts.prizeProject = prizeProject
- ts.lock.Unlock()
- settlementOrder := append(loseAreas, winAreas...)
- return settlementOrder, areaResult
- }
- // 预估庄家赔付比例
- func (ts *tablesink) calcBankerLoseRate(bankerGold int, areaTotalBet map[int]int, areaDeck []common.CardDeck, areaResult []int, settlementOrder []int, bankerWin int) float64 {
- bankerLoseRate := 1.0
- //庄家赔付
- bankerLose := 0
- //庄家底注
- base := 0
- for _, betBid := range settlementOrder {
- base += int(areaTotalBet[betBid]) //底注
- if areaResult[betBid] == common.Win {
- odds := common.GetMultiple(areaDeck[betBid].Project) + 1
- bankerLose += int(odds * float64(areaTotalBet[betBid]))
- }
- }
- settle := bankerGold + base + bankerWin
- //预估结算
- if bankerLose > settle {
- //庄家金币不足
- bankerLoseRate = float64(settle) / float64(bankerLose)
- log.Release("enterOpenState.calcBankerLoseRate bankerGold not enough bankerGold:%v,bankerWin:%v,settle:%v,bankerLose:%v, bankerLoseRate:%v", bankerGold, bankerWin, settle, bankerLose, bankerLoseRate)
- }
- return bankerLoseRate
- }
- // 处理玩家输的情况(因为非系统庄需要考虑玩家实际输的金额,所以区分成了两个方法)
- func (ts *tablesink) handleLoss(areaDeck []common.CardDeck, settlementOrder []int, settleInfo map[int]*common.SettleInfo, prizeTotalBet int, bankerTotalBet, bankerTotalWin []int) (map[int]*common.SettleInfo, int, []int, []int, []int) {
- // 处理输的情况的代码
- //记录需要刷新的免费筹码的用户id
- refreshFreeChips := make([]int, 0)
- ts.lock.Lock()
- bankerCards := ts.bankerCards
- prizeArea := ts.prizeArea
- areaResult := ts.areaResult
- diamondCards := ts.diamondCards
- clubCards := ts.clubCards
- heartCards := ts.heartCards
- spadeCards := ts.spadeCards
- bankerOdds := common.GetMultiple(bankerCards.Project)
- for _, betBid := range settlementOrder {
- if areaResult[betBid] == common.Win {
- continue
- }
- for userId, betList := range ts.userBetList {
- if len(betList) == 0 {
- continue
- }
- actualModifyAmount := 0
- //庄家赔率
- var odds float64 = 0
- odds = bankerOdds
- for _, v := range betList {
- if v.BetId != betBid {
- continue
- }
- var result common.Result
- result.UserId = v.UserId
- result.Bet = v
- result.AreaResult = areaResult
- result.Amount = v.Amount
- betAmount := v.Amount
- if v.BetId == prizeArea {
- prizeTotalBet += betAmount
- }
- bankerTotalBet[result.BetId] += betAmount
- settleInfo[userId].ActualBetAmount += betAmount
- if v.IsFree {
- betAmount = 0
- }
- settleInfo[userId].BetAmount += betAmount
- deductedAmount := 0 //记录免费卷抵扣的金额
- result.LoseAmount = 0
- result.WinAmount = 0
- if odds > 1 {
- //庄赢超过一倍
- result.LoseAmount = int((odds - 1) * float64(result.Amount))
- //考虑免费卷抵扣的情况
- if v.IsFree {
- freeChip, _ := ts.freeChips.checkFreeChipsNum(userId)
- //log.Release("enterOpenState.checkFreeChipsNum freeChip:%v,LoseAmount:%v", freeChip, result.LoseAmount)
- if freeChip > 0 {
- //免费筹码有多少扣多少
- _, deductedAmount = ts.freeChips.useFreeChipsFromInventory(userId, result.LoseAmount)
- //记录需要刷新的免费筹码的用户id
- refreshFreeChips = append(refreshFreeChips, userId)
- }
- result.LoseAmount -= deductedAmount
- log.Release("enterOpenState.useFreeChipsFromInventory deductedAmount:%v,LoseAmount:%v", deductedAmount, result.LoseAmount)
- }
- }
- usr := ts.table.GetUserByUserId(userId)
- //得到实际扣除的金额
- actualModifyAmount = ts.handleResult(result, usr)
- absActualModifyAmount := actualModifyAmount
- if actualModifyAmount < 0 {
- absActualModifyAmount = actualModifyAmount * -1
- }
- if result.LoseAmount > 0 || deductedAmount > 0 {
- // 玩家不够输的情况
- settleInfo[userId].LoseAmount += result.LoseAmount + deductedAmount
- bankerTotalWin[result.BetId] += result.LoseAmount + deductedAmount
- if absActualModifyAmount < result.LoseAmount {
- //如果存在玩家不够扣的情况
- settleInfo[userId].LoseAmount -= result.LoseAmount - absActualModifyAmount
- bankerTotalWin[result.BetId] -= result.LoseAmount - absActualModifyAmount
- }
- }
- actualDesc := utils.FormatScore(actualModifyAmount)
- if v.IsFree {
- actualDesc = fmt.Sprintf("F%s(%s)", utils.FormatScore(actualModifyAmount), utils.FormatScore(deductedAmount))
- }
- betDesc := fmt.Sprintf("[%s:%s[%s]]", ts.getBetDesc(result.Bet), utils.FormatScore(v.Amount), actualDesc)
- settleInfo[userId].BetDesc = fmt.Sprintf("%s %s", settleInfo[userId].BetDesc, betDesc)
- //判断是否没有数据
- if len(settleInfo[userId].ResultDesc) == 0 {
- settleInfo[userId].ResultDesc = ts.getResultDesc(areaResult, diamondCards, clubCards, heartCards, spadeCards)
- }
- }
- //log.Debug("GetResultOdds odds= %v, BetId = %v", odds, result.BetId)
- }
- }
- ts.lock.Unlock()
- return settleInfo, prizeTotalBet, refreshFreeChips, bankerTotalBet, bankerTotalWin
- }
- // 处理玩家赢的情况
- func (ts *tablesink) handleWin(areaDeck []common.CardDeck, settlementOrder []int, settleInfo map[int]*common.SettleInfo, prizeTotalBet int, bankerTotalBet, bankerTotalLose []int, bankerLoseRate float64) (map[int]*common.SettleInfo, int, []int, []int) {
- ts.lock.Lock()
- prizeArea := ts.prizeArea
- areaResult := ts.areaResult
- diamondCards := ts.diamondCards
- clubCards := ts.clubCards
- heartCards := ts.heartCards
- spadeCards := ts.spadeCards
- taxRate := ts.roomInfo.TaxRate
- for _, betBid := range settlementOrder {
- if areaResult[betBid] == common.Lose {
- continue
- }
- for userId, betList := range ts.userBetList {
- if len(betList) == 0 {
- continue
- }
- actualModifyAmount := 0
- //庄家赔率
- var odds float64 = 0
- for _, v := range betList {
- if v.BetId != betBid {
- continue
- }
- var result common.Result
- result.UserId = v.UserId
- result.Bet = v
- result.AreaResult = areaResult
- result.Amount = v.Amount
- betAmount := v.Amount
- if v.BetId == prizeArea {
- prizeTotalBet += betAmount
- }
- bankerTotalBet[result.BetId] += betAmount
- settleInfo[userId].ActualBetAmount += betAmount
- if v.IsFree {
- betAmount = 0
- }
- settleInfo[userId].BetAmount += betAmount
- deductedAmount := 0 //记录免费卷抵扣的金额
- result.LoseAmount = 0
- result.WinAmount = 0
- if common.Win == areaResult[result.BetId] {
- odds = common.GetMultiple(areaDeck[result.BetId].Project) + 1
- result.WinAmount = int(odds * float64(result.Amount))
- settleInfo[userId].ActualWinAmount += result.WinAmount
- bankerTotalLose[result.BetId] += result.WinAmount
- //免费的也需要扣本金
- realWin := result.WinAmount - result.Amount
- if realWin > 0 {
- result.Tax = realWin * taxRate / 100
- }
- result.WinAmount -= result.Tax
- settleInfo[userId].TaxAmount += result.Tax
- settleInfo[userId].WinAmount += int(float64(result.WinAmount) * bankerLoseRate) //玩家要算完台费才扣
- settleInfo[userId].TotalOdds += odds
- }
- usr := ts.table.GetUserByUserId(userId)
- //得到实际扣除的金额
- actualModifyAmount = ts.handleResult(result, usr)
- actualDesc := utils.FormatScore(actualModifyAmount)
- if v.IsFree {
- actualDesc = fmt.Sprintf("F%s(%s)", utils.FormatScore(actualModifyAmount), utils.FormatScore(deductedAmount))
- }
- betDesc := fmt.Sprintf("[%s:%s[%s]]", ts.getBetDesc(result.Bet), utils.FormatScore(v.Amount), actualDesc)
- settleInfo[userId].BetDesc = fmt.Sprintf("%s %s", settleInfo[userId].BetDesc, betDesc)
- //判断是否没有数据
- if len(settleInfo[userId].ResultDesc) == 0 {
- settleInfo[userId].ResultDesc = ts.getResultDesc(areaResult, diamondCards, clubCards, heartCards, spadeCards)
- }
- }
- //log.Debug("GetResultOdds odds= %v, BetId = %v", odds, result.BetId)
- }
- }
- ts.lock.Unlock()
- return settleInfo, prizeTotalBet, bankerTotalBet, bankerTotalLose
- }
- // 结算结果
- func (ts *tablesink) settleResults(settleInfo map[int]*common.SettleInfo, bankerLoseRate float64) int {
- bankerSettle := 0
- ts.lock.Lock()
- ts.scores = []common.UserSetScore{}
- poolValue := waterpool.GetInventoryValue(common.GAMEID, waterpool.RoomType_Hundred, config.Room.RoomName)
- //先判断是否为空
- if len(settleInfo) != 0 {
- //根据settleInfo进行结算
- for userId, total := range settleInfo {
- //记录实际输赢 总赢金-总投注-总输 0-100-100
- totalResult := total.WinAmount - total.BetAmount - total.LoseAmount
- //记录庄家输赢 用户总输 +总投注额 - 用户总赢金
- bankerSettle += int(float64(total.LoseAmount+total.ActualBetAmount-total.ActualWinAmount) * bankerLoseRate)
- //log.Release("enterOpenState.settleResults bankerSettle:%v,LoseAmount:%v,ActualBetAmount:%v,ActualWinAmount:%v,bankerLoseRate:%v", bankerSettle, total.LoseAmount, total.ActualBetAmount, total.ActualWinAmount, bankerLoseRate)
- // 纪录输赢
- if ts.roomInfo.Test {
- bets := []int{}
- betList, ok := ts.userBetList[userId]
- if ok {
- for n := 0; n < len(betList); n++ {
- bets = append(bets, betList[n].BetId)
- }
- }
- if len(bets) > 0 {
- ts.stat.lists = append(ts.stat.lists, Statistics{
- betAmount: total.BetAmount,
- winOrLossAmount: totalResult,
- betArea: bets,
- waterpool: poolValue,
- })
- }
- }
- go ts.table.WriteBetRecordWithPlayTime(userId, total.BetAmount, total.WinAmount-total.LoseAmount, total.TotalOdds,
- settleInfo[userId].BetDesc, settleInfo[userId].ResultDesc, ts.roomInfo.RoomName, ts.roomInfo.BetTime)
- ts.userList.addResult(userId, ts.roomInfo.SerialNumber, total.BetAmount, total.WinAmount, -total.LoseAmount, totalResult)
- //有上榜的玩家才发
- if common.IsInTopN(ts.score_users.LuckyStarUsers, userId, 1) || common.IsInTopN(ts.score_users.BetGoldRankingUsers, userId, 7) {
- ts.scores = append(ts.scores, common.UserSetScore{UserId: userId, Score: totalResult})
- }
- usr := ts.table.GetUserByUserId(userId)
- if usr == nil {
- //检查是否为机器人
- if !userservices.IsRobot(userId) || ts.roomInfo.Test {
- ts.settleStats(userId, total.BetAmount, totalResult, total.TaxAmount)
- }
- continue
- } else if !usr.IsRobot() || ts.roomInfo.Test {
- ts.settleStats(userId, total.BetAmount, totalResult, total.TaxAmount)
- }
- // 只返回具体的金额 用于飘分
- data := fmt.Sprint(totalResult)
- ts.table.SendGameData(usr.GetUserIndex(), TotalResult, data)
- }
- }
- ts.lock.Unlock()
- return bankerSettle
- }
- // 结算统计
- func (ts *tablesink) settleStats(userId, betAmount, winAmount, totalTax int) {
- if betAmount > 0 {
- ts.dayBetRank.addBetPool(userId, betAmount)
- ts.weekBetRank.addBetPool(userId, betAmount)
- ts.prizePool.updatePrizePool(betAmount)
- }
- //上报水池
- go waterpool.AddBet(0, betAmount, false, common.GAMEID)
- if winAmount != 0 {
- go waterpool.ReducePool(0, winAmount+betAmount, false, common.GAMEID)
- }
- }
- // 计算庄家分数
- func (ts *tablesink) calculateBankerScore(bankerId, bankerBetAmount, bankerSettle int, bankerBetDesc string) int {
- if bankerId == -1 {
- return bankerSettle
- }
- // 庄家写分
- banker := ts.table.GetUserByUserId(bankerId)
- if banker != nil {
- ts.lock.Lock()
- // 得到庄家的输赢
- bankerGold := ts.bankerInfo.Gold
- // 判断庄家赢的钱是否超过自身金额 这个游戏允许超过自身的钱
- // if bankerSettle > bankerGold {
- // bankerSettle = bankerGold
- // }
- //判断是否输破产
- if bankerGold+bankerSettle < 0 {
- bankerSettle = -bankerGold
- log.Release("enterOpenState.calculateBankerScore Bankruptcy bankerGold:%v,bankerSettle:%v", bankerGold, bankerSettle)
- }
- //计算台费
- bankerTax := 0
- if bankerSettle > 0 {
- bankerTax = bankerSettle * ts.roomInfo.BankerTaxRate / 100
- bankerSettle -= bankerTax
- log.Release("enterOpenState.calculateBankerScore Calculate station fees bankerTax:%v,bankerSettle:%v", bankerTax, bankerSettle)
- }
- ts.bankerInfo.Tax += bankerTax
- // 庄家分数最后写
- ts.bankerInfo.Score += bankerSettle
- ts.bankerInfo.Gold += bankerSettle
- ts.scores = append(ts.scores, common.UserSetScore{UserId: ts.bankerInfo.UserId, Score: bankerSettle})
- ts.dayBetRank.addBetPool(ts.bankerInfo.UserId, bankerBetAmount)
- ts.weekBetRank.addBetPool(ts.bankerInfo.UserId, bankerBetAmount)
- log.Debug("enterOpenState UserId= %d, bankerGold = %d,bankerBetAmount = %d,bankerSettle = %d", ts.bankerInfo.UserId, bankerGold, bankerBetAmount, bankerSettle)
- go ts.table.WriteBetRecordWithPlayTime(ts.bankerInfo.UserId, 0, bankerSettle, 0,
- fmt.Sprintf("banker bet(%d)", bankerBetAmount), fmt.Sprintf("banker result(%d) %s ", bankerSettle, bankerBetDesc), ts.roomInfo.RoomName, ts.roomInfo.BetTime)
- go ts.updateBankerGold()
- ts.lock.Unlock()
- }
- return bankerSettle
- }
- // 发彩池
- func (ts *tablesink) enterPrizeState() {
- // 如果是发奖阶段
- ts.lock.Lock()
- var prizeArea = ts.prizeArea
- var prizeProject = ts.prizeProject
- var prizeTotalBet = ts.prizeTotalBet
- var projectRate = GetProjectRate(prizeProject)
- //总奖池
- var prizePool = ts.prizePool.getPrizePool()
- //奖池比例
- var prizeRate = float64(prizePool * projectRate / 100)
- //(区域下注总金额/区域总下注金额) * (总奖池*项目比例/100)(1000/10000)*(1000000*20%)=20000
- ts.scores = []common.UserSetScore{}
- prizeStateDesc := fmt.Sprintf("PrizeArea:[%v] PrizeProject:[%v] PrizeTotalBet:[%v] ProjectRate:[%v] PrizePool:[%v] PrizeRate:[%v]", prizeArea, prizeProject, prizeTotalBet, projectRate, prizePool, prizeRate)
- maxBetAmount := 0
- for userId, betList := range ts.userBetList {
- // usr := ts.table.GetUserByUserId(userId)
- var total struct {
- UserId int
- BetAmount int
- Prize int
- }
- total.UserId = userId
- total.Prize = 0
- for _, v := range betList {
- // 判断是否买了这个区域
- if prizeArea != v.BetId {
- continue
- }
- //奖金
- prize := int(float64(v.Amount) / float64(prizeTotalBet) * prizeRate)
- total.Prize += prize
- total.BetAmount += v.Amount
- prizeStateDesc = fmt.Sprintf("%s [%d %d[%d:%d]]", prizeStateDesc, userId, v.BetId, v.Amount, prize)
- }
- if total.Prize <= 0 {
- continue
- }
- if total.BetAmount > maxBetAmount {
- maxBetAmount = total.BetAmount
- }
- totalResult := total.Prize
- go ts.prizePool.deductJackpot(totalResult)
- go ts.table.WriteUserMoney(userId, totalResult, 0, 2, 2+common.GAMEID*100, ts.roomInfo.RoomName)
- // 写用户纪录
- d, _ := json.Marshal(total)
- go transaction.WriteGameRecord(userId, common.GAMEID, ts.roomInfo.RoomName, string(d))
- ts.scores = append(ts.scores, common.UserSetScore{UserId: userId, Score: totalResult})
- }
- //排序分数越大越靠前
- sort.Slice(ts.scores, func(i, j int) bool {
- return ts.scores[i].Score > ts.scores[j].Score
- })
- scoreUserList := []common.ScoreUser{}
- //第一名存储起来
- if len(ts.scores) > 0 {
- //第一名就是下注最大的
- var userId = ts.scores[0].UserId
- var score = ts.scores[0].Score
- ts.prizePool.updatePrizeRank(userId, score, maxBetAmount)
- user := userservices.GetUserInfo(userId)
- info := make([]int, 0, 1)
- info = append(info, score)
- scoreUser := common.ScoreUser{
- UserId: userId,
- BetAmount: maxBetAmount,
- NickName: "",
- FaceId: 0,
- FaceUrl: "",
- VipLevel: 0,
- VipExpire: 0,
- Decorations: nil,
- Info: info,
- }
- if user != nil {
- scoreUser.NickName = user.NickName
- scoreUser.FaceId = user.FaceId
- scoreUser.FaceUrl = user.FaceUrl
- scoreUser.VipLevel = user.Vip
- scoreUser.VipExpire = user.VipExpire
- scoreUser.Decorations = user.Decorations
- }
- scoreUserList = append(scoreUserList, scoreUser)
- }
- ts.score_users.PrizeLuckyStarUsers = scoreUserList
- ts.lock.Unlock()
- log.Release("----enterPrizeState---- %v", prizeStateDesc)
- //清除已经离开的用户
- ts.clearLeaveUser()
- }
- // 清除已经离开的用户
- func (ts *tablesink) clearLeaveUser() {
- ts.lock.Lock()
- bankerId := ts.bankerInfo.UserId
- for userId, betList := range ts.userBetList {
- //庄家忽略
- if bankerId == userId {
- continue
- }
- if len(betList) == 0 {
- continue
- }
- usr := ts.table.GetUserByUserId(userId)
- if usr == nil {
- ts.userList.removeUser(userId)
- if ts.removeCandidate(userId) {
- ts.broadcastBankerInfo()
- }
- }
- }
- ts.lock.Unlock()
- }
- // 找到投注额的最大值和最小值
- func (ts *tablesink) getBetMaxAndMin() (int, int, common.AreaHandCards) {
- maxAmount := ts.diamondAmount
- minAmount := ts.diamondAmount
- var maxType common.AreaHandCards
- maxType = common.Area_Diamond //默认选中0
- typeAmount := []int{ts.diamondAmount, ts.clubAmount, ts.heartAmount, ts.spadeAmount}
- for i, f := range typeAmount {
- if f > maxAmount {
- maxAmount = f
- maxType = common.AreaHandCards(i + 1)
- }
- if f < minAmount {
- minAmount = f
- //minType = common.BidType(i+ 1)
- }
- }
- return maxAmount, minAmount, maxType
- }
- func (ts *tablesink) addHistory() {
- Historys := config.OpenHistory{AreaResult: ts.areaResult, SerialNumber: ts.roomInfo.SerialNumber}
- ts.lock.Lock()
- defer ts.lock.Unlock()
- // log.Debug("addHistory ts.roomInfo:%v", ts.roomInfo)
- log.Debug("addHistory Historys:%v", Historys)
- ts.roomInfo.Historys = append(ts.roomInfo.Historys, Historys)
- if len(ts.roomInfo.Historys) > ts.roomInfo.HistoryCount {
- ts.roomInfo.Historys = ts.roomInfo.Historys[1:]
- }
- }
- // 处理结算
- func (ts *tablesink) handleResult(result common.Result, usr *user.UserInfo) int {
- data, _ := json.Marshal(result)
- if usr != nil {
- go ts.table.SendGameData(usr.GetUserIndex(), Result, string(data))
- }
- actualModifyAmount := result.WinAmount
- //这个游戏比较特殊,写分要用WriteUserMoneyWithModifyAmount
- if result.LoseAmount > 0 {
- //输的写分
- actualModifyAmount = ts.table.WriteUserMoneyWithModifyAmount(result.UserId, -result.LoseAmount, result.Tax, 2, 2+common.GAMEID*100, ts.roomInfo.RoomName)
- } else {
- go ts.table.WriteUserMoney(result.UserId, result.WinAmount, result.Tax, 2, 2+common.GAMEID*100, ts.roomInfo.RoomName)
- }
- // 写用户纪录
- var record common.RecordInfo
- record.Result = result
- record.SerialNumber = ts.roomInfo.SerialNumber
- d, _ := json.Marshal(record)
- go transaction.WriteGameRecord(result.UserId, common.GAMEID, ts.roomInfo.RoomName, string(d))
- return actualModifyAmount
- }
- func (ts *tablesink) getHistory() string {
- ts.lock.RLock()
- defer ts.lock.RUnlock()
- data, _ := json.Marshal(ts.roomInfo.Historys)
- return string(data)
- }
- func (ts *tablesink) getBetDesc(bet common.Bet) string {
- return common.GetBetDesc(bet.BetId)
- }
- func (ts *tablesink) getResultDesc(areaResult []int, diamondCards, clubCards, heartCards, spadeCards common.HandCards) string {
- resultDesc := ""
- for i, v := range areaResult {
- resultDesc += " ["
- resultDesc += common.GetResultDesc(i, v)
- if common.BidType(i) == common.BidType_Diamond {
- resultDesc += getHandCardsHex(diamondCards, true)
- } else if common.BidType(i) == common.BidType_Club {
- resultDesc += getHandCardsHex(clubCards, true)
- } else if common.BidType(i) == common.BidType_Heart {
- resultDesc += getHandCardsHex(heartCards, true)
- } else if common.BidType(i) == common.BidType_Spade {
- resultDesc += getHandCardsHex(spadeCards, true)
- }
- resultDesc += "] "
- }
- return resultDesc
- }
- // 广播免费筹码变化
- func (ts *tablesink) onFreeChipsChange() {
- ts.table.SendGameData(-1, FreeChipChange, "")
- }
|