package gamelogic import ( "encoding/json" "fmt" "time" "bet24.com/log" "bet24.com/servers/games/greedy/common" "bet24.com/servers/games/greedy/config" userservices "bet24.com/servers/micros/userservices/proto" waterpool "bet24.com/servers/micros/waterpool/proto" "bet24.com/servers/user" "bet24.com/utils" ) func (ts *tablesink) startPeriod() { delaySecond := 0 switch ts.roomInfo.State { case common.GameState_Open: delaySecond = ts.roomInfo.BetTime ts.roomInfo.TotalBet = 0 ts.roomInfo.State = common.GameState_Bet case common.GameState_Bet: common.ResetWinningOdds(ts.roomInfo.Odds) common.ResetBetProbability(ts.roomInfo.Probability) delaySecond = ts.roomInfo.OpenTime ts.roomInfo.State = common.GameState_Open default: log.Release("startPeriod failed state = %d", ts.roomInfo.State) return } ts.LastStateTick = time.Now() ts.onStateChanged() if ts.closeGame && ts.roomInfo.State == common.GameState_Open { //开奖后关闭房间 log.Debug("tablesink.startPeriod Close the room after the open draw %v:%d,State = %d noPlayerCount= %d ", ts.roomInfo.RoomName, delaySecond, ts.roomInfo.State, ts.noPlayerCount) // 关闭游戏 ts.stopPeriodPoll() return } ts.timer = 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) stopPeriodPoll() { if ts.timer != nil { ts.timer.Stop() } if ts.noPlayerCount >= 6 { ts.table.PrivateRoomSetWinners(nil) } } func (ts *tablesink) getStateSecond() int { return int(time.Since(ts.LastStateTick).Seconds()) } func (ts *tablesink) onStateChanged() { if ts.roomInfo.State == common.GameState_Bet { ts.lock.Lock() ts.userBetList = make(map[int][]common.Bet) ts.roomInfo.SerialNumber++ //初始化8个区域 max := int(common.BidTypeMax) betCounts := make([]int, max) diamondHots := make([]int, max) areaPopular := common.AreaPopular{ MostPopular: -1, BetCount: betCounts, DiamondHot: diamondHots, } ts.areaPopular = &areaPopular ts.hotDogAmount = 0 ts.kebabAmount = 0 ts.chickenLegAmount = 0 ts.meatSliceAmount = 0 ts.radishAmount = 0 ts.cornAmount = 0 ts.spinachAmount = 0 ts.tomatoAmount = 0 ts.lock.Unlock() log.Debug("onStateChanged SerialNumber = %d", ts.roomInfo.SerialNumber) go ts.arrangeRobotActions() } // 如果是开奖阶段 if ts.roomInfo.State == common.GameState_Open { ts.enterOpenState(false) go ts.stopRobotPoll() } 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.SpinResult = ts.spinResult state.Historys = ts.roomInfo.Historys state.TableUser = *ts.score_users state.AreaPopular = *ts.areaPopular state.SerialNumber = ts.roomInfo.SerialNumber if state.State == common.GameState_Bet { for _, v := range ts.userBetList { state.BetCmds = append(state.BetCmds, v...) } } state.CloseGame = ts.closeGame 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.BetOption(betId) if bidType >= common.BidTypeMax || bidType < common.HotDog { log.Release("isCanBet invalid betting area %d,%v", bidType, common.HotDog) return false, "invalid bet area" } // 检查个人下注 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 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) 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.areaPopular.BetCount[bet.BetId]++ } ts.lock.Unlock() betAmount := bet.Amount ts.userList.addBet(bet.UserId, betAmount, bet.BetId) return true, "" } func (ts *tablesink) enterOpenState(isReset bool) { spinResult := common.Spin() // 钻石场 避免 连续大奖 重新摇奖 if gs.IsChipRoom() && spinResult == common.MeatSlice && ts.drawMeatSliceWinAmount > 0 { spinResult = common.Spin() } ts.drawMeatSliceWinAmount = 0 // 开奖 ts.lock.Lock() ts.spinResult = spinResult ts.lock.Unlock() //针对主区域差额确定,特殊区域不考虑 controlType := 0 //controlType 1表示扣减,2表示放水 //找到投注额的最大值和最小值 maxAmount := ts.hotDogAmount minAmount := ts.hotDogAmount //最大值和最小值对应的下注区域 var maxBet, minBet common.BetOption betsAmount := []int{ts.hotDogAmount, ts.kebabAmount, ts.chickenLegAmount, ts.meatSliceAmount, ts.radishAmount, ts.cornAmount, ts.spinachAmount, ts.tomatoAmount} //只重置一次 if !isReset { for i, f := range betsAmount { if f > maxAmount { maxAmount = f //因为默认值是0,所以这里要加1 maxBet = common.BetOption(i + 1) } if f < minAmount { minAmount = f minBet = common.BetOption(i + 1) } } if maxAmount > 0 || minAmount > 0 { controlType = waterpool.GetControlType(0, false, common.GAMEID) } //根据情况判断是否需要重新开奖 if controlType == 1 { if spinResult == maxBet { ts.enterOpenState(true) return } } else if controlType == 2 { if spinResult != minBet { ts.enterOpenState(true) return } } } ts.addHistory(int(spinResult)) ts.lock.Lock() ts.scores = []common.UserSetScore{} if ts.userList == nil { // 如果没有玩家,将 noPlayerCount 的值加 1 ts.noPlayerCount++ if ts.noPlayerCount >= 6 { // 如果连续 6 期没有玩家,开奖后关闭游戏 ts.closeGame = true } } else { ts.noPlayerCount = 0 } // 纪录每个玩家总输赢 for userId, betList := range ts.userBetList { usr := ts.table.GetUserByUserId(userId) var total struct { UserId int BetAmount int WinAmount int WinAmountOnly int DayWinAmount int } total.UserId = userId betDesc := fmt.Sprintf("%v:", ts.roomInfo.SerialNumber) betIdDesc := "" betAmountDesc := "" resultDesc := "" totalTax := 0 //开奖赔率 winOdds := common.GetOdds(spinResult) for i, v := range betList { // 根据每个人计算结果 var result common.Result result.UserId = v.UserId result.Bet = v result.SpinResult = spinResult result.Amount = v.Amount betAmount := v.Amount total.BetAmount += betAmount odds := common.GetResultOdds(result.BetId, spinResult) //log.Debug("GetResultOdds odds= %v, BetId = %v", odds, result.BetId) // 看下有没有中的 if odds > 0 { result.WinAmount = int(odds * float64(result.Amount)) //免费的也要扣本金 realWin := result.WinAmount - result.Amount if realWin > 0 { result.Tax = realWin * ts.roomInfo.TaxRate / 100 } total.WinAmountOnly += result.WinAmount result.WinAmount -= result.Tax total.WinAmount += result.WinAmount } betIdDesc += fmt.Sprintf("%d", result.BetId) if i != len(betList)-1 { betIdDesc += "," } betAmountDesc = fmt.Sprintf("%s [%s:%s]", betAmountDesc, ts.getBetDesc(result.Bet), utils.FormatScore(v.Amount)) resultDesc = ts.getResultDesc(result) totalTax += result.Tax //ts.handleResult(result, usr) } betDesc = fmt.Sprintf("%s%s&%s", betDesc, betIdDesc, betAmountDesc) if total.WinAmountOnly > 0 { ts.winRank.addWinPool(userId, total.WinAmountOnly) } go ts.handleResult(userId, total.BetAmount, total.WinAmount, totalTax, usr) // 纪录输赢 go ts.table.WriteBetRecordWithPlayTime(userId, total.BetAmount, total.WinAmount, winOdds, betDesc, resultDesc, ts.roomInfo.RoomName, ts.roomInfo.BetTime) ts.userList.addResult(userId, total.WinAmount-total.BetAmount, total.WinAmountOnly) ts.scores = append(ts.scores, common.UserSetScore{UserId: userId, Score: total.WinAmount - total.BetAmount}) if usr == nil { continue } _, _, winAmount := ts.winRank.getRankList(userId, -1) total.DayWinAmount = winAmount // 发送我的总输赢 data, _ := json.Marshal(total) ts.table.SendGameData(usr.GetUserIndex(), TotalResult, string(data)) } ts.lock.Unlock() ts.winRank.winPoolToRedis() //ts.userList.dump() // 结算完毕,计算连胜榜 ts.lock.Lock() //因为前端只需要显示前三名的NickName和金币所以这里只取前三名 ts.score_users.WinGoldRankingUsers = ts.userList.getWinGoldRankingUsers(3) ts.score_users.DayWinGoldRankingUsers = ts.GetWinRank(1) ts.lock.Unlock() ts.userList.clearBetStatus() } func (ts *tablesink) addHistory(spinResult int) { Historys := config.OpenHistory{SpinResult: spinResult, SerialNumber: ts.roomInfo.SerialNumber} ts.lock.Lock() defer ts.lock.Unlock() log.Debug("addHistory %v,%v", Historys, ts.roomInfo) 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(userId int, betAmount, winAmount, tax int, usr *user.UserInfo) { // data, _ := json.Marshal(result) // if usr != nil { // go ts.table.SendGameData(usr.GetUserIndex(), Result, string(data)) // } ts.table.WriteUserMoney(userId, winAmount, tax, 2, 2+common.GAMEID*100, ts.roomInfo.RoomName) // 写用户纪录 // var record common.RecordInfo // record.SpinResult = result.SpinResult // record.SerialNumber = ts.roomInfo.SerialNumber // d, _ := json.Marshal(record) // go transaction.WriteGameRecord(userId, common.GAMEID, ts.roomInfo.RoomName, string(d)) } 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(result common.Result) string { return common.GetResultDesc(result.SpinResult) } func (ts *tablesink) currentGameNumber() int { now := time.Now() startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) difference := now.Sub(startOfDay) secondsSinceMidnight := int(difference.Seconds()) gameDuration := ts.roomInfo.BetTime + ts.roomInfo.OpenTime currentGame := secondsSinceMidnight/gameDuration + 1 return currentGame } func (ts *tablesink) GetWinRank(count int) []common.ScoreUser { //用户id var userIds []int //获取winRank前10名 rankList, _, _ := ts.winRank.getRankList(0, count) log.Debug("tablesink.GetWinRank rankList:%v", rankList) //不为空 if len(rankList) > 0 { scoreUserList := make([]common.ScoreUser, 0, len(rankList)) //如果rankList昵称为空则补齐 userIds = make([]int, len(rankList)) for i, u := range rankList { userIds[i] = u.UserId } users := userservices.GetUserInfoInBulk(userIds) for i, v := range rankList { info := make([]int, 0, 1) info = append(info, v.WinAmount) scoreUser := common.ScoreUser{ UserId: v.UserId, NickName: "", FaceId: 0, FaceUrl: "", VipLevel: 0, VipExpire: 0, Decorations: nil, Info: info, } user := users[i] if user.UserId == v.UserId { 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) } return scoreUserList } return []common.ScoreUser{} }