package gamelogic import ( "encoding/json" "fmt" "time" "bet24.com/log" "bet24.com/servers/games/luckyfruit_table/common" "bet24.com/servers/games/luckyfruit_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: delaySecond = ts.roomInfo.BetTime ts.roomInfo.TotalBet = 0 ts.roomInfo.State = common.GameState_Bet case common.GameState_Bet: common.ResetWinningOdds(ts.roomInfo.Odds) common.ResetFruitProbability(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() 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) onStateChanged() { if ts.roomInfo.State == 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.spinResult = -1 //便于查看上一局开奖结果 ts.appleAmount = 0 ts.watermelonAmount = 0 ts.bananaAmount = 0 ts.orangeAmount = 0 ts.grapeAmount = 0 ts.lock.Unlock() log.Debug("onStateChanged SerialNumber = %d", ts.roomInfo.SerialNumber) go ts.arrangeRobotActions() } // 如果是开奖阶段 if ts.roomInfo.State == common.GameState_Open { go ts.stopRobotPoll() controlType := waterpool.GetControlType(0, false, common.GAMEID) ts.enterOpenState(controlType, false) } 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.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.Fruit(betId) if bidType >= common.BigOrange || bidType < common.Orange { log.Release("isCanBet invalid bet %d,%v", bidType, common.BigOrange) 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 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.lock.Unlock() betAmount := bet.Amount if !bet.IsFree { ts.userList.addBet(bet.UserId, betAmount, bet.BetId) } return true, "" } func (ts *tablesink) enterOpenState(controlType int, isReset bool) { spinResult := common.Spin() winArea := common.GetWinArea(spinResult) // 元宝场 避免 连续大苹果 重新摇奖 // if ts.IsChipRoom() && spinResult == common.BigApple && ts.drawAppleWinAmount > 0 { // spinResult = common.Spin() // winArea = common.GetWinArea(spinResult) // } ts.drawAppleWinAmount = 0 // 开奖 ts.lock.Lock() ts.spinResult = spinResult ts.lock.Unlock() poolValue := waterpool.GetInventoryValue(common.GAMEID, waterpool.RoomType_Hundred, ts.roomInfo.RoomName) //只重置一次 if !isReset { //1表示扣减,2表示放水 if controlType != 0 { simulateBetResults := 0 ts.lock.RLock() //计算所有区域的下注总额 for _, betList := range ts.userBetList { if len(betList) == 0 { continue } for _, v := range betList { if v.IsRobot && !ts.roomInfo.Test { //机器人跳过 continue } odds := common.GetResultOdds(v.BetId, spinResult) if odds > 0 { //庄家输 simulateBetResults -= int(odds * float64(v.Amount)) } //庄家无论输赢都需要收回底注 simulateBetResults += v.Amount } } ts.lock.RUnlock() log.Release("tableSink.enterOpenState controlType:%v,simulateBetResults:%v", controlType, simulateBetResults) if controlType == 1 && simulateBetResults < 0 { ts.enterOpenState(controlType, false) return } else if controlType == 2 && simulateBetResults > 0 { ts.enterOpenState(controlType, false) return } } } //log.Debug("getCards %v,%v", ts.bankerCards, ts.playerCards) //log.Debug("GetResult r= %v,bankerCardType = %v, bankerCardPoint = %v ,playerCardType = %v, playerCardPoint = %v", r, bankerCardType, bankerCardPoint, playerCardType, playerCardPoint) ts.addHistory(int(spinResult)) ts.lock.Lock() ts.scores = []common.UserSetScore{} // 纪录每个玩家总输赢 for userId, betList := range ts.userBetList { usr := ts.table.GetUserByUserId(userId) var total struct { UserId int BetAmount int WinAmount int WinAmountOnly int } total.UserId = userId betDesc := fmt.Sprintf("SpinResult: %v WinArea: %v", spinResult, winArea) resultDesc := "" totalTax := 0 //开奖赔率 winOdds := common.GetOdds(spinResult) var betAreas []betAreaInfo for _, v := range betList { // 根据每个人计算结果 var result common.Result result.UserId = v.UserId result.Bet = v result.SpinResult = spinResult result.WinArea = winArea result.Amount = v.Amount betAmount := v.Amount if v.IsFree { betAmount = 0 } betAreas = append(betAreas, betAreaInfo{ betArea: v.BetId, 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 // } result.Tax = result.WinAmount * ts.roomInfo.TaxRate / 100 total.WinAmountOnly += result.WinAmount result.WinAmount -= result.Tax total.WinAmount += result.WinAmount } betDesc = fmt.Sprintf("%s [%s:%s]", betDesc, ts.getBetDesc(result.Bet), utils.FormatScore(v.Amount)) resultDesc = ts.getResultDesc(result) totalTax += result.Tax ts.handleResult(result, usr) } if ts.roomInfo.Test { ts.stat.lists = append(ts.stat.lists, Statistics{ betAmount: total.BetAmount, winAmount: total.WinAmount, betArea: betAreas, winArea: spinResult, winOdd: winOdds, waterpool: poolValue, }) } // 纪录输赢 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 { //检查是否为机器人 if !userservices.IsRobot(userId) || ts.roomInfo.Test { ts.settleStats(userId, total.BetAmount, total.WinAmount, totalTax) } continue } else if !usr.IsRobot() || ts.roomInfo.Test { ts.settleStats(userId, total.BetAmount, total.WinAmount, totalTax) } // 发送我的总输赢 data, _ := json.Marshal(total) ts.table.SendGameData(usr.GetUserIndex(), TotalResult, string(data)) } ts.lock.Unlock() ts.betRank.betPoolToRedis() //ts.userList.dump() // 结算完毕,计算连胜榜 ts.lock.Lock() // ts.score_users.LuckyStarUsers = ts.userList.getLuckyStarUsers(5) //因为前端只需要显示前十名的NickName和金币所以这里只取前十名 ts.score_users.WinGoldRankingUsers = ts.userList.getWinGoldRankingUsers(10) // ts.richList = ts.refreshRichList(20) ts.score_users.BetGoldRankingUsers = ts.userList.getBetGoldRankingUsers(5) ts.lock.Unlock() ts.userList.clearBetStatus() } // 结算统计 func (ts *tablesink) settleStats(userId, betAmount, winAmount, totalTax int) { if betAmount > 0 { ts.betRank.addBetPool(userId, betAmount) } //上报水池 go waterpool.AddBet(0, betAmount, false, common.GAMEID) go waterpool.ReducePool(0, winAmount, false, common.GAMEID) } // func (ts *tablesink) refreshRichList(count int) []int { // userlist := ts.table.GetUserList() // sort.Slice(userlist, func(i, j int) bool { // return ts.table.GetUserChipOrGoldByUser(userlist[i]) > ts.table.GetUserChipOrGoldByUser(userlist[j]) // }) // ret := []int{} // for k, v := range userlist { // if k >= count { // break // } // gold := ts.table.GetUserChipOrGoldByUser(v) // if gold <= 0 { // break // } // ret = append(ret, v.GetUserId()) // } // return ret // } 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(result common.Result, usr *user.UserInfo) { // data, _ := json.Marshal(result) // if usr != nil { // go ts.table.SendGameData(usr.GetUserIndex(), Result, string(data)) // } ts.table.WriteUserMoney(result.UserId, result.WinAmount, result.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(result.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) onFreeChipsChange() { ts.table.SendGameData(-1, FreeChipChange, "") }