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, "") }