tablesink_impl.go 23 KB

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