tablesink_impl.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. package gamelogic
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math"
  6. "math/rand"
  7. "time"
  8. coreservice "bet24.com/servers/coreservice/client"
  9. "bet24.com/servers/games/ludo/config"
  10. robotmanager "bet24.com/servers/insecureframe/robot"
  11. "bet24.com/servers/user"
  12. )
  13. func (ts *tablesink) checkAndStartGame() {
  14. if ts.gameScene.Phase != Phase_Free && ts.gameScene.Phase != Phase_End {
  15. return
  16. }
  17. // 查看是否所有人都ready
  18. readyCount := 0
  19. for i := 0; i < CHAIR_COUNT; i++ {
  20. usr := ts.table.GetUserByChair(i)
  21. if usr == nil {
  22. continue
  23. }
  24. userStatus := usr.GetUserStatus()
  25. // 旁观不判断
  26. if userStatus <= user.UserStatus_Free ||
  27. userStatus == user.UserStatus_Watch {
  28. continue
  29. }
  30. // 如果是开始
  31. if userStatus == user.UserStatus_Play {
  32. ts.table.LogWithTableId("-----checkAndStartGame: chair[%d]: %d, playing kicked", i, usr.GetUserId())
  33. //ts.table.KickUserByChair(i, true)
  34. continue
  35. }
  36. if userStatus != user.UserStatus_Ready {
  37. ts.table.LogWithTableId("-----checkAndStartGame: chair[%d]: %d, status: %d", i, usr.GetUserId(), usr.GetUserStatus())
  38. return
  39. }
  40. readyCount++
  41. }
  42. // ts.table.LogWithTableId("-----checkAndStartGame : %d ", readyCount)
  43. if ts.IsDual() && readyCount == 2 || readyCount == 4 {
  44. ts.startGame()
  45. }
  46. }
  47. func (ts *tablesink) getValidUserCount() int {
  48. count := 0
  49. for i := 0; i < CHAIR_COUNT; i++ {
  50. usr := ts.table.GetUserByChair(i)
  51. if usr == nil {
  52. continue
  53. }
  54. if usr.IsRobot() {
  55. continue
  56. }
  57. userStatus := usr.GetUserStatus()
  58. if userStatus <= user.UserStatus_Free || userStatus == user.UserStatus_Watch {
  59. continue
  60. }
  61. count++
  62. }
  63. return count
  64. }
  65. func (ts *tablesink) checkIsNeedRobot() {
  66. if !robotmanager.IsRunning() {
  67. return
  68. }
  69. if ts.gameScene.Phase != Phase_Free && ts.gameScene.Phase != Phase_End {
  70. return
  71. }
  72. count := 0
  73. for i := 0; i < CHAIR_COUNT; i++ {
  74. usr := ts.table.GetUserByChair(i)
  75. if usr == nil {
  76. continue
  77. }
  78. /*if usr.IsRobot() {
  79. continue
  80. }*/
  81. if usr.GetUserStatus() <= user.UserStatus_Free {
  82. continue
  83. }
  84. count++
  85. }
  86. chairCount := CHAIR_COUNT
  87. if ts.IsDual() {
  88. chairCount = 2
  89. }
  90. if count >= chairCount {
  91. return
  92. }
  93. robotCount := 1
  94. if !ts.IsDual() {
  95. robotCount = rand.Intn(chairCount-count) + 1
  96. }
  97. ts.table.LogWithTableId("-------checkIsNeedRobot. need: %d ------", robotCount)
  98. for i := 0; i < robotCount; i++ {
  99. sec := rand.Intn(robotCount*3*1000) + 1000
  100. time.AfterFunc(time.Duration(sec)*time.Millisecond, func() {
  101. if ts.gameScene.Phase != Phase_Free && ts.gameScene.Phase != Phase_End {
  102. return
  103. }
  104. tableID := ts.table.GetTableID()
  105. robotmanager.GetOneRobotEnterTable(tableID, ts.roomInfo.MinGold, ts.roomInfo.MaxGold)
  106. })
  107. }
  108. }
  109. func (ts *tablesink) removeOneRobot() {
  110. if ts.gameScene.Phase != Phase_End {
  111. return
  112. }
  113. for i := 0; i < CHAIR_COUNT; i++ {
  114. usr := ts.table.GetUserByChair(i)
  115. if usr == nil {
  116. continue
  117. }
  118. if !usr.IsRobot() {
  119. continue
  120. }
  121. ts.table.KickUserByChair(i, false)
  122. return
  123. }
  124. }
  125. func (ts *tablesink) checkUserReadyStatus(chair int) {
  126. if ts.gameScene.Phase != Phase_Free && ts.gameScene.Phase != Phase_End {
  127. return
  128. }
  129. usr := ts.table.GetUserByChair(chair)
  130. if usr == nil {
  131. return
  132. }
  133. if !usr.IsRobot() {
  134. ts.table.LogWithTableId("1111111------checkUserReadyStatus: %d %d", chair, usr.GetUserId())
  135. //超时没有准备则踢出
  136. ts.table.KickUserByChair(chair, true)
  137. //ts.table.UserWatch(usr.GetUserIndex())
  138. return
  139. }
  140. //桌上还有没有真人,有就准备,没有就踢走
  141. count := 0
  142. for i := 0; i < CHAIR_COUNT; i++ {
  143. u := ts.table.GetUserByChair(i)
  144. if u == nil {
  145. continue
  146. }
  147. if u.IsRobot() {
  148. continue
  149. }
  150. if u.GetUserStatus() <= user.UserStatus_Free {
  151. continue
  152. }
  153. count++
  154. }
  155. if count >= 1 {
  156. ts.table.LogWithTableId("tablesink.checkUserReadyStatus: %d robot to ready ", usr.GetUserId())
  157. ts.table.SetUserReadyStatus(usr.GetUserIndex(), true)
  158. } else {
  159. ts.table.LogWithTableId("222222------checkUserReadyStatus: %d ", usr.GetUserId())
  160. //超时没有准备则踢出
  161. ts.table.KickUser(usr.GetUserIndex(), !usr.IsRobot())
  162. // if usr.IsRobot() {
  163. // //ts.table.UserWatch(usr.GetUserIndex())
  164. // ts.table.KickUser(usr.GetUserIndex(), false)
  165. // } else {
  166. // ts.table.UserWatch(usr.GetUserIndex())
  167. // }
  168. }
  169. }
  170. //匹配阶段超时
  171. func (ts *tablesink) dealMatchTimeOut() {
  172. ts.gameScene.Phase = Phase_Move
  173. ts.LastOpraTime = time.Now()
  174. ts.gameScene.Index++
  175. ts.table.NotifySceneChanged(-1)
  176. ts.resetGameTimer(false, false, 0)
  177. }
  178. //移动棋子或掷骰子 阶段超时
  179. func (ts *tablesink) dealPlayTimeOut() {
  180. if ts.gameScene.Phase != Phase_Dice && ts.gameScene.Phase != Phase_Move {
  181. return
  182. }
  183. if isValidChair(ts.gameScene.WhoseTurn) {
  184. ts.gameScene.Players[ts.gameScene.WhoseTurn].AutoOut = true
  185. }
  186. ts.dealGamePlay()
  187. }
  188. //处理游戏阶段逻辑 包含掷骰子和移动飞机
  189. func (ts *tablesink) dealGamePlay() {
  190. ts.LastOpraTime = time.Now()
  191. chairId := ts.gameScene.WhoseTurn
  192. if !isValidChair(chairId) {
  193. ts.table.LogWithTableId("tablesink.dealGamePlay whoseturn invalid %d", chairId)
  194. return
  195. }
  196. player := ts.gameScene.Players[chairId]
  197. // 掷骰子
  198. if player.LastAction == Action_Move {
  199. ts.doAction(chairId, Action_Dice, 0, nil)
  200. } else {
  201. ts.doAction(chairId, Action_Move, -1, nil)
  202. }
  203. }
  204. func (ts *tablesink) onRobotChatTimer() {
  205. start := rand.Intn(4)
  206. for i := 0; i < CHAIR_COUNT; i++ {
  207. chair := (start + i) % CHAIR_COUNT
  208. usr := ts.table.GetUserByChair(chair)
  209. if usr == nil || !usr.IsRobot() {
  210. continue
  211. }
  212. whoseturn := ts.table.GetUserByChair(ts.gameScene.WhoseTurn)
  213. if whoseturn == nil {
  214. return
  215. }
  216. ts.sendBatChat(usr.GetUserIndex(), usr.GetUserId(), whoseturn.GetUserId())
  217. return
  218. }
  219. }
  220. func (ts *tablesink) sendBatChat(userIndex int32, sender, receiver int) {
  221. if sender == receiver {
  222. return
  223. }
  224. if rand.Intn(100) >= 35 {
  225. return
  226. }
  227. chatIds := []int{0, 4, 10, 11}
  228. chatId := chatIds[rand.Intn(4)]
  229. data := fmt.Sprintf("3/%d/%d/%d", chatId, sender, receiver)
  230. ts.table.LogWithTableId("tablesink.sendBatChat ,%s", data)
  231. ts.recvChatMsg(userIndex, data)
  232. }
  233. func (ts *tablesink) sendLoseChat(userIndex int32, sender int, delayMs int) bool {
  234. if rand.Intn(100) >= 25 {
  235. return false
  236. }
  237. time.AfterFunc(time.Duration(delayMs)*time.Millisecond, func() {
  238. chatIds := []int{1, 2, 4, 5}
  239. chatId := chatIds[rand.Intn(4)]
  240. data := fmt.Sprintf("2/%d/%d", chatId, sender)
  241. ts.table.LogWithTableId("tablesink.sendLoseChat ,%s", data)
  242. ts.recvChatMsg(userIndex, data)
  243. })
  244. return true
  245. }
  246. func (ts *tablesink) sendWinChat(userIndex int32, sender int, delayMs int) {
  247. if rand.Intn(100) >= 25 {
  248. return
  249. }
  250. time.AfterFunc(time.Duration(delayMs)*time.Millisecond, func() {
  251. chatIds := []int{0, 3}
  252. chatId := chatIds[rand.Intn(2)]
  253. data := fmt.Sprintf("2/%d/%d", chatId, sender)
  254. ts.table.LogWithTableId("tablesink.sendWinChat ,%s", data)
  255. ts.recvChatMsg(userIndex, data)
  256. })
  257. }
  258. //检查机器人操作
  259. func (ts *tablesink) checkRobotAction(isCanMove, isNextChair bool, moveDuration int) {
  260. chairId := ts.gameScene.WhoseTurn
  261. usr := ts.table.GetUserByChair(chairId)
  262. if usr == nil {
  263. return
  264. }
  265. if !usr.IsRobot() {
  266. return
  267. }
  268. //机器人也要考虑延迟问题 否则会导致前端收消息过快
  269. delay := SEC_DELAY //掷骰子时间 机器人用等待时间
  270. switch ts.gameScene.Phase {
  271. case Phase_Dice:
  272. //如果没有可以移动的则直接进入掷骰子阶段的定时间
  273. if isNextChair && !isCanMove {
  274. //没有移动直接换人 加延迟
  275. delay += SEC_NEXT_CHAIR
  276. } else if isCanMove {
  277. //移动棋子时间
  278. delay -= SEC_NEXT_CHAIR
  279. //机器人要判断是否只有一个棋子可以移动
  280. count := ts.gameScene.Players[chairId].canMovePlaneCountByPosition()
  281. if count != 1 {
  282. //有多个棋子时增加选择时间
  283. delay += rand.Intn(2500)
  284. }
  285. }
  286. case Phase_Move:
  287. //前一个有移动的话 要算上移动的等待时间
  288. if isCanMove {
  289. delay += moveDuration
  290. }
  291. }
  292. time.AfterFunc(time.Duration(delay)*time.Millisecond, func() {
  293. ts.dealGamePlay()
  294. })
  295. }
  296. func (ts *tablesink) startGame() {
  297. if ts.gameScene.Phase != Phase_Free && ts.gameScene.Phase != Phase_End {
  298. ts.table.LogWithTableId("tablesink.startGame ts.gameScene.Phase = %d faield", ts.gameScene.Phase)
  299. return
  300. }
  301. validChairs := []int{}
  302. for i := 0; i < CHAIR_COUNT; i++ {
  303. usr := ts.table.GetUserByChair(i)
  304. if usr == nil {
  305. continue
  306. }
  307. userStatus := usr.GetUserStatus()
  308. if userStatus <= user.UserStatus_Free ||
  309. userStatus == user.UserStatus_Watch {
  310. continue
  311. }
  312. if userStatus != user.UserStatus_Ready {
  313. ts.table.LogWithTableId("ts.startGame chair[%d] userStatue = %d", i, userStatus)
  314. return
  315. }
  316. if ts.table.GetUserChipOrGoldByUser(usr) < ts.roomInfo.BaseScore {
  317. //超过房间限制
  318. if usr.IsRobot() {
  319. go ts.table.KickUser(usr.GetUserIndex(), false)
  320. } else {
  321. go ts.table.UserWatch(usr.GetUserIndex())
  322. }
  323. continue
  324. }
  325. validChairs = append(validChairs, i)
  326. }
  327. if len(validChairs) <= 1 {
  328. ts.table.LogWithTableId("tablesink.startGame ready count = %d faield", len(validChairs))
  329. return
  330. }
  331. // 创建场景
  332. ts.gameScene.initData()
  333. ts.gameScene.base = ts.roomInfo.BaseScore
  334. for i := 0; i < CHAIR_COUNT; i++ {
  335. usr := ts.table.GetUserByChair(i)
  336. if usr == nil {
  337. continue
  338. }
  339. // 下底注
  340. b := ts.writeScore(usr.GetUserId(), -ts.roomInfo.BaseScore, 0, 0, ScoreType_Bet, ts.roomInfo.RoomName, usr.IsRobot())
  341. if !b {
  342. ts.table.LogWithTableId("tablesink.startGame %d 金币不足,站起", usr.GetUserId())
  343. //金币不足
  344. if usr.IsRobot() {
  345. go ts.table.KickUser(usr.GetUserIndex(), false)
  346. } else {
  347. go ts.table.UserWatch(usr.GetUserIndex())
  348. }
  349. continue
  350. }
  351. ts.gameScene.pool += ts.roomInfo.BaseScore
  352. ts.gameScene.Players[i].initData(i, usr.GetUserId(), ts.table.GetUserChipOrGoldByUser(usr))
  353. }
  354. if ts.gameScene.getPlayerCount() < 2 {
  355. ts.table.LogWithTableId("游戏开始,用户不足")
  356. ts.gameScene.Phase = Phase_End
  357. for i := 0; i < CHAIR_COUNT; i++ {
  358. if ts.gameScene.Players[i].IsValid {
  359. ts.writeScore(ts.gameScene.Players[i].userId, ts.roomInfo.BaseScore, 0, 0, ScoreType_Return, ts.roomInfo.RoomName, ts.isRobot(i))
  360. }
  361. }
  362. ts.endGame()
  363. return
  364. }
  365. //发送匹配结束
  366. ts.gameScene.Phase = Phase_Match
  367. ts.gameScene.WhoseTurn = validChairs[rand.Intn(len(validChairs))]
  368. ts.gameScene.LastTurn = -1
  369. tableId := ts.table.GetTableID()
  370. ts.table.LogWithTableId("tablesink.startGame Table[%d]", tableId)
  371. ts.table.SetTimer(TIMER_MATCH, SEC_MATCH)
  372. ts.table.KillTimer(TIMER_ROBOT)
  373. ts.gameScene.dump(tableId)
  374. ts.table.StartGame()
  375. }
  376. func (ts *tablesink) endGame() {
  377. ts.table.LogWithTableId("--------endGame-----------")
  378. ts.gameScene.dump(ts.table.GetTableID())
  379. // 先调用框架的EngGame,保证旁观用户状态改变
  380. ts.table.EndGame()
  381. realUserCount := 0
  382. robotCount := 0
  383. for i := 0; i < CHAIR_COUNT; i++ {
  384. usr := ts.table.GetUserByChair(i)
  385. if usr == nil {
  386. continue
  387. }
  388. if usr.GetUserStatus() == user.UserStatus_Watch {
  389. continue
  390. }
  391. // 机器人,随机1-2秒准备
  392. if !usr.IsRobot() {
  393. /*
  394. -- timer
  395. ts.readyTimer[i] = time.NewTimer(time.Duration(SEC_READY) * time.Millisecond)
  396. */
  397. ts.table.SetTimer(TIMER_READY_0+i, SEC_READY)
  398. realUserCount++
  399. } else {
  400. ts.table.SetTimer(TIMER_READY_0+i, 1000+rand.Intn(1000))
  401. /*
  402. -- timer
  403. ts.readyTimer[i] = time.NewTimer(time.Duration(3000+rand.Intn(3000)) * time.Millisecond)
  404. */
  405. robotCount++
  406. }
  407. }
  408. if realUserCount >= 2 && robotCount > 0 {
  409. //ts.removeOneRobot()
  410. ts.table.SetTimer(TIMER_REMOVE_ROBOT, 2000+rand.Intn(3000))
  411. }
  412. }
  413. //聊天
  414. func (ts *tablesink) recvChatMsg(userIndex int32, data string) {
  415. usr := ts.table.GetPlayer(userIndex)
  416. if usr == nil {
  417. ts.table.LogWithTableId("tablesink.recvChatMsg,usr[%d] not exist", userIndex)
  418. return
  419. }
  420. ts.table.SendGameData(-1, CMD_TABLECHAT, data)
  421. }
  422. //取消托管消息
  423. func (ts *tablesink) recvCancleAutoMsg(userIndex int32, data string) {
  424. usr := ts.table.GetPlayer(userIndex)
  425. if usr == nil {
  426. ts.table.LogWithTableId("tablesink.recvCancleAutoMsg,usr[%d] not exist", userIndex)
  427. return
  428. }
  429. chairId := usr.GetUserChairId()
  430. if chairId == -1 {
  431. return
  432. }
  433. ts.gameScene.Players[chairId].AutoOut = false
  434. // 重启倒计时
  435. if ts.gameScene.WhoseTurn != chairId {
  436. return
  437. }
  438. ts.table.KillTimer(TIMER_GAME)
  439. switch ts.gameScene.Phase {
  440. case Phase_Dice:
  441. ts.table.SetTimer(TIMER_GAME, ts.GetMoveSec())
  442. return
  443. case Phase_Move:
  444. ts.table.SetTimer(TIMER_GAME, ts.GetDiceSec())
  445. return
  446. }
  447. }
  448. //设置托管
  449. func (ts *tablesink) recvAutoMsg(userIndex int32, data string) {
  450. usr := ts.table.GetPlayer(userIndex)
  451. if usr == nil {
  452. ts.table.LogWithTableId("tablesink.recvAutoMsg,user[%d] not exist", userIndex)
  453. return
  454. }
  455. chairId := usr.GetUserChairId()
  456. if chairId == -1 {
  457. return
  458. }
  459. ts.gameScene.Players[chairId].AutoOut = true
  460. // 重启倒计时
  461. if ts.gameScene.WhoseTurn != chairId {
  462. return
  463. }
  464. switch ts.gameScene.Phase {
  465. case Phase_Dice:
  466. ts.table.SetTimer(TIMER_GAME, SEC_AUTO)
  467. return
  468. case Phase_Move:
  469. //移动棋子时间要长一些
  470. times := SEC_AUTO + SEC_DELAY
  471. ts.table.SetTimer(TIMER_GAME, times)
  472. return
  473. }
  474. }
  475. //操作掷骰子或者移动飞机
  476. func (ts *tablesink) recvAction(userIndex int32, data string) {
  477. if ts.gameScene.Phase != Phase_Dice && ts.gameScene.Phase != Phase_Move {
  478. ts.table.LogWithTableId("tablesink.recvAction,phase is wrong! %d ", ts.gameScene.Phase)
  479. return
  480. }
  481. usr := ts.table.GetPlayer(userIndex)
  482. if usr == nil {
  483. ts.table.LogWithTableId("tablesink.recvAction,usr[%d] not exist", userIndex)
  484. return
  485. }
  486. chairId := usr.GetUserChairId()
  487. if !isValidChair(chairId) {
  488. ts.table.LogWithTableId("tablesink.recvAction invalid chair %d", chairId)
  489. return
  490. }
  491. var action CmdAction
  492. err := json.Unmarshal([]byte(data), &action)
  493. if err != nil {
  494. ts.table.LogWithTableId("tablesink.recvAction,Unmarshal failed[%d] %s", userIndex, data)
  495. return
  496. }
  497. if action.Action == Action_Drop {
  498. ts.dealDrop(chairId)
  499. return
  500. }
  501. ts.doAction(chairId, action.Action, action.PlaneId, usr)
  502. }
  503. func (ts *tablesink) getDicePoint(chairId int, isRobot bool) int {
  504. number := 0
  505. round := ts.gameScene.Players[chairId].round
  506. hopeRound := ts.gameScene.Players[chairId].hopeRound
  507. hope := ts.gameScene.Players[chairId].hope
  508. if isRobot {
  509. //如果是机器人出点的时候 检查是否有可以攻击的对手
  510. rnd := rand.Intn(100)
  511. points := []int{1, 2, 3, 4, 5, 6}
  512. if rnd <= config.Rooms.GetParam1(ts.roomInfo.RoomID) {
  513. //检查前方是否有非机器人棋子
  514. for _, v := range ts.gameScene.Players[chairId].Planes {
  515. //没有出机场或者已经到终点和快到终点的过滤
  516. if v.Position == 0 || v.Position == MAX_STEP || v.Position >= 52 {
  517. continue
  518. }
  519. for _, p := range points {
  520. //可以攻击优先
  521. total, _, _ := ts.gameScene.checkPositionIsCrashed(chairId, v.Position+p, v.Id)
  522. if total == 1 {
  523. number = 6
  524. if p < 6 {
  525. number = p
  526. }
  527. if number == hope {
  528. ts.gameScene.Players[chairId].isShakeOutHope = true
  529. }
  530. //打印调试日志
  531. //ts.table.LogWithTableId("tablesink.getDicePoint-Robot Can Kill Chair[%d] PlaneId[%d] number[%d]", crashedPlayer.chairId, tempCrashed.Id, number)
  532. return number
  533. }
  534. }
  535. }
  536. }
  537. }
  538. //每过4轮检查一次期待点数
  539. if hopeRound%4 == 0 {
  540. if !ts.gameScene.Players[chairId].isShakeOutHope {
  541. //如果3轮内没有出过 则必出期待点
  542. number = hope
  543. ts.gameScene.Players[chairId].isShakeOutHope = true
  544. return number
  545. }
  546. ts.gameScene.Players[chairId].isShakeOutHope = false
  547. }
  548. //随机取
  549. number = ts.getRandomNumber(round)
  550. if isRobot && ts.IsDual() && number < 3 && ts.gameScene.checkIsBehind(chairId) {
  551. //从3,4,5,6中随机取一个
  552. number = rand.Intn(4) + 3
  553. }
  554. if number == hope {
  555. ts.gameScene.Players[chairId].isShakeOutHope = true
  556. }
  557. return number
  558. }
  559. func (ts *tablesink) doAction(chairId, action, planeId int, usr *user.UserInfo) {
  560. //是否是机器人的判断 不应该由用户上报的usr信息中获得,以及应该减少指针传递
  561. isRobot := ts.isRobot(chairId)
  562. number := 0
  563. if action == Action_Dice {
  564. ts.gameScene.Players[chairId].round++
  565. ts.gameScene.Players[chairId].hopeRound++
  566. number = ts.getDicePoint(chairId, isRobot)
  567. //ts.sendWinChat(usr.GetUserIndex(), usr.GetUserId(), 2000+rand.Intn(2000))
  568. }
  569. ok, errMsg, isNextChair, stepCount := ts.gameScene.addAction(chairId, action, number, planeId, isRobot)
  570. if !ok {
  571. if usr != nil {
  572. ts.table.SendGameData(usr.GetUserIndex(), CMD_ACTION, errMsg)
  573. }
  574. return
  575. }
  576. ts.table.KillTimer(TIMER_GAME)
  577. if ts.gameScene.Players[chairId].isWin() {
  578. ts.checkAndEndGame(chairId, stepCount)
  579. return
  580. }
  581. isCanMove := true
  582. moveDuration := 0
  583. if isNextChair {
  584. ts.gameScene.nextChair()
  585. //如果切换玩家并且前一个玩家是移动棋子则需要增加延迟
  586. if action == Action_Dice {
  587. isCanMove = false
  588. }
  589. }
  590. if action == Action_Move {
  591. ts.gameScene.Phase = Phase_Move
  592. moveDuration = stepCount * SEC_MOVE_TIME
  593. if ts.gameScene.ActionResult.CrashedChairId >= 0 && ts.gameScene.ActionResult.CrashedPlaneId >= 0 {
  594. //有攻击则增加时间
  595. moveDuration += SEC_DELAY
  596. }
  597. } else {
  598. ts.gameScene.Phase = Phase_Dice
  599. }
  600. ts.gameScene.Index++
  601. ts.table.NotifySceneChanged(-1)
  602. ts.resetGameTimer(isCanMove, isNextChair, moveDuration)
  603. }
  604. //重置游戏计时器
  605. func (ts *tablesink) resetGameTimer(isCanMove, isNextChair bool, moveDuration int) {
  606. ts.table.KillTimer(TIMER_GAME)
  607. ts.table.KillTimer(TIMER_ROBOT)
  608. if !isValidChair(ts.gameScene.WhoseTurn) {
  609. //log.Release("resetGameTimer ts.gameScene.WhoseTurn = %d", ts.gameScene.WhoseTurn)
  610. return
  611. }
  612. switch ts.gameScene.Phase {
  613. case Phase_Dice:
  614. if ts.gameScene.Players[ts.gameScene.WhoseTurn].AutoOut {
  615. times := SEC_AUTO
  616. if isNextChair && !isCanMove {
  617. //没有移动直接换人 加延迟
  618. times += SEC_NEXT_CHAIR
  619. } else if isCanMove {
  620. times = SEC_AUTO + SEC_DELAY
  621. }
  622. ts.table.SetTimer(TIMER_GAME, times)
  623. } else {
  624. //如果没有可以移动的则直接进入掷骰子阶段的定时间
  625. times := ts.GetDiceSec()
  626. if isNextChair && !isCanMove {
  627. //没有移动直接换人 加延迟
  628. times += SEC_NEXT_CHAIR
  629. } else if isCanMove {
  630. times = ts.GetMoveSec() + SEC_DELAY
  631. }
  632. ts.table.SetTimer(TIMER_GAME, times)
  633. }
  634. case Phase_Move:
  635. if ts.gameScene.WhoseTurn != -1 && ts.gameScene.Players[ts.gameScene.WhoseTurn].AutoOut {
  636. //移动棋子时间要长一些
  637. times := SEC_AUTO
  638. if isCanMove {
  639. times += moveDuration
  640. }
  641. ts.table.SetTimer(TIMER_GAME, times)
  642. } else {
  643. //前一个有移动的话 要算上移动的等待时间
  644. times := ts.GetDiceSec()
  645. if isCanMove {
  646. times += moveDuration
  647. }
  648. ts.table.SetTimer(TIMER_GAME, times)
  649. }
  650. }
  651. ts.table.SetTimer(TIMER_ROBOT, SEC_ROBOT_CHAT)
  652. ts.LastOpraTime = time.Now()
  653. ts.checkRobotAction(isCanMove, isNextChair, moveDuration)
  654. }
  655. func (ts *tablesink) checkAndEndGame(winner, stepCount int) {
  656. _, ended := ts.gameScene.addWinner(winner)
  657. if ended {
  658. // 结束了,把没写分的都写分
  659. for i := 0; i < CHAIR_COUNT; i++ {
  660. ts.writeChairScore(i)
  661. }
  662. ts.enterEndPhase()
  663. } else {
  664. // 没有结束,先写分
  665. ts.writeChairScore(winner)
  666. ts.table.SetUserEndGame(winner)
  667. ts.gameScene.Players[winner].IsValid = false
  668. ts.gameScene.Index++
  669. ts.gameScene.nextChair()
  670. ts.table.NotifySceneChanged(-1)
  671. //额外增加播放旗子动画
  672. moveDuration := stepCount*SEC_MOVE_TIME + SEC_DELAY*2
  673. ts.resetGameTimer(true, true, moveDuration)
  674. }
  675. }
  676. func (ts *tablesink) writeChairScore(chairId int) {
  677. if !ts.gameScene.Players[chairId].IsValid {
  678. return
  679. }
  680. if ts.gameScene.Players[chairId].writtenScore {
  681. return
  682. }
  683. player := &ts.gameScene.Players[chairId]
  684. if player.Dropped {
  685. return
  686. }
  687. score := ts.gameScene.Players[chairId].Score
  688. if score <= 0 {
  689. ts.gameScene.Players[chairId].Score = -ts.roomInfo.BaseScore
  690. ts.writeScore(player.userId, 0, 0, 1, ScoreType_End, ts.roomInfo.RoomName, ts.isRobot(chairId))
  691. go ts.table.WriteBetRecord(player.userId, ts.roomInfo.BaseScore, 0, 1.0, "lose", "lose", GAME_NAME)
  692. usr := ts.table.GetUserByChair(chairId)
  693. if usr != nil {
  694. go ts.table.RequestADAward(usr.GetUserIndex(), -ts.roomInfo.BaseScore)
  695. }
  696. return
  697. }
  698. tax := (score - ts.roomInfo.BaseScore) * ts.roomInfo.RoomInfoBase.TaxRate / 100
  699. ts.writeScore(player.userId, score-tax, tax, 1, ScoreType_End, ts.roomInfo.RoomName, ts.isRobot(chairId))
  700. go ts.table.WriteBetRecord(player.userId, ts.roomInfo.BaseScore, score-tax, 1.0, "win", fmt.Sprintf("win[%d]", player.Place), GAME_NAME)
  701. player.writtenScore = true
  702. }
  703. func (ts *tablesink) enterEndPhase() {
  704. ts.gameScene.Phase = Phase_End
  705. ts.gameScene.WhoseTurn = -1
  706. ts.gameScene.Index++
  707. ts.table.NotifySceneChanged(-1)
  708. ts.endGame()
  709. }
  710. func (ts *tablesink) writeScore(userId int, amount, tax int, status, scoreType int, sourceName string, isRobot bool) bool {
  711. if !isRobot {
  712. config.Rooms.AddWinAmount(ts.roomInfo.RoomID, -amount)
  713. }
  714. if config.Server.LoseTax > 0 && scoreType == ScoreType_End {
  715. if amount > 0 && tax > 0 {
  716. go coreservice.ModifyJackpot(tax/10, GAMEID, userId, GAME_NAME, config.Server.IsChipRoom > 0)
  717. tax = 0
  718. } else {
  719. // 如果是退出、放弃,则加税
  720. score := ts.gameScene.getScore(userId)
  721. if score < 0 {
  722. tax = int(math.Abs(float64(score))) * ts.roomInfo.RoomInfoBase.TaxRate / 100
  723. }
  724. }
  725. }
  726. ok, _ := ts.table.WriteUserMoney(userId, amount, tax, status, scoreType, sourceName)
  727. return ok
  728. }
  729. func (ts *tablesink) isRobot(chairId int) bool {
  730. usr := ts.table.GetUserByChair(chairId)
  731. if usr == nil {
  732. return false
  733. }
  734. return usr.IsRobot()
  735. }
  736. func (ts *tablesink) dealDrop(chairId int) bool {
  737. if !isValidChair(chairId) {
  738. ts.table.LogWithTableId("tablesink.dealDrop invalid ChairId %d", chairId)
  739. return false
  740. }
  741. if !ts.gameScene.Players[chairId].IsValid {
  742. ts.table.LogWithTableId("tablesink.dealDrop invalid ChairId2 %d", chairId)
  743. return false
  744. }
  745. if ts.gameScene.Players[chairId].Place > 0 {
  746. ts.table.LogWithTableId("tablesink.dealDrop Winning users cannot dropped %d", chairId)
  747. return false
  748. }
  749. if ts.gameScene.Players[chairId].Dropped {
  750. ts.table.LogWithTableId("tablesink.dealDrop already dropped %d", chairId)
  751. return false
  752. }
  753. ts.gameScene.Index++
  754. ts.gameScene.Players[chairId].drop()
  755. ts.gameScene.Players[chairId].LastAction = Action_Drop
  756. // 如果没人了,结算并写分
  757. validPlayerCount := 0
  758. winner := -1 //获胜者
  759. for i := 0; i < CHAIR_COUNT; i++ {
  760. if !ts.gameScene.Players[i].IsValid {
  761. continue
  762. }
  763. if ts.gameScene.Players[i].Dropped {
  764. continue
  765. }
  766. validPlayerCount++
  767. winner = i
  768. }
  769. usr := ts.table.GetUserByChair(chairId)
  770. ts.gameScene.Players[chairId].Score = -ts.roomInfo.BaseScore
  771. if ts.gameScene.Players[chairId].Score+ts.gameScene.Players[chairId].enterGold < 0 {
  772. ts.table.LogWithTableId("tablesink.dealDrop 分数不够扣 %d %d",
  773. ts.gameScene.Players[chairId].Score, ts.gameScene.Players[chairId].enterGold)
  774. ts.gameScene.Players[chairId].Score = -ts.gameScene.Players[chairId].enterGold
  775. }
  776. //逃跑也写分
  777. ts.writeScore(usr.GetUserId(), 0, 0, 1, ScoreType_End, ts.roomInfo.RoomName, ts.isRobot(chairId))
  778. go ts.table.WriteBetRecord(ts.gameScene.Players[chairId].userId, ts.roomInfo.BaseScore, 0, 1.0, "drop", "drop", GAME_NAME)
  779. if usr != nil {
  780. go ts.table.RequestADAward(usr.GetUserIndex(), -ts.roomInfo.BaseScore)
  781. }
  782. ts.table.SetUserEndGame(chairId)
  783. ts.broadcastDrop(chairId) //广播弃权消息滞后避免广播弃权消息时,用户已经退出
  784. if validPlayerCount <= 1 {
  785. ts.gameScene.LastTurn = chairId
  786. ts.checkAndEndGame(winner, 0)
  787. return true
  788. }
  789. // 其他人还能继续
  790. if ts.gameScene.WhoseTurn == chairId {
  791. ts.gameScene.nextChair()
  792. ts.resetGameTimer(true, true, 0)
  793. ts.table.NotifySceneChanged(-1)
  794. }
  795. return true
  796. }
  797. func (ts *tablesink) broadcastDrop(chairId int) {
  798. var cmd CmdDrop
  799. cmd.ChairId = chairId
  800. d, _ := json.Marshal(cmd)
  801. ts.table.SendGameData(-1, CMD_DROP, string(d))
  802. }