tablesink_impl.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. package gamelogic
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "time"
  6. "bet24.com/log"
  7. "bet24.com/servers/games/luckyfruit_table/common"
  8. "bet24.com/servers/games/luckyfruit_table/config"
  9. userservices "bet24.com/servers/micros/userservices/proto"
  10. waterpool "bet24.com/servers/micros/waterpool/proto"
  11. "bet24.com/servers/transaction"
  12. "bet24.com/servers/user"
  13. "bet24.com/utils"
  14. )
  15. func (ts *tablesink) startPeriod() {
  16. delaySecond := 0
  17. switch ts.roomInfo.State {
  18. case common.GameState_Open:
  19. delaySecond = ts.roomInfo.BetTime
  20. ts.roomInfo.TotalBet = 0
  21. ts.roomInfo.State = common.GameState_Bet
  22. case common.GameState_Bet:
  23. common.ResetWinningOdds(ts.roomInfo.Odds)
  24. common.ResetFruitProbability(ts.roomInfo.Probability)
  25. delaySecond = ts.roomInfo.OpenTime
  26. ts.roomInfo.State = common.GameState_Open
  27. default:
  28. log.Release("startPeriod failed state = %d", ts.roomInfo.State)
  29. return
  30. }
  31. ts.LastStateTick = time.Now()
  32. ts.onStateChanged()
  33. time.AfterFunc(time.Duration(delaySecond)*time.Second, ts.startPeriod)
  34. log.Debug("tablesink.startPeriod %v:%d,State = %d", ts.roomInfo.RoomName, delaySecond, ts.roomInfo.State)
  35. }
  36. func (ts *tablesink) getStateSecond() int {
  37. return int(time.Since(ts.LastStateTick).Seconds())
  38. }
  39. func (ts *tablesink) onStateChanged() {
  40. if ts.roomInfo.State == common.GameState_Bet {
  41. now := time.Now()
  42. serialNumber := now.Minute() + now.Hour()*100 + now.Day()*10000 + int(now.Month())*1000000 + (now.Year()%10)*100000000
  43. serialNumber = serialNumber*100 + now.Second()
  44. ts.lock.Lock()
  45. ts.userBetList = make(map[int][]common.Bet)
  46. ts.roomInfo.SerialNumber = serialNumber
  47. // ts.spinResult = -1 //便于查看上一局开奖结果
  48. ts.appleAmount = 0
  49. ts.watermelonAmount = 0
  50. ts.bananaAmount = 0
  51. ts.orangeAmount = 0
  52. ts.grapeAmount = 0
  53. ts.lock.Unlock()
  54. log.Debug("onStateChanged SerialNumber = %d", ts.roomInfo.SerialNumber)
  55. go ts.arrangeRobotActions()
  56. }
  57. // 如果是开奖阶段
  58. if ts.roomInfo.State == common.GameState_Open {
  59. go ts.stopRobotPoll()
  60. controlType := waterpool.GetControlType(0, false, common.GAMEID)
  61. ts.enterOpenState(controlType, false)
  62. }
  63. ts.table.NotifySceneChanged(-1)
  64. //ts.refreshRoomInfo()
  65. }
  66. func (ts *tablesink) getStateData() string {
  67. var state common.GameState
  68. state.Sec = ts.getStateSecond()
  69. ts.lock.RLock()
  70. state.State = ts.roomInfo.State
  71. ts.roomInfo.StateSec = state.Sec
  72. state.SpinResult = ts.spinResult
  73. state.Historys = ts.roomInfo.Historys
  74. state.TableUser = *ts.score_users
  75. //state.RichList = ts.richList
  76. //state.BetList = ts.betList
  77. state.SerialNumber = ts.roomInfo.SerialNumber
  78. // if len(ts.scores) > 0 {
  79. // state.Scores = append(state.Scores, ts.scores...)
  80. //} else {
  81. // state.Scores = []common.UserSetScore{}
  82. // }
  83. if state.State == common.GameState_Bet {
  84. for _, v := range ts.userBetList {
  85. state.BetCmds = append(state.BetCmds, v...)
  86. }
  87. }
  88. ts.lock.RUnlock()
  89. data, _ := json.Marshal(state)
  90. return string(data)
  91. }
  92. func (ts *tablesink) isCanBet(bet common.Bet) (bool, string) {
  93. amount := bet.Amount
  94. userId := bet.UserId
  95. betId := bet.BetId
  96. if ts.roomInfo.State != common.GameState_Bet {
  97. return false, "Bet failed,Please wait for next round"
  98. }
  99. if amount < ts.roomInfo.MinBet || amount > ts.roomInfo.MaxBet {
  100. return false, "Bet amount exceeded"
  101. }
  102. bidType := common.Fruit(betId)
  103. if bidType >= common.BigOrange || bidType < common.Orange {
  104. log.Release("isCanBet invalid bet %d,%v", bidType, common.BigOrange)
  105. return false, "invalid bet"
  106. }
  107. // 检查个人下注
  108. myAmount := 0
  109. ts.lock.RLock()
  110. betList, ok := ts.userBetList[userId]
  111. if ok {
  112. for _, v := range betList {
  113. myAmount += v.Amount
  114. }
  115. }
  116. ts.lock.RUnlock()
  117. maxBet := ts.roomInfo.MaxBet
  118. totalMaxBet := ts.roomInfo.TotalMax
  119. totalBet := ts.roomInfo.TotalBet
  120. if myAmount+amount > maxBet {
  121. return false, "Bet amount user exceeded"
  122. }
  123. // 检查全体下注
  124. if amount+totalBet > totalMaxBet {
  125. return false, "Bet amount section exceeded"
  126. }
  127. return true, ""
  128. }
  129. func (ts *tablesink) addBet(bet common.Bet) (bool, string) {
  130. ok, errMsg := ts.isCanBet(bet)
  131. if !ok {
  132. return ok, errMsg
  133. }
  134. ts.lock.Lock()
  135. ts.roomInfo.TotalBet += bet.Amount
  136. betList, ok := ts.userBetList[bet.UserId]
  137. // 合并之前下注
  138. found := false
  139. if ok {
  140. for i := 0; i < len(betList); i++ {
  141. if !betList[i].IsSameBet(&bet) {
  142. continue
  143. }
  144. betList[i].Amount += bet.Amount
  145. // 合并下注
  146. found = true
  147. break
  148. }
  149. }
  150. //log.Debug("tablesink.addBet %v", ts.userBetList)
  151. if !found {
  152. ts.userBetList[bet.UserId] = append(ts.userBetList[bet.UserId], bet)
  153. }
  154. ts.lock.Unlock()
  155. betAmount := bet.Amount
  156. if !bet.IsFree {
  157. ts.userList.addBet(bet.UserId, betAmount, bet.BetId)
  158. }
  159. return true, ""
  160. }
  161. func (ts *tablesink) enterOpenState(controlType int, isReset bool) {
  162. spinResult := common.Spin()
  163. winArea := common.GetWinArea(spinResult)
  164. // 元宝场 避免 连续大苹果 重新摇奖
  165. // if ts.IsChipRoom() && spinResult == common.BigApple && ts.drawAppleWinAmount > 0 {
  166. // spinResult = common.Spin()
  167. // winArea = common.GetWinArea(spinResult)
  168. // }
  169. ts.drawAppleWinAmount = 0
  170. // 开奖
  171. ts.lock.Lock()
  172. ts.spinResult = spinResult
  173. ts.lock.Unlock()
  174. poolValue := waterpool.GetInventoryValue(common.GAMEID, waterpool.RoomType_Hundred, ts.roomInfo.RoomName)
  175. //只重置一次
  176. if !isReset {
  177. //1表示扣减,2表示放水
  178. if controlType != 0 {
  179. simulateBetResults := 0
  180. ts.lock.RLock()
  181. //计算所有区域的下注总额
  182. for _, betList := range ts.userBetList {
  183. if len(betList) == 0 {
  184. continue
  185. }
  186. for _, v := range betList {
  187. if v.IsRobot && !ts.roomInfo.Test {
  188. //机器人跳过
  189. continue
  190. }
  191. odds := common.GetResultOdds(v.BetId, spinResult)
  192. if odds > 0 {
  193. //庄家输
  194. simulateBetResults -= int(odds * float64(v.Amount))
  195. }
  196. //庄家无论输赢都需要收回底注
  197. simulateBetResults += v.Amount
  198. }
  199. }
  200. ts.lock.RUnlock()
  201. log.Release("tableSink.enterOpenState controlType:%v,simulateBetResults:%v", controlType, simulateBetResults)
  202. if controlType == 1 && simulateBetResults < 0 {
  203. ts.enterOpenState(controlType, false)
  204. return
  205. } else if controlType == 2 && simulateBetResults > 0 {
  206. ts.enterOpenState(controlType, false)
  207. return
  208. }
  209. }
  210. }
  211. //log.Debug("getCards %v,%v", ts.bankerCards, ts.playerCards)
  212. //log.Debug("GetResult r= %v,bankerCardType = %v, bankerCardPoint = %v ,playerCardType = %v, playerCardPoint = %v", r, bankerCardType, bankerCardPoint, playerCardType, playerCardPoint)
  213. ts.addHistory(int(spinResult))
  214. ts.lock.Lock()
  215. ts.scores = []common.UserSetScore{}
  216. // 纪录每个玩家总输赢
  217. for userId, betList := range ts.userBetList {
  218. usr := ts.table.GetUserByUserId(userId)
  219. var total struct {
  220. UserId int
  221. BetAmount int
  222. WinAmount int
  223. WinAmountOnly int
  224. }
  225. total.UserId = userId
  226. betDesc := fmt.Sprintf("SpinResult: %v WinArea: %v", spinResult, winArea)
  227. resultDesc := ""
  228. totalTax := 0
  229. //开奖赔率
  230. winOdds := common.GetOdds(spinResult)
  231. var betAreas []betAreaInfo
  232. for _, v := range betList {
  233. // 根据每个人计算结果
  234. var result common.Result
  235. result.UserId = v.UserId
  236. result.Bet = v
  237. result.SpinResult = spinResult
  238. result.WinArea = winArea
  239. result.Amount = v.Amount
  240. betAmount := v.Amount
  241. if v.IsFree {
  242. betAmount = 0
  243. }
  244. betAreas = append(betAreas, betAreaInfo{
  245. betArea: v.BetId,
  246. betAmount: v.Amount,
  247. })
  248. total.BetAmount += betAmount
  249. odds := common.GetResultOdds(result.BetId, spinResult)
  250. //log.Debug("GetResultOdds odds= %v, BetId = %v", odds, result.BetId)
  251. // 看下有没有中的
  252. if odds > 0 {
  253. result.WinAmount = int(odds * float64(result.Amount))
  254. //免费的也要扣本金
  255. // realWin := result.WinAmount - result.Amount
  256. // if realWin > 0 {
  257. // result.Tax = realWin * ts.roomInfo.TaxRate / 100
  258. // }
  259. result.Tax = result.WinAmount * ts.roomInfo.TaxRate / 100
  260. total.WinAmountOnly += result.WinAmount
  261. result.WinAmount -= result.Tax
  262. total.WinAmount += result.WinAmount
  263. }
  264. betDesc = fmt.Sprintf("%s [%s:%s]", betDesc, ts.getBetDesc(result.Bet), utils.FormatScore(v.Amount))
  265. resultDesc = ts.getResultDesc(result)
  266. totalTax += result.Tax
  267. ts.handleResult(result, usr)
  268. }
  269. if ts.roomInfo.Test {
  270. ts.stat.lists = append(ts.stat.lists, Statistics{
  271. betAmount: total.BetAmount,
  272. winAmount: total.WinAmount,
  273. betArea: betAreas,
  274. winArea: spinResult,
  275. winOdd: winOdds,
  276. waterpool: poolValue,
  277. })
  278. }
  279. // 纪录输赢
  280. go ts.table.WriteBetRecordWithPlayTime(userId, total.BetAmount, total.WinAmount, winOdds,
  281. betDesc, resultDesc, ts.roomInfo.RoomName, ts.roomInfo.BetTime)
  282. ts.userList.addResult(userId, total.WinAmount-total.BetAmount, total.WinAmountOnly)
  283. ts.scores = append(ts.scores, common.UserSetScore{UserId: userId, Score: total.WinAmount - total.BetAmount})
  284. if usr == nil {
  285. //检查是否为机器人
  286. if !userservices.IsRobot(userId) || ts.roomInfo.Test {
  287. ts.settleStats(userId, total.BetAmount, total.WinAmount, totalTax)
  288. }
  289. continue
  290. } else if !usr.IsRobot() || ts.roomInfo.Test {
  291. ts.settleStats(userId, total.BetAmount, total.WinAmount, totalTax)
  292. }
  293. // 发送我的总输赢
  294. data, _ := json.Marshal(total)
  295. ts.table.SendGameData(usr.GetUserIndex(), TotalResult, string(data))
  296. }
  297. ts.lock.Unlock()
  298. ts.betRank.betPoolToRedis()
  299. //ts.userList.dump()
  300. // 结算完毕,计算连胜榜
  301. ts.lock.Lock()
  302. // ts.score_users.LuckyStarUsers = ts.userList.getLuckyStarUsers(5)
  303. //因为前端只需要显示前十名的NickName和金币所以这里只取前十名
  304. ts.score_users.WinGoldRankingUsers = ts.userList.getWinGoldRankingUsers(10)
  305. // ts.richList = ts.refreshRichList(20)
  306. ts.score_users.BetGoldRankingUsers = ts.userList.getBetGoldRankingUsers(5)
  307. ts.lock.Unlock()
  308. ts.userList.clearBetStatus()
  309. }
  310. // 结算统计
  311. func (ts *tablesink) settleStats(userId, betAmount, winAmount, totalTax int) {
  312. if betAmount > 0 {
  313. ts.betRank.addBetPool(userId, betAmount)
  314. }
  315. //上报水池
  316. go waterpool.AddBet(0, betAmount, false, common.GAMEID)
  317. go waterpool.ReducePool(0, winAmount, false, common.GAMEID)
  318. }
  319. // func (ts *tablesink) refreshRichList(count int) []int {
  320. // userlist := ts.table.GetUserList()
  321. // sort.Slice(userlist, func(i, j int) bool {
  322. // return ts.table.GetUserChipOrGoldByUser(userlist[i]) > ts.table.GetUserChipOrGoldByUser(userlist[j])
  323. // })
  324. // ret := []int{}
  325. // for k, v := range userlist {
  326. // if k >= count {
  327. // break
  328. // }
  329. // gold := ts.table.GetUserChipOrGoldByUser(v)
  330. // if gold <= 0 {
  331. // break
  332. // }
  333. // ret = append(ret, v.GetUserId())
  334. // }
  335. // return ret
  336. // }
  337. func (ts *tablesink) addHistory(spinResult int) {
  338. Historys := config.OpenHistory{SpinResult: spinResult, SerialNumber: ts.roomInfo.SerialNumber}
  339. ts.lock.Lock()
  340. defer ts.lock.Unlock()
  341. log.Debug("addHistory %v,%v", Historys, ts.roomInfo)
  342. ts.roomInfo.Historys = append(ts.roomInfo.Historys, Historys)
  343. if len(ts.roomInfo.Historys) > ts.roomInfo.HistoryCount {
  344. ts.roomInfo.Historys = ts.roomInfo.Historys[1:]
  345. }
  346. }
  347. // 处理结算
  348. func (ts *tablesink) handleResult(result common.Result, usr *user.UserInfo) {
  349. // data, _ := json.Marshal(result)
  350. // if usr != nil {
  351. // go ts.table.SendGameData(usr.GetUserIndex(), Result, string(data))
  352. // }
  353. ts.table.WriteUserMoney(result.UserId, result.WinAmount, result.Tax, 2, 2+common.GAMEID*100, ts.roomInfo.RoomName)
  354. // 写用户纪录
  355. var record common.RecordInfo
  356. record.SpinResult = result.SpinResult
  357. record.SerialNumber = ts.roomInfo.SerialNumber
  358. d, _ := json.Marshal(record)
  359. go transaction.WriteGameRecord(result.UserId, common.GAMEID, ts.roomInfo.RoomName, string(d))
  360. }
  361. func (ts *tablesink) getHistory() string {
  362. ts.lock.RLock()
  363. defer ts.lock.RUnlock()
  364. data, _ := json.Marshal(ts.roomInfo.Historys)
  365. return string(data)
  366. }
  367. func (ts *tablesink) getBetDesc(bet common.Bet) string {
  368. return common.GetBetDesc(bet.BetId)
  369. }
  370. func (ts *tablesink) getResultDesc(result common.Result) string {
  371. return common.GetResultDesc(result.SpinResult)
  372. }
  373. // 广播免费筹码变化
  374. func (ts *tablesink) onFreeChipsChange() {
  375. ts.table.SendGameData(-1, FreeChipChange, "")
  376. }