table.js 135 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126
  1. 'use strict';
  2. var util = require('util');
  3. var quick = require('quick-pomelo');
  4. var P = quick.Promise;
  5. var cor = P.coroutine;
  6. var _ = require('lodash');/////是一个一致性、模块化、高性能的 JavaScript 实用工具库。
  7. //// 为什么选择 Lodash ?
  8. //// Lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。
  9. //// Lodash 的模块化方法 非常适用于:
  10. //// 遍历 array、object 和 string
  11. //// 对值进行操作和检测
  12. //// 创建符合功能的函数
  13. var uuid = require('node-uuid');
  14. var Logic = require('./logic');
  15. var User = require('./user');
  16. var Score = require('./score');
  17. var conf = require('../config/games').sxjiang || {};
  18. var M = require('../../share/message');
  19. var C = require('../../share/constant');
  20. var paiJuHuiFang = require('../../share/paiJuHuiFang');//////TL++ 牌局回放
  21. var configCommon = require('../../share/configCommon');//////TL++配置相关的公共方法
  22. var setReabte = require('../../share/setReabte');//////TL++记录返利相关的公共方法
  23. var logger = quick.logger.getLogger('fhmj', __filename);
  24. // 桌子状态
  25. var STATE = { FREE: 1, PLAYING: 2, FREE2: 3 , END: 4};//ts++REFREE 二次空闲 END结束
  26. // 结算模式
  27. var MODE = { NORMAL: 1, NOCARD: 2, OFFLINE: 3 };
  28. //ts++结束模式 空闲0,游戏中1, 正常结束3,房主解散3,断线解散4,断线解散5,系统解散6
  29. var ENDMODE = { FREE: 0,PLAYING: 1, OWNEREND: 2,NORMALEND: 3,REGEND: 4, OFFLINEEND: 5, SYSTEMEND: 6 };
  30. // 金币消耗
  31. const COSTS = conf.sit_costs || {};
  32. /////TL++,下面这几行为了记录用户行为
  33. // var log4js2 = require("log4js");////cssj
  34. // var log4js_config2 = require("./logConf.json");
  35. // log4js2.configure(log4js_config2);
  36. // var LogFile2 = log4js2.getLogger('log_file');////cssj
  37. // 构造方法
  38. var Table = function (cPlayerId,cUserId,cName,cHead,game, id, cell, round, type,gameKindTL,playerAllCount,upId,other,agentId,yxndlbTime,yxndlbTip) {
  39. let str3 = "table构造方法.......id: "+id + " type " + type+" game "+game.id;
  40. logger.warn(str3);////cssj
  41. this.app = game.app;
  42. this.gameId = 10007;
  43. this.game = game;
  44. this.id = id;
  45. this.recordid = uuid.v1()+'_'+id;//ts++唯一记录
  46. this.upId = upId;//ts++上局的ID
  47. this.type = type;
  48. this.agentId=agentId;
  49. this.yxndlbTime = yxndlbTime;
  50. this.yxndlbTip = yxndlbTip;
  51. var num_cost = 50;
  52. // if(gameKindTL == 2){
  53. // //num_cost = 50;//////冲刺扣50
  54. // num_cost =parseInt(COSTS[1]);
  55. // }
  56. // else
  57. // {
  58. num_cost =parseInt(COSTS[round]);
  59. // }
  60. this.other = other;//////TL++2人3人的游戏规则
  61. // console.warn("222创建房间的other",other,this.other," gameKindTL ",gameKindTL," type " ,type);
  62. this.jiangmaType = -1;////奖码类型:-1:不奖码,1:159奖码,2:摸几奖几,3:一码全中
  63. this.jiangmaCount = -1;////奖码张数
  64. if(this.other & 1){
  65. this.jiangmaType = 1;
  66. if(this.other & 8) this.jiangmaCount = 2;
  67. else if(this.other & 16) this.jiangmaCount = 4;
  68. else if(this.other & 32) this.jiangmaCount = 6;
  69. }
  70. else if(this.other & 2){
  71. this.jiangmaType = 2;
  72. this.jiangmaCount = 0;
  73. }
  74. else if(this.other & 4){
  75. this.jiangmaType = 3;
  76. this.jiangmaCount = 1;
  77. }
  78. this.hzCount = 0;/////红中个数
  79. if(this.other & 64) this.hzCount = 4;
  80. else if(this.other & 1024) this.hzCount = 6;
  81. else if(this.other & 2048) this.hzCount = 8;
  82. this.isQGHJM = false;/////是否抢杠胡奖码
  83. if(this.other & 128) this.isQGHJM = true;
  84. this.isHZHG = false;/////是否荒庄荒杠
  85. if(this.other & 256) this.isHZHG = true;
  86. this.isWGHZJYM = false;/////无红中胡加一码
  87. if(this.other & 512) this.isWGHZJYM = true;
  88. this.isZNZM = this.type == 2;/////是否只能自摸,拉杠情况可以胡
  89. // console.warn("奖码类型:-1:不奖码,1:159奖码,2:摸几奖几,3:一码全中 "+this.jiangmaType)
  90. // console.warn("奖码张数 "+this.jiangmaCount)
  91. // console.warn("红中个数 "+this.hzCount)
  92. // console.warn("是否抢杠胡奖码 "+this.isQGHJM)
  93. // console.warn("是否荒庄荒杠 "+this.isHZHG)
  94. // console.warn("无红中胡加一码 "+this.isWGHZJYM)
  95. // console.warn("是否只能自摸 "+this.isZNZM)
  96. this.cost = num_cost;
  97. this.over = 0;
  98. this.round = round;
  99. this.stime = 0;
  100. this.ctime = Date.now();
  101. this.etime = 0;
  102. this.lconfigCommon = null;
  103. // 人数
  104. this.ccount = playerAllCount;//Logic.CHAIR_COUNT;
  105. this.mcount = Logic.CARDS_COUNT;
  106. // 房主
  107. this.ownerChairId = -1;//房主的chairid
  108. this.ownerId = cPlayerId;//房主Id
  109. this.ownerUid = cUserId;//房主的userID
  110. this.ownerName = cName;
  111. this.ownerHeadUrl = cHead;
  112. // 数据
  113. var logic = new Logic(type,gameKindTL,playerAllCount,other);
  114. this.logic = logic;
  115. this.score = new Score(this);
  116. this.handCards = Array(this.ccount);
  117. this.huCards = logic.fillDeep(Array(this.ccount), []);
  118. this.users = Array(this.ccount);
  119. this.chBanker = 0;
  120. this.quFeng = 0;
  121. this.bankFlag = 0;
  122. this.outCards = logic.fillDeep(Array(this.ccount), []);
  123. // 标记
  124. this.isDihus = _.fill(Array(this.ccount), true);
  125. this.isTianhu = true;
  126. this.outCard = 0;
  127. this.outerId = -1;
  128. this.disCards = [];
  129. this.currentId = -1;
  130. // 包含字,总杠次,保留量
  131. // this.hasWords = !(type & 2);/////TL++zs
  132. // this.hasWords = true;/////是否含有字牌/////TL++
  133. this.gonCount = 0;
  134. // this.disCounts = [26, 14, 16, 26];/////TL++zs
  135. // this.disCounts = [1,1,1,1,];
  136. // 允许吃牌
  137. this.hasEat = false;//!!(type & 4);////是否可吃牌
  138. // 允许点炮
  139. this.hasEHu = true;///!!(type & 8);
  140. // 一炮多响
  141. this.isMHu = true;//!!(type & 16);
  142. // 允许杠胡
  143. this.hasGHu = true;///!!(type & 32);
  144. // 点炮出钱
  145. this.isWOne = true;//!!(type & 64);
  146. // 权限:16-胡,8-杠,4-碰,2-吃,1-等待,0-无
  147. this.masks = _.fill(Array(this.ccount), 0);
  148. this.excepts = logic.fillDeep(Array(this.ccount), {});
  149. // 等待杠类型,1-普通杠, 2-暗杠, 3-自摸明杠
  150. this.gangType = 0;
  151. this.gangCard = 0;
  152. // 抢杠胡、被杠玩家
  153. this.isGangHu = false;
  154. this.gangOuter = -1;
  155. // 等待吃类型,1-@**左吃, 2-*@*中吃, 3-@**右吃
  156. this._eatType = 0;
  157. this.autoOutTimer = null;
  158. this.everyIsAutoOut = _.fill(Array(this.ccount), 0);
  159. // 胡牌者
  160. this.anams = Array(this.ccount);
  161. this.huRes = Array(this.ccount);
  162. this.winner = { lead: -1, chs: [] };
  163. // 底分
  164. this.cell = cell;
  165. // 围观者
  166. this.lookers = [];
  167. //结束时的继线用户
  168. this.leaveUsers = [];
  169. // 状态
  170. this.state = STATE.FREE;
  171. // 申请结束标记
  172. this.overFlag = 0;
  173. this.overTimer = null;
  174. this.endTableTime = 60;//////TL++,申请解散房间之后60秒之后不操作则认为同意解散
  175. this.reqJieSan = [-1,-1,-1,-1];/////解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  176. //断线 结束定时器
  177. this.endTimer = null;
  178. //////以下全为TL++
  179. /////TL++,补花定时器,防止连续补花太快
  180. this.PJHF = new paiJuHuiFang();
  181. // this.buhuaTimeout = null;
  182. this.backStartTimer = null;//////重入之后系统会自动准备为了解决可能没牌的问题2秒之后才开始游戏
  183. this.PaijuHuiFang = [];////TL++,牌局回放
  184. // this.zhyzfgs = [-2,null,null];/////TL++,由于最后一张牌的摸牌被打断所以 用来记录最后一张牌的发牌函数的参数
  185. // this.isLianGang = [-1,false,-1];/////TL++,连杠的玩家座位号,是否连杠 杠的牌
  186. this.isYJJSGL = false;/////是否已经执行过结算函数了
  187. this.isYJKSGL = false;/////是否已经执行过开始函数了
  188. this.JSFJTimeout = null;//解散房间倒计时
  189. this.JSFJTime = 60;//解散房间倒计时60秒
  190. this.SQJSTime = null;//申请解散房间的时间,用于计算解散房间倒计时所剩的时间
  191. this.gameNeverStart = true;//游戏是否从未开始过,用于解散房间判断
  192. this.pjhffileName = [];//用于记录玩家牌局回放的json文件名
  193. this.playerPosList = [[],[],[],[]];//记录玩家的位置信息数组
  194. this.gameKindTL = gameKindTL || 1;//平搓还是冲刺 = 1代表平搓 = 2代表冲刺
  195. this.playerAllCount = playerAllCount || 4;//游戏人数 = 2表示2人局 = 3表示3人局 = 4表示4人局
  196. this.isNeverStart = true;//游戏是否从未开始
  197. this.sszjDataList = [];//设置实时战绩的数据
  198. this.isEveryZZ = false;//是否每一个人都做过庄
  199. // this.isZJYG = false;////本局庄家是否有杠
  200. this.chairArry = [0,1,2,3];//
  201. // this.isNeverTounchHU = false;/////是否从未点击过胡按钮
  202. this.sszjs = [];//ts++实时战绩
  203. this.LWKF = [10,10,10,10,10];//////TL++礼物扣费
  204. this.isGameOk=false;//ts++牌局正常结束
  205. this.agentRebate=0;//ts++本局的返利
  206. // delete require.cache[require.resolve('../../share/setReabte')];
  207. // setReabte = require('../../share/setReabte');
  208. this.lsetReabte = new setReabte(this.app);
  209. };
  210. // 导出状态
  211. Table.STATE = STATE;
  212. //ts++ 结束模式
  213. Table.ENDMODE = ENDMODE;
  214. // 导出类
  215. module.exports = Table;
  216. // 原型对象
  217. var proto = Table.prototype;
  218. // 是否站满
  219. proto.isFull = function () {
  220. return (this.lookers.length >= 5);
  221. };
  222. // 是否准备
  223. proto.isReady = function () {
  224. for (let user of this.users) {
  225. if (!user || !user.isReady()) return false;
  226. }
  227. return true;
  228. };
  229. // ts++是否二次准备
  230. proto.isReady2 = function () {
  231. for (let user of this.users) {
  232. if (!user || !user.isReady2()) return false;
  233. }
  234. return true;
  235. };
  236. // 是否游戏中
  237. proto.isPlaying = function () {
  238. return this.state > STATE.FREE;
  239. };
  240. // 是否全在线
  241. proto.isOnline = function () {
  242. for (let user of this.users) {
  243. if (user && user.isOffline()) return false;
  244. }
  245. return true;
  246. };
  247. // 是否全断线
  248. proto.isOffline = function () {
  249. for (let user of this.users) {
  250. if (!user || !user.isOffline()) return false;
  251. }
  252. return true;
  253. };
  254. // 是否空桌
  255. proto.isEmpty = function () {
  256. if (this.lookers.length > 0) return false;
  257. for (let i = 0; i < this.users.length; ++i) {
  258. if (this.users[i]) return false;
  259. }
  260. return true;
  261. };
  262. // 局数完成
  263. proto.isGameOver = function () {
  264. let str3 = "table 局数完成 .......id: "+ this.id + " this.over " + this.over;
  265. logger.warn(str3);////cssj
  266. return (this.over >= this.round);
  267. };
  268. // 重置本局
  269. proto.resetRound = function () {
  270. _.fill(this.handCards, null);
  271. _.fill(this.isDihus, true);
  272. this.isTianhu = true;
  273. _.fill(this.masks, 0);
  274. if(this.autoOutTimer)
  275. {
  276. clearTimeout(this.autoOutTimer);
  277. this.autoOutTimer = null;
  278. }
  279. this.everyIsAutoOut = _.fill(Array(this.ccount), 0);
  280. this.logic.fillDeep(this.excepts, {});
  281. _.fill(this.huRes, null);
  282. this.gonCount = 0;
  283. this.winner.chs = [];
  284. this.winner.lead = -1;
  285. this.logic.fillDeep(this.huCards, []);
  286. this.logic.fillDeep(this.outCards, []);
  287. this.outCard = 0;
  288. this.outerId = -1;
  289. this.currentId = -1;
  290. this._eatType = 0;
  291. this.gangType = 0;
  292. this.gangCard = 0;
  293. this.isGangHu = false;
  294. this.gangOuter = -1;
  295. };
  296. // 发送消息
  297. proto.pushMsgAsync = cor(function* (cidOrIds, route, msg) {
  298. // console.warn("444WWWWWWWTTTTTT",cidOrIds, route, msg);
  299. var playerIds = [];
  300. if (Array.isArray(cidOrIds)) playerIds = cidOrIds;
  301. else {
  302. if (cidOrIds < 0 || cidOrIds >= this.users.length) {
  303. for (let user of this.users) {
  304. if (user) playerIds.push(user.id);
  305. }
  306. for (let lker of this.lookers) {
  307. playerIds.push(lker.id);
  308. }
  309. } else {
  310. let user = this.users[cidOrIds];
  311. if (user) playerIds.push(user.id);
  312. // console.warn("555WWWWWWWTTTTTT",cidOrIds, route, user.name);
  313. }
  314. }
  315. if (playerIds.length > 0) {
  316. let channelId = 'xct:' + this.id;
  317. // console.warn("666WWWWWWWTTTTTT",cidOrIds, route, playerIds,msg);
  318. return this.app.controllers.push._pushAsync(channelId, playerIds, route, msg);
  319. }
  320. });
  321. // 围观消息
  322. proto.lookMsgAsync = cor(function* (route, msg) {
  323. var playerIds = [];
  324. for (let lker of this.lookers) {
  325. playerIds.push(lker.id);
  326. }
  327. if (playerIds.length > 0) {
  328. let channelId = 'xct:' + this.id;
  329. return this.app.controllers.push._pushAsync(channelId, playerIds, route, msg);
  330. }
  331. });
  332. // 获得桌子信息
  333. proto.getTableInfo = function () {
  334. // 桌子信息
  335. let endTableTime = Math.floor((this.SQJSTime - Date.now())/1000);
  336. var tableInfo = {
  337. id: this.id,
  338. gameId: this.gameId,
  339. type: this.type,
  340. cost: this.cost,
  341. over: this.over,
  342. round: this.round,
  343. users: [],
  344. lookers: [],
  345. ownerId: -1,//this.ownerChairid
  346. ownerUserId: this.ownerUid,////TL++,房主的userID
  347. ownerName: this.ownerName,//////TL++,房主的昵称
  348. ownerHeadUrl: this.ownerHeadUrl,//////TL++,房主的头像地址
  349. gameKindTL: this.gameKindTL,////平搓还是冲刺 = 1代表平搓 = 2代表冲刺
  350. playerAllCount: this.playerAllCount,////游戏人数 = 2表示2人局 = 3表示3人局 = 4表示4人局
  351. other: this.other,
  352. creatTime : this.ctime,
  353. nowTime : Date.now(),
  354. state: this.state,
  355. sszjDataList: this.sszjDataList,////TL++,设置实时战绩的数据
  356. isZHYZ: this.logic.isZHYZ, /////TL++,是否最后一张
  357. playerPosList: this.playerPosList,/////TL++玩家位置数据
  358. chairArry: this.chairArry,/////TL++
  359. isNeverStart: this.isNeverStart,/////TL++,游戏是否从未开始
  360. overFlag:this.overFlag,//ts++房间解散标识
  361. endTableTime:endTableTime,
  362. recordid:this.recordid,
  363. yxndlbTime:this.yxndlbTime,
  364. yxndlbTip:this.yxndlbTip,
  365. reqJieSan:this.reqJieSan
  366. };
  367. // 正在游戏
  368. var isPlaying = this.isPlaying();
  369. if (isPlaying) {
  370. tableInfo.qFeng = this.quFeng;
  371. tableInfo.banker = this.chBanker;
  372. tableInfo.stime = Date.now() - this.stime;
  373. tableInfo.currentId = this.currentId;
  374. tableInfo.disCards = this.disCards;
  375. tableInfo.lastCount = this.logic.leaveCount();
  376. tableInfo.isGangHu = this.isGangHu;
  377. tableInfo.gangCard = this.gangCard;
  378. //////TL++,游戏过程中重入
  379. tableInfo.baiDaCard = String(this.logic.baiDaCard);//////TL++,本局百搭牌
  380. tableInfo.everyFllowerCardList = [[],[],[],[]]; /////每个人手上的花牌
  381. //////TL++ end,游戏过程中重入
  382. }
  383. // 桌上玩家
  384. for (let i = 0; i < this.users.length; ++i) {
  385. let user = this.users[i];
  386. if (user) {
  387. let score = this.score.getScore(user.id);
  388. let uinfo = {
  389. account: user.account, name: user.name, sex: user.sex, headurl: user.headurl,
  390. state: user.state2, score: score, chairId: user.chairId
  391. };
  392. if (isPlaying) {
  393. let huCards = [];
  394. for (let huCard of this.huCards[i]) {
  395. huCards.push({ style: huCard.style, type: huCard.type, card: huCard.cards[0], origin: huCard.origin });
  396. }
  397. uinfo.huCards = huCards;
  398. uinfo.outCards = this.outCards[i];
  399. let handCard = this.handCards[i] || [];
  400. uinfo.handCount = handCard.length;
  401. }
  402. tableInfo.users.push(uinfo);
  403. }
  404. }
  405. // 围观玩家
  406. for (let i = 0; i < this.lookers.length; ++i) {
  407. let user = this.lookers[i];
  408. if (user) {
  409. tableInfo.lookers.push({ account: user.account, name: user.name, sex: user.sex, headurl: user.headurl });
  410. }
  411. }
  412. return tableInfo;
  413. };
  414. // 回到桌子
  415. proto.backAsync = cor(function* (user) {
  416. let str3 = "table回到桌子.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  417. logger.warn(str3);////cssj
  418. user.offlinetime=0;//ts++
  419. var data = { chairId: String(user.chairId) };
  420. var chairId = user.chairId;
  421. let isGuoHuList = [[false,0],[false,0],[false,0],[false,0],];
  422. if (chairId != -1) {
  423. // 加入频道
  424. var connectorId = user.connectorId || '';
  425. if (connectorId) {
  426. let channelId = 'xct:' + this.id;
  427. yield this.app.controllers.push._joinAsync(channelId, user.id, connectorId);
  428. }
  429. // 恢复状态
  430. if (this.state == STATE.FREE) {
  431. yield this.readyGameAsync(user);
  432. } else if (this.state == STATE.PLAYING) {
  433. //user.state = User.STATE.PLAYING;//ts--
  434. user.state2 = User.STATE.PLAYING;//ts++
  435. data.mask = String(this.masks[chairId]);
  436. data.handCards = this.handCards[chairId];
  437. // 状态通知
  438. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  439. }else if (this.state == STATE.FREE2) {//ts++二次准备
  440. //user.state = User.STATE.PLAYING;//ts--
  441. user.state2 = User.STATE.READY;
  442. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  443. if (this.isReady2() && !this.isGameOk)
  444. {
  445. if(!this.backStartTimer){
  446. this.backStartTimer = this.app.timer.setTimeout(() => this.backStartTimeAsync(), 2 * 1000);//延迟2秒开始游戏
  447. }
  448. }
  449. }
  450. // 取消计时
  451. if (this.isOnline() && this.endTimer) {
  452. clearTimeout(this.endTimer);
  453. this.endTimer = null;
  454. }
  455. isGuoHuList[chairId] = this.logic.isGuoHuList[chairId];
  456. }
  457. // 数据处理
  458. data.fee = this.score.isFeed(user.id) ? '0' : '1';
  459. data.table = this.getTableInfo();
  460. let hutipdata = {
  461. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  462. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  463. };
  464. if(chairId == this.currentId){
  465. let tipres = this.logic.hutip(this.currentId,this.handCards[this.currentId],this.huCards[this.currentId],this.huCards,this.outCards);////重入时调用胡牌提示
  466. data.table.hutipdata = tipres;
  467. }
  468. else{
  469. data.table.hutipdata = hutipdata;
  470. }
  471. let isAutoOut = 0;
  472. if (chairId != -1) {
  473. isAutoOut = this.everyIsAutoOut[chairId];
  474. }
  475. data.table.isAutoOut = isAutoOut;
  476. data.table.isGuoHuList = isGuoHuList;
  477. return { code: C.OK, data: data };
  478. });
  479. //ts++重入后自动开始
  480. proto.backStartTimeAsync = cor(function* () {
  481. yield this.startGameAsync();
  482. });
  483. // 加入桌子
  484. proto.joinAsync = cor(function* (user) {
  485. // 撤出删除队列
  486. //this.game.cancelDelete(this.id);
  487. // 加入桌子之前
  488. yield this.beforeJoinAsync(user);
  489. // 加入围观者
  490. this.lookers.push(user);
  491. // 加入桌子之后
  492. yield this.afterJoinAsync(user);
  493. // 数据返回处理
  494. var data = { chairId: String(user.chairId) };
  495. data.fee = this.score.isFeed(user.id) ? '0' : '1';
  496. data.table = this.getTableInfo();
  497. return { code: C.OK, data: data };
  498. });
  499. // 加入桌子之前
  500. proto.beforeJoinAsync = cor(function* (user) {
  501. var connectorId = user.connectorId || '';
  502. if (connectorId) {
  503. let channelId = 'xct:' + this.id;
  504. return this.app.controllers.push._joinAsync(channelId, user.id, connectorId);
  505. }
  506. });
  507. // 加入桌子之后
  508. proto.afterJoinAsync = cor(function* (user) {
  509. // 加入通知
  510. return this.pushMsgAsync(-1, 'sxjiang_event', {
  511. type: M.JOIN, data: { account: user.account, userId: user.userId, name: user.name, sex: user.sex, headurl: user.headurl,playerPosList: this.playerPosList }
  512. });
  513. });
  514. // 坐下桌子
  515. proto.seatAsync = cor(function* (user, chairId) {
  516. // let chairId = this.chairArry[_chairId];
  517. // console.warn("坐下桌子不不vvvvvv",chairId,_chairId,this.chairArry,this.users.length);
  518. // 参数校验
  519. if (chairId < 0 || chairId >= this.ccount) {
  520. return { code: C.FAILD, msg: C.CHAIR_NOT_FOUND };
  521. }
  522. if (this.users[chairId]) {
  523. // console.warn("坐下桌子死了vv000",this.users[chairId]);
  524. // console.warn("坐下桌子死了vvvvvv",this.users.length,this.users);
  525. return { code: C.FAILD, msg: C.CHAIR_HAS_SOMEONE };
  526. }
  527. // 查找玩家
  528. var player = yield this.app.models.Player.findByIdAsync(user.id, 'diamond cost');
  529. if (!player) {
  530. return { code: C.FAILD, msg: C.PLAYER_NOT_FOUND };
  531. }
  532. if (this.users[chairId]) {
  533. return { code: C.FAILD, msg: C.CHAIR_HAS_SOMEONE };
  534. }
  535. // 调换座位
  536. if (user.chairId != -1) {
  537. return this.changeChairAsync(user, chairId);
  538. }
  539. // 围观玩家
  540. var pos = _.findIndex(this.lookers, (u) => (u.id == user.id));
  541. if (pos == -1) {
  542. return { code: C.FAILD, msg: C.TABLE_NOT_USER };
  543. }
  544. //ts++
  545. let dSource=player.diamond;
  546. let dNow=player.diamond;
  547. //坐下花费
  548. var costdata = null;
  549. if (!this.score.isFeed(user.id)) {
  550. if (player.diamond < this.cost) {
  551. return { code: C.FAILD, msg: C.GAME_DIAMOND_LOW };
  552. }//////TL++zsyl 1000局测完之后要放出来的
  553. player.diamond -= this.cost;
  554. player.cost = (player.cost || 0) + this.cost;
  555. dNow-=this.cost;
  556. this.score.addUser(user.id,chairId,user.userId, user.name, user.sex, user.headurl,user.diamond,this.gameKindTL);
  557. costdata = { cost: String(this.cost) };
  558. }
  559. // 坐下处理
  560. this.lookers.splice(pos, 1);
  561. this.users[chairId] = user;
  562. user.chairId = chairId;
  563. user.state = User.STATE.READY;
  564. yield this.afterSeatAsync(user);
  565. if (player.isModified())
  566. {
  567. yield player.saveAsync();/////只有第一次坐下的时候才会执行
  568. // 钻石记录
  569. var diamondrecord = new this.app.models.DiamondRecord({
  570. _id: uuid.v1(),
  571. playerId: user.id,
  572. dType: 3,//坐下
  573. dSource: dSource,
  574. dSwap: -1*this.cost,
  575. dNow: dNow,
  576. tableId: this.recordid
  577. });
  578. yield diamondrecord.saveAsync();
  579. // console.warn("ts++坐下-------------------钻石记录");
  580. if (costdata) yield this.pushMsgAsync(chairId, 'sxjiang_event', { type: M.COST_FEE, data: costdata });
  581. }
  582. // if (this.isReady()) yield this.pushMsgAsync(this.ownerChairid, 'sxjiang_event', { type: M.START_BUTTON });//////TL++zsyl所有人准备之后通知房主点击开始游戏
  583. if (this.state == STATE.FREE && this.isReady() && !this.isGameOk) {
  584. yield this.randomChangeChairTL();
  585. }
  586. return { code: C.OK, chairId: String(chairId) };
  587. });
  588. // 调换座位 自己坐下之后点击另外一个位子的时候调用这个方法 这个参数user输出之后相当的长
  589. proto.changeChairAsync = cor(function* (user, chairId) {
  590. if (this.state != STATE.FREE) {
  591. return { code: C.FAILD, msg: C.TABLE_NOT_FREE };
  592. }
  593. if (this.users[chairId]) {
  594. return { code: C.FAILD, msg: C.CHAIR_HAS_SOMEONE };
  595. }
  596. // var _chairId = user.chairId;
  597. // delete this.users[_chairId];
  598. // this.users[chairId] = user;
  599. // user.chairId = chairId;
  600. // user.state = User.STATE.READY;
  601. // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.CHAIR_CHANGE, data: { oldId: String(_chairId), newId: String(chairId), state: String(user.state), state2: String(user.state2) } });
  602. // // if (this.ownerChairid == _chairId) {
  603. // // this.ownerChairid = chairId;
  604. // // // 换房主通知
  605. // // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.OWNER_CHANGE, data: { ownerChairid: String(this.ownerChairid) } });
  606. // // }
  607. return { code: C.OK, chairId: String(chairId) };
  608. });
  609. // 坐下桌子之后
  610. proto.afterSeatAsync = cor(function* (user) {
  611. let posListTL = {
  612. chairId: user.chairId,
  613. headurl: user.headurl,
  614. longitude: user.longitude, // 经度,浮点数,范围为180 ~ -180。
  615. latitude: user.latitude, // 纬度,浮点数,范围为90 ~ -90
  616. }
  617. this.playerPosList[user.chairId] = posListTL/////TL++记录玩家的位置信息数组
  618. // 坐下通知
  619. let score = this.score.getScore(user.id);
  620. yield this.pushMsgAsync(-1, 'sxjiang_event', {///////发送坐下
  621. type: M.SEAT, data: {
  622. account: user.account,
  623. name: user.name,
  624. sex: user.sex,
  625. headurl: user.headurl,
  626. state: String(user.state),
  627. score: String(score),
  628. chairId: String(user.chairId),
  629. userId: String(user.userId),
  630. playerPosList: this.playerPosList, /////TL++记录玩家的位置信息数组
  631. }
  632. });
  633. });
  634. //////TL++,在首次游戏开始的时候随机打乱用户的座位
  635. proto.randomChangeChairTL = cor(function* () {
  636. // console.warn("111在首次游戏开始的时候随机打乱用户的座位",this.users[0].name,this.users[1].name,this.users[2].name,this.users[3].name);
  637. // console.warn("1在首次游戏开始的时候随机打乱用户的座位",this.users[0].chairId,this.users[1].chairId,this.users[2].chairId,this.users[3].chairId);
  638. if(this.playerAllCount > 2){
  639. let changeResult = [];
  640. if (this.over <= 0) {///////本房间开始的第一局游戏
  641. // for (let i = 0; i < this.ccount; i++) {/////这种随机4次可能会导致4次随机之后和打乱之前的顺序一样所以弃用
  642. for (let i = 0; i < 1; i++) {
  643. let oldchaieID = i;
  644. let olduser = this.users[i];
  645. let newchaieID = Math.floor(Math.random()*this.playerAllCount);////// 区间[0,3]取整数
  646. while (newchaieID == oldchaieID) {
  647. newchaieID = Math.floor(Math.random()*this.playerAllCount);////// 区间[0,3]取整数
  648. }
  649. let newuser = this.users[newchaieID];
  650. // console.warn("222在首次游戏开始的时候随机打乱用户的座位",oldchaieID,newchaieID);
  651. // console.warn("xxxxxxxxx删除有没有用啊",this.users.length);
  652. delete this.users[newchaieID];
  653. delete this.users[oldchaieID];
  654. // console.warn("xxxxxxxxx22删除有没有用啊",this.users.length);
  655. this.users[newchaieID] = olduser;
  656. this.users[newchaieID].chairId = newchaieID;
  657. // this.users[newchaieID].id = newuser.id;
  658. this.users[oldchaieID] = newuser;
  659. this.users[oldchaieID].chairId = oldchaieID;
  660. // this.users[oldchaieID].id = olduser.id;
  661. changeResult.push([oldchaieID,newchaieID])
  662. }
  663. // console.warn("333在首次游戏开始的时候随机打乱用户的座位",this.users[0].name,this.users[1].name,this.users[2].name,this.users[3].name);
  664. // console.warn("3在首次游戏开始的时候随机打乱用户的座位",this.users[0].chairId,this.users[1].chairId,this.users[2].chairId,this.users[3].chairId);
  665. // console.warn("3在首次游戏开始的时候随机打乱用户的座位",this.users[0].id,this.users[1].id,this.users[2].id,this.users[3].id);
  666. // console.warn("3在首次游戏开始的",this.users[0]);
  667. ////// this.users 发送给前端会代码报错
  668. // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.CHAIR_DALUAN, data: { changeResult:changeResult } });
  669. /////TL++
  670. for (let i = 0; i < this.users.length; ++i) {
  671. this.score.setUserChair(this.users[i].id,this.users[i].chairId)
  672. }
  673. let daluanData = [];
  674. var isPlaying = this.isPlaying();
  675. for (let i = 0; i < this.users.length; ++i) {
  676. let user = this.users[i];
  677. if (user) {
  678. let score = this.score.getScore(user.id);
  679. let uinfo = {
  680. account: user.account, name: user.name, sex: user.sex, headurl: user.headurl,
  681. state: user.state, score: score, chairId: user.chairId
  682. };
  683. if (isPlaying) {
  684. let huCards = [];
  685. for (let huCard of this.huCards[i]) {
  686. huCards.push({ style: huCard.style, type: huCard.type, card: huCard.cards[0], origin: huCard.origin });
  687. }
  688. uinfo.huCards = huCards;
  689. uinfo.outCards = this.outCards[i];
  690. let handCard = this.handCards[i] || [];
  691. uinfo.handCount = handCard.length;
  692. }
  693. daluanData.push(uinfo);
  694. }
  695. }
  696. // this.score.delUser(user.id);
  697. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.CHAIR_DALUAN, data: { daluanData:daluanData } });
  698. }
  699. }
  700. // console.warn("444在首次游戏开始的时候随机打乱用户的座位",changeResult);
  701. // this.starTimer = this.app.timer.setTimeout(() => this.startGameAsync(), 500);
  702. yield this.startGameAsync()/////TL++,在首次游戏的时候随机打乱用户的座位
  703. });
  704. // 站起桌子
  705. proto.standAsync = cor(function* (user) {
  706. let str3 = "table 站起桌子.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  707. logger.warn(str3);////cssj
  708. var chairId = user.chairId;
  709. if (chairId != -1) {
  710. user.state = User.STATE.FREE;
  711. delete this.users[chairId];
  712. delete this.handCards[chairId];
  713. user.chairId = -1;
  714. this.lookers.push(user);
  715. yield this.afterStandAsync(user, chairId);
  716. }
  717. return { code: C.OK };
  718. });
  719. // 站起桌子之后
  720. proto.afterStandAsync = cor(function* (user, chairId) {
  721. // 站起通知
  722. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.STAND, data: { chairId: String(chairId) } });
  723. //if (this.ownerChairid == -1) this.ownerChairid = -1;//////TL++,房主坐下之后重置房主chairid
  724. /////TL++,作坐下的玩家离开桌子之后将他的位置信息从位置列表里面删除
  725. if(chairId != -1) this.playerPosList[chairId] = [];
  726. // 桌主离开
  727. //////TL++zsyl,原先的这个逻辑是房主站起之后会切换房主
  728. // if (chairId == this.ownerChairid) {
  729. // let newCid = _.findIndex(this.users, (user) => user);
  730. // this.ownerChairid = newCid;
  731. // if (newCid != -1) this.ownerUid = this.users[newCid].id;
  732. // // 换房主通知
  733. // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.OWNER_CHANGE, data: { ownerChairid: String(this.ownerChairid) } });
  734. // }
  735. //是否退费
  736. // console.warn("ts++++++++站起桌子之后");
  737. var scorer = this.score.getUser(user.id);
  738. if (scorer && scorer.over <= 0) {
  739. // console.warn("ts++没有开始游戏退分",user.id);
  740. this.score.delUser(user.id);
  741. let player = yield this.app.models.Player.findByIdAsync(user.id, 'diamond cost');
  742. if (player) {
  743. // console.warn("ts++没有开始游戏退分",player.diamond);
  744. let dSource=player.diamond;
  745. let dNow=player.diamond+this.cost;
  746. player.diamond += this.cost;
  747. player.cost -= this.cost;
  748. yield player.saveAsync();
  749. //return this.app.controllers.player.pushAsync(user.id, 'sxjiang_event', { type: M.BACK_FEE, data: { back: String(this.cost) } });
  750. // 退费 钻石记录
  751. var diamondrecord = new this.app.models.DiamondRecord({
  752. _id: uuid.v1(),
  753. playerId: user.id,
  754. dType: 4,//退费
  755. dSource: dSource,
  756. dSwap: this.cost,
  757. dNow: dNow,
  758. tableId: this.recordid
  759. });
  760. yield diamondrecord.saveAsync();
  761. // console.warn("ts++退分-------------------钻石记录");
  762. //var costdata = { cost: String(-1*this.cost) };
  763. //if (costdata) yield this.pushMsgAsync(chairId, 'sxjiang_event', { type: M.COST_FEE, data: costdata });
  764. }
  765. }
  766. else
  767. {
  768. if(user.cost==0 && user.spreadId)//ts++推荐人奖励
  769. {
  770. // let spreader = yield this.app.models.Player.findByIdAsync(user.spreadId, 'spreadCount spreadRebate');
  771. // if (spreader) {
  772. // spreader.spreadCount += 1;
  773. // spreader.spreadRebate += 100;
  774. // yield spreader.saveAsync();
  775. // }
  776. ////20200928因为现在的spreadId存的是userId,所以上面那段用不了了
  777. if(!this.lconfigCommon) {
  778. // console.warn("邀请新人送钻石活动 this.lconfigCommon 不存在 "+this.etime);
  779. this.lconfigCommon = new configCommon(this.app);
  780. }
  781. let yxhdxx = this.lconfigCommon.getActiveOpenTime(1);//邀请新人送钻石活动是否开启和开始结束时间的信息
  782. let isKQ = false;//邀请新人送钻石活动是否开启
  783. if(yxhdxx && yxhdxx.open && yxhdxx.startTime && yxhdxx.endTime) isKQ = true;
  784. // console.warn("获取配置信息 yxhdxx "+JSON.stringify(yxhdxx));
  785. if(isKQ && this.etime >= yxhdxx.startTime && this.etime < yxhdxx.endTime){
  786. var cpopts = {};
  787. cpopts['userId'] = parseInt(user.spreadId);
  788. let spreadList = yield this.app.models.Player.findMongoAsync(cpopts, 'spreadCount spreadRebate', { sort: { stime: 1 } });//
  789. if(spreadList.length == 1){
  790. spreadList[0].spreadCount += 1;
  791. spreadList[0].spreadRebate += 100;
  792. yield spreadList[0].saveAsync();
  793. }
  794. }
  795. }
  796. yield this.lsetReabte.updateDaterebateRecord(this.agentId,this.etime);
  797. // if(this.agentId) //正常结束的才能算
  798. // {
  799. // if(this.agentRebate>0)
  800. // {
  801. // //console.warn("代理返利写分+++++");
  802. // let gameCost2=this.agentRebate;//游戏消耗
  803. // let agentRebate2=parseInt(this.agentRebate*this.rEBATERATE);
  804. // this.agentRebate=0;
  805. // var today = new Date();
  806. // today.setHours(0);
  807. // today.setMinutes(0);
  808. // today.setSeconds(0);
  809. // today.setMilliseconds(0);
  810. // let nowverifyDate=today.getTime();
  811. // var agenter = yield this.app.models.Agenter.findByIdAsync(this.agentId,'rebateOther rebateCount rebateAll rebateNow rebateOut verifyDate verifyRebate agentRate');
  812. // if (agenter)
  813. // {
  814. // //日结算
  815. // let verifyBool=false;
  816. // let verifyDate=0;
  817. // let verifyRebate=0;
  818. // //日奖励
  819. // let dateAgentRate=0;
  820. // let dateRebate=0;
  821. // if(agenter.verifyRebate>0 && agenter.verifyDate!=nowverifyDate)
  822. // {
  823. // verifyBool=true;
  824. // verifyDate=agenter.verifyDate;
  825. // verifyRebate=agenter.verifyRebate;
  826. // dateAgentRate=agenter.agentRate;
  827. // agenter.rebateNow += verifyRebate;
  828. // agenter.rebateNow += dateRebate;
  829. // agenter.rebateOther += dateRebate;
  830. // agenter.rebateCount += dateRebate;
  831. // agenter.verifyRebate=0;
  832. // }
  833. // //修改代理数据
  834. // agenter.rebateCount += agentRebate2;
  835. // agenter.rebateAll += agentRebate2;
  836. // agenter.verifyDate=nowverifyDate;
  837. // agenter.verifyRebate+= agentRebate2;
  838. // let rCount=agenter.rebateCount;
  839. // let rOther=agenter.rebateOther;
  840. // let rAll=agenter.rebateAll;
  841. // let rNow=agenter.rebateNow;
  842. // let rOut=agenter.rebateOut;
  843. // let rVerifyDate=agenter.verifyDate;
  844. // let rVerifyRebate=agenter.verifyRebate;
  845. // yield agenter.saveAsync();
  846. // // console.warn("代理返利写分+++++agenter.saveAsync()");
  847. // // 锁定返利记录
  848. // if(verifyBool && verifyRebate>0)
  849. // {
  850. // var verifyrebateRecord = new this.app.models.RebateRecord({
  851. // _id: uuid.v1(),
  852. // agentId:this.agentId,
  853. // tableId: '',
  854. // rType: 3,
  855. // rCount: rCount- agentRebate2,
  856. // rOther: rOther,
  857. // rAll: rAll- agentRebate2,
  858. // rNow: rNow,
  859. // rOut: rOut,
  860. // rSwap: verifyRebate,
  861. // rDateSwap: dateRebate,
  862. // rVerifyDate: verifyDate,
  863. // rVerifyRebate: 0
  864. // });
  865. // yield verifyrebateRecord.saveAsync();
  866. // var daterebateRecord = new this.app.models.DateRebateRecord({
  867. // _id: uuid.v1(),
  868. // agentId:this.agentId,
  869. // verifyDate: verifyDate,
  870. // verifyRebate: verifyRebate,
  871. // dateAgentRate: dateAgentRate,
  872. // dateRebate: dateRebate
  873. // });
  874. // yield daterebateRecord.saveAsync();
  875. // }
  876. // // 返利记录
  877. // var rebateRecord = new this.app.models.RebateRecord({
  878. // _id: uuid.v1(),
  879. // agentId:this.agentId,
  880. // tableId: this.recordid,
  881. // rType: 1,
  882. // rCount: rCount,
  883. // rOther: rOther,
  884. // rAll: rAll,
  885. // rNow: rNow,
  886. // rOut: rOut,
  887. // rSwap: agentRebate2,
  888. // rDateSwap: 0,
  889. // rVerifyDate: rVerifyDate,
  890. // rVerifyRebate: rVerifyRebate
  891. // });
  892. // yield rebateRecord.saveAsync();
  893. // // console.warn("返利记录+++++rebateRecord.saveAsync()");
  894. // }
  895. // }
  896. // let gameRebate=0;
  897. // if(this.isGameOk)
  898. // {
  899. // gameRebate=parseInt(this.cost*this.rEBATERATE);
  900. // }
  901. // var today = new Date();
  902. // today.setHours(0);
  903. // today.setMinutes(0);
  904. // today.setSeconds(0);
  905. // today.setMilliseconds(0);
  906. // let date=today.getTime();
  907. // let countid=this.agentId+'-'+user.userId+'-'+date;
  908. // var playercount = yield this.app.models.PlayerCount.findByIdAsync(countid,'gameCount gameCost agentRebate time');
  909. // if (playercount)
  910. // {
  911. // playercount.gameCount+=1;
  912. // playercount.gameCost+=this.cost;
  913. // playercount.agentRebate+=gameRebate;
  914. // playercount.time=Date.now();
  915. // }
  916. // else
  917. // {
  918. // playercount = new this.app.models.PlayerCount({
  919. // _id: countid,
  920. // agentId:this.agentId,
  921. // playerId: user.id,
  922. // userId: user.userId,
  923. // name: user.name,
  924. // date: date,
  925. // gameCount: 1,
  926. // gameCost: this.cost,
  927. // agentRebate: gameRebate,
  928. // time:Date.now()
  929. // });
  930. // }
  931. // yield playercount.saveAsync();
  932. // }
  933. // console.warn("活动奖励 下面开始进行判断 ",user.spreadId,user.registerTime,user.lastLoginTime);
  934. // let str11 = "hdjl xmksjxpd "+ this.id + " isGameOk: " + this.isGameOk + " userId: " + user.userId + " spreadId: " + user.spreadId + " registerTime: " + user.registerTime + " lastLoginTime: " + user.lastLoginTime ;
  935. // logger.warn(str11);////cssj
  936. // if(this.isGameOk && this.ccount == 4 && user.spreadId)//活动奖励
  937. // {
  938. // // console.warn("活动奖励 至此是游戏正常结束而且玩家有推荐id",user.spreadId,user.registerTime,user.lastLoginTime);
  939. // ////正常结束而且该玩家有推荐人id
  940. // let acSTime = 1601481600000;////20201001零点的时间戳,活动开始时间
  941. // let acETime = acSTime + 86400000*8;////20201008这天截止的时间戳 活动结束时间
  942. // let xzsjc = Date.now();
  943. // let str12 = "hdjl zcyxszcjseqwjytjr "+this.id + " userId: " + user.userId +" xzsjc: "+xzsjc;
  944. // logger.warn(str12);////cssj
  945. // if(xzsjc >= acSTime && xzsjc < acETime){
  946. // if((user.registerTime >= acSTime && user.registerTime < acETime) || user.lastLoginTime < 1598889600000){
  947. // // console.warn("活动奖励 至此该玩家是新用户",user.spreadId,user.registerTime,user.lastLoginTime);
  948. // let str13 = "hdjl zcgwjsxyh "+this.id + " userId: " + user.userId;
  949. // logger.warn(str13);////cssj
  950. // ////活动期间注册或者9月1号10月1日之间未登陆过的玩家
  951. // var todayTL = new Date();
  952. // todayTL.setHours(0);
  953. // todayTL.setMinutes(0);
  954. // todayTL.setSeconds(0);
  955. // todayTL.setMilliseconds(0);
  956. // let jrldsjc=todayTL.getTime();////今日零点时间戳
  957. // let jrjssjc=jrldsjc + 86400000;////今日结束时间戳
  958. // var opts = { stime: { $gte: jrldsjc, $lt: jrjssjc },type: { $gte: 1, $lt: 2 }};
  959. // opts['sid'] = user.id;
  960. // let acrlist = yield this.app.models.ActiveRewardRecord.findMongoAsync(opts, '_id rewardtype totalfee type sid rid gameCount stime succtime succState', { sort: { stime: 1 } });//
  961. // if(acrlist.length == 0){
  962. // // console.warn("活动奖励 活动期间今日该玩家产生新的记录",user.spreadId,user.registerTime,user.lastLoginTime);
  963. // let str14 = "hdjl hdqjjrgwjcsxdjl "+this.id + " userId: " + user.userId;
  964. // logger.warn(str14);////cssj
  965. // ////活动期间今日该玩家产生新的记录
  966. // var activerewardrec = new this.app.models.ActiveRewardRecord({
  967. // _id: uuid.v1(), // UUID
  968. // rewardtype: 0, // 奖励类型,0红包
  969. // totalfee: 0, // 产生金额,红包为分
  970. // type:1, //活动类型:1国庆签到2国庆邀请
  971. // sid: user.id, // 产生奖励的玩家id
  972. // sname:user.name, // 产生奖励的玩家name
  973. // suid:user.userId, // 产生奖励的玩家userId
  974. // rid: user.id, // 此条奖励的受益玩家
  975. // gameCount: 1, // 游戏局数
  976. // stime: xzsjc, // 记录产生时间
  977. // succtime: 0, // 任务完成时间,任务未完成的时候这里是0
  978. // succState: 0 // 任务是否完成的状态,0:未完成1:已达成
  979. // });
  980. // yield activerewardrec.saveAsync();
  981. // }
  982. // else{
  983. // let str15 = "hdjl hdqjjrgwjyjcsgjl "+this.id + " userId: " + user.userId;
  984. // logger.warn(str15);////cssj
  985. // ////活动期间更新今日该玩家已经产生的记录
  986. // let newre = acrlist[0];
  987. // newre.gameCount++;
  988. // if(newre.gameCount >= 2){
  989. // // console.warn("活动奖励 活动期间更新今日该玩家已经产生的记录",user.spreadId,user.registerTime,user.lastLoginTime);
  990. // let str16 = "hdjl hdqjgxjrgwjyjcsdjl "+this.id + " userId: " + user.userId + " gameCount: " + newre.gameCount;
  991. // logger.warn(str16);////cssj
  992. // ////完成为解散2局,该玩家完成了签到的任务了
  993. // if(newre.gameCount == 2){
  994. // newre.totalfee = 500;
  995. // newre.succtime = xzsjc;
  996. // newre.succState = 1;
  997. // }
  998. // yield newre.saveAsync();
  999. // }
  1000. // if(newre.gameCount == 2){
  1001. // var opts2 = { stime: { $gte: acSTime, $lt: acETime },type: { $gte: 2, $lt: 3 }};
  1002. // opts2['sid'] = user.id;
  1003. // let acrlist2 = yield this.app.models.ActiveRewardRecord.findMongoAsync(opts2, 'rid', { sort: { stime: 1 } });//
  1004. // let isneedcj = false;////是否需要创建邀请奖励产生记录
  1005. // if(acrlist2.length == 0){
  1006. // isneedcj = true;
  1007. // // if(parseInt(acrlist2[0].rid) && parseInt(acrlist2[0].rid) == user.spreadId) isneedcj = true;
  1008. // }
  1009. // // console.warn("活动奖励 完成未解散2局,该玩家的推荐人完成了邀请的任务了",user.spreadId,user.registerTime,user.lastLoginTime);
  1010. // let str17 = "hdjl csgwjdyqjl "+this.id + " userId: " + user.userId + " isneedcj: " + isneedcj;
  1011. // logger.warn(str17);////cssj
  1012. // if(isneedcj){
  1013. // ////完成为解散2局,该玩家的推荐人完成了邀请的任务了
  1014. // var activerewardrec = new this.app.models.ActiveRewardRecord({
  1015. // _id: uuid.v1(), // UUID
  1016. // rewardtype: 0, // 奖励类型,0红包
  1017. // totalfee: 500, // 产生金额,红包为分
  1018. // type:2, //活动类型:1国庆签到2国庆邀请
  1019. // sid: user.id, // 产生奖励的玩家id
  1020. // suid:user.userId, // 产生奖励的玩家userId
  1021. // sname:user.name, // 产生奖励的玩家name
  1022. // rid: user.spreadId,// 此条奖励的受益玩家
  1023. // gameCount: newre.gameCount, // 游戏局数
  1024. // stime: xzsjc, // 记录产生时间
  1025. // succtime: xzsjc, // 任务完成时间,任务未完成的时候这里是0
  1026. // succState: 1 // 任务是否完成的状态,0:未完成1:已达成
  1027. // });
  1028. // yield activerewardrec.saveAsync();
  1029. // }
  1030. // }
  1031. // }
  1032. // }
  1033. // }
  1034. // }
  1035. // let str4 = "table 222 站起桌子之后---id:%s"+this.id + " uid"+user.userId+" "+ this.state;
  1036. // logger.info(str4);////cssj
  1037. }
  1038. });
  1039. // 玩家断线
  1040. proto.offlineAsync = cor(function* (user) {
  1041. let str3 = "table 玩家断线.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  1042. logger.warn(str3);////cssj
  1043. if (user.chairId != -1) {
  1044. //user.state = User.STATE.OFFLINE;//ts--
  1045. user.state2 = User.STATE.OFFLINE;//ts++
  1046. user.offlinetime = Date.now();//ts++断线
  1047. var channelId = 'xct:' + this.id;
  1048. yield this.app.controllers.push._quitAsync(channelId, user.id);
  1049. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  1050. // 无人在线
  1051. // console.warn("提前结算666");
  1052. //if (this.isOffline()) return this.overTimeAsync(MODE.OFFLINE);
  1053. // console.warn("玩家断线-------定时器启动");
  1054. // 计时结算
  1055. if (!this.endTimer) this.endTimer = this.app.timer.setTimeout(() => this.overTimeAsync(ENDMODE.OFFLINEEND),600000);/////断线10分钟自动结算
  1056. // let str4 = "table 玩家断线---id:"+this.id + ",uid"+user.userId+" "+ this.state;
  1057. // logger.info(str4);////cssj
  1058. }
  1059. });
  1060. // 离开桌子
  1061. proto.leaveAsync = cor(function* (user) {
  1062. let str3 = "table 离开桌子.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  1063. logger.warn(str3);////cssj
  1064. // this.leavePlayerID = user.id;//////TL++,旁观为房主的话离开之后由于从观战者列表里面删除了,导致发消息的时候他收不到离开桌子的消息
  1065. // console.warn("离开桌子、、、、、、、");
  1066. yield this.beforeLeaveAsync(user);
  1067. var chairId = user.chairId;
  1068. // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.LEAVE, data: { account: user.account } });/////TL++zs,原来在下面
  1069. if (chairId != -1) {
  1070. delete this.users[chairId];
  1071. delete this.handCards[chairId];
  1072. yield this.afterStandAsync(user, chairId);
  1073. } else {
  1074. let pos = _.findIndex(this.lookers, (u) => (u.id == user.id));
  1075. if (pos != -1) this.lookers.splice(pos, 1);
  1076. }
  1077. return this.afterLeaveAsync(user);
  1078. });
  1079. // 离开桌子之前
  1080. proto.beforeLeaveAsync = cor(function* (user) {
  1081. var channelId = 'xct:' + this.id;
  1082. return this.app.controllers.push._quitAsync(channelId, user.id);
  1083. });
  1084. // 离开桌子之后
  1085. proto.afterLeaveAsync = cor(function* (user) {
  1086. // 离开通知
  1087. /////TL++zsyl 在此之前离开玩家已经从玩家列表或者旁观者列表中删除了所以把下面这句提到前面去了
  1088. return this.pushMsgAsync(-1, 'sxjiang_event', { type: M.LEAVE, data: { account: user.account } });
  1089. });
  1090. // 玩家准备
  1091. proto.readyGameAsync = cor(function* (user) {
  1092. let str3 = "table 玩家准备.......id: "+ this.id + " user.chairId: " + user.chairId + " this.over: " + this.over + " user.name: " + user.name ;
  1093. logger.warn(str3);////cssj
  1094. // let str3 = "table 玩家准备---id:"+this.id + ",uid"+user.userId+","+ this.state;
  1095. // logger.info(str3);////cssj
  1096. if(this.state==STATE.FREE2)//ts++二次空闲
  1097. {
  1098. user.state2 = User.STATE.READY;
  1099. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  1100. if (this.isReady2() && !this.isGameOk) yield this.startGameAsync();
  1101. }
  1102. else
  1103. {
  1104. user.state = User.STATE.READY;
  1105. user.state2 = User.STATE.READY;
  1106. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  1107. // console.warn("玩家准备玩家准备玩家准备 ",this.isReady() ,this.isGameOver());
  1108. if (this.isReady() && !this.isGameOk) yield this.startGameAsync();
  1109. }
  1110. // let str4 = "table 222玩家准备---id:"+this.id + ",uid"+user.userId+","+ this.state;
  1111. // logger.info(str4);////cssj
  1112. return { code: C.OK };
  1113. });
  1114. // 开始游戏
  1115. proto.startGameAsync = cor(function* () {
  1116. //this.backStartTimer = null;//////重入之后系统会自动准备为了解决可能没牌的问题2秒之后才开始游戏
  1117. let str4 = "table 开始游戏---id:"+this.id +" ,state "+ this.state +" 当前局 "+ (this.over+1);
  1118. logger.warn(str4);////cssj
  1119. if(this.isYJKSGL){
  1120. return;
  1121. }
  1122. this.isYJKSGL = true;/////是否已经执行过开始函数了
  1123. this.isYJJSGL = false;/////是否已经执行过结算函数了
  1124. if(this.backStartTimer)
  1125. {
  1126. clearTimeout(this.backStartTimer);
  1127. this.backStartTimer = null;
  1128. }
  1129. // 状态设置
  1130. this.state = STATE.PLAYING;
  1131. //this.setUserState(-1, User.STATE.PLAYING);//ts--
  1132. //ts++设置为游戏状态
  1133. for (let user of this.users)
  1134. {
  1135. if (user) {
  1136. if(user.state == User.STATE.PLAYING)//ts++已经开始
  1137. {
  1138. if(user.state2 == User.STATE.READY)
  1139. {
  1140. user.state2 = User.STATE.PLAYING
  1141. user.offlinetime = 0;
  1142. }
  1143. }
  1144. else//ts++第一次开始
  1145. {
  1146. user.state = User.STATE.PLAYING
  1147. user.state2 = User.STATE.PLAYING
  1148. user.offlinetime = 0;
  1149. }
  1150. }
  1151. }
  1152. //ts++end
  1153. let whdata = yield this.app.models.WHstate.findByIdReadOnlyAsync('wh', 'rebaterate yxndlbTime yxndlbTip');
  1154. // console.warn("22检查是否维护状态",whdata);
  1155. if (whdata) {
  1156. if(whdata.yxndlbTime) this.yxndlbTime = whdata.yxndlbTime;
  1157. if(whdata.yxndlbTip) this.yxndlbTip = whdata.yxndlbTip;
  1158. }
  1159. this.PaijuHuiFang = [];////TL++,牌局回放 重置数据
  1160. this.lgkhCount = 0;/////TL++拉杠可胡玩家的数量
  1161. this.logic.isZHYZ = false;/////是不是最后1张
  1162. // this.logic.isNeedBuHua = false/////TL++在游戏开始的时候初始化是否需要补花
  1163. // this.isLianGang = [-1,false,-1];/////TL++,连杠的玩家座位号,是否连杠 在游戏开始的时候清空
  1164. // 初始信息
  1165. if (this.over <= 0) {///////本房间开始的第一局游戏
  1166. this.stime = Date.now();
  1167. // this.chBanker = this.ownerChairid;///////TL++zsyl
  1168. this.chBanker = 0;
  1169. //this.game.cancelDelete(this.id);//////TL++游戏第一次开始时候关闭房间20分钟未开始删除桌子
  1170. this.pjhffileName[this.pjhffileName.length] = this.PJHF.getjsonFileName(0,this.recordid,this.ctime);/////TL++,用于记录玩家牌局回放的json文件名
  1171. // console.error("000HHHHHHHHHHHHHHHHHHHHHH",this.pjhffileName.length,this.pjhffileName);
  1172. this.PJHF.writePJHFJson(this.getTableInfo(),0,this.id);////在开始第一局的时候将桌子信息写入本地的json文件
  1173. this.isNeverStart = false;/////TL++,游戏是否从未开始
  1174. // yield this.randomChangeChairTL()/////TL++,在首次游戏的时候随机打乱用户的座位
  1175. }
  1176. this.gameNeverStart = false;/////TL++,游戏是否从未开始过,用于解散房间判断
  1177. this.currentId = this.chBanker;
  1178. this.isDihus[this.chBanker] = false;
  1179. // 发手牌 把这句提前是为了洗牌之后能拿到百搭牌在游戏开始的时候给客户端发过去
  1180. let dice1 = this.logic.dice();/////骰子1的点数
  1181. let dice2 = this.logic.dice();/////骰子2的点数
  1182. var handCards = this.logic.handCards(this.chBanker,this.PJHF,this.over,this.recordid,this.ctime);
  1183. if(this.playerAllCount == 4){
  1184. if(this.chBanker == 0) this.logic.isMZWF = [0,1,2,3];/////是不是满足位风
  1185. else if(this.chBanker == 1) this.logic.isMZWF = [3,0,1,2];/////是不是满足位风
  1186. else if(this.chBanker == 2) this.logic.isMZWF = [2,3,0,1];/////是不是满足位风
  1187. else if(this.chBanker == 3) this.logic.isMZWF = [1,2,3,0];/////是不是满足位风
  1188. }
  1189. // }
  1190. else if(this.playerAllCount == 3){
  1191. if(this.chBanker == 0) this.logic.isMZWF = [0,1,2,8];/////是不是满足位风
  1192. else if(this.chBanker == 1) this.logic.isMZWF = [3,0,1,8];/////是不是满足位风
  1193. else if(this.chBanker == 2) this.logic.isMZWF = [2,3,0,8];/////是不是满足位风
  1194. }
  1195. else if(this.playerAllCount == 2){
  1196. if(this.chBanker == 0) this.logic.isMZWF = [0,2,8,8];/////是不是满足位风
  1197. else if(this.chBanker == 1) this.logic.isMZWF = [2,0,8,8];/////是不是满足位风
  1198. }
  1199. //console.warn("ccccccccccccccccccccc当局的圈风",this.logic.fengQuan,this.chBanker);
  1200. let scoreListTL = []
  1201. for (let i = 0; i < this.users.length; ++i) {
  1202. let user = this.users[i];
  1203. if (user) {
  1204. let score = this.score.getScore(user.id);
  1205. scoreListTL[i] = score
  1206. }
  1207. }
  1208. // 掷骰子
  1209. var sttGame = {
  1210. banker: String(this.chBanker),
  1211. qFeng: String(this.quFeng),
  1212. stime: String(Date.now() - this.stime),
  1213. baiDaCard: String(this.logic.baiDaCard),//////TL++,本局百搭牌
  1214. startNum1: String(dice1),////骰子点数
  1215. startNum2: String(dice2),////骰子点数
  1216. setCardFileName: String(this.logic.setCardFileName),////TL++设置手牌的文件名
  1217. scoreListTL:scoreListTL,/////TL++,每个玩家当前的分数列表
  1218. yxndlbTime:this.yxndlbTime,
  1219. yxndlbTip:this.yxndlbTip,
  1220. };
  1221. // console.warn("游侠开始*******************this.chBanker",this.chBanker);
  1222. this.setPaijuHuiFangData(M.START_GAME,sttGame);/////TL++ 牌局回放 push游戏开始
  1223. // 开始通知
  1224. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.START_GAME, data: sttGame });
  1225. ////// 发手牌原来在这里
  1226. var lastCount = this.logic.leaveCount();/////TL++
  1227. for (let i = 0; i < handCards.length; ++i) {
  1228. this.handCards[i] = handCards[i].cards;/////TL++zsyl
  1229. if (i == this.chBanker) {
  1230. let __isHu = false;
  1231. let length = this.handCards[i].length;
  1232. this.logic.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡
  1233. // this.logic.chengBaoTL = [[],[],[],[]];
  1234. // console.error("sscc3333胡牌分析 游戏开始i",i);
  1235. let huRes = this.logic.huAnalyze(i,this.handCards[i], this.handCards[i][length - 1], this.huCards[i], true);
  1236. // console.error("ssccDDD胡牌分析 huRes",huRes);
  1237. if (huRes) {
  1238. // let str3a = "table fpphcg:"+this.id + ",uid"+this.handCards[i];
  1239. // logger.info(str3a);////cssj
  1240. __isHu = true;
  1241. this.huRes[i] = huRes;
  1242. }
  1243. let res = this.logic.anGangAnalyze(this.handCards[i]);
  1244. let isGang = (res.length > 0);
  1245. if (isGang) this.masks[i] |= 8;
  1246. if (__isHu) this.masks[i] |= 16;
  1247. }
  1248. let scards = {
  1249. mask: String(this.masks[i]),
  1250. cards: handCards[i].cards,
  1251. lastCount: String(lastCount)
  1252. };
  1253. ////发牌的胡牌提示
  1254. if (i == this.chBanker) {
  1255. ////游戏开始时候的庄家的胡牌提示
  1256. scards.hutipdata = this.logic.hutip(this.chBanker,handCards[i].cards,this.huCards[i],this.huCards,this.outCards);////起手发牌调用胡牌提示
  1257. }
  1258. else{
  1259. ////游戏开始时候的闲家的胡牌提示
  1260. scards.hutipdata = {
  1261. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  1262. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  1263. };
  1264. }
  1265. // 发牌通知
  1266. // console.error("sscc发牌通知 4条应该=================",i,handCards.lengt);
  1267. yield this.pushMsgAsync(i, 'sxjiang_event', { type: M.SEND_CARD, data: scards });
  1268. }
  1269. let pjhfsplist = {
  1270. shouPai:this.logic.deepCloneTL(this.handCards),
  1271. maskList:this.logic.deepCloneTL(this.masks),/////TL++,10月28号,为了实现能看到每个玩家的操作
  1272. lastCount:String(this.logic.leaveCount())
  1273. }
  1274. this.setPaijuHuiFangData(M.SEND_CARD,pjhfsplist);/////TL++ 牌局回放 push发牌数据
  1275. // 围观通知
  1276. var cardCounts = _.fill(Array(this.ccount), 0);
  1277. for (let i = 0; i < cardCounts.length; ++i) {
  1278. cardCounts[i] = this.handCards[i].length;
  1279. }
  1280. yield this.lookMsgAsync('sxjiang_event', { type: M.SEND_CARD, data: { cardCounts: cardCounts, lastCount: String(lastCount) } });
  1281. let str3 = "table 222开始游戏---id:"+this.id +","+ this.state;
  1282. logger.warn(str3);////cssj
  1283. return { code: C.OK };
  1284. });
  1285. // 出牌
  1286. proto.outCardAsync = cor(function* (chairId, card) {
  1287. let str3 = "table 出牌---id:"+this.id + " ,uid "+chairId+" this.masks "+ this.masks +" card "+card;
  1288. logger.warn(str3);////cssj
  1289. // console.warn("出牌出剖出牌",chairId,this.buhuaTimeout);///// 您正在补花,请稍后出牌。/////TL++,正在补花的时候不允许玩家出牌
  1290. // if(this.buhuaTimeout) return { code: C.FAILD, msg: C.GAME_BUHUA_ING };
  1291. // 校验顺序
  1292. if (this.currentId != chairId) {
  1293. return { code: C.FAILD, msg: C.TABLE_TURN_ERROR };
  1294. }
  1295. if(this.autoOutTimer)
  1296. {
  1297. clearTimeout(this.autoOutTimer);
  1298. this.autoOutTimer = null;
  1299. }
  1300. this.logic.chuPaiTL()////TL++,统计出牌个数,为了判断天胡和地胡
  1301. // 吃椪杠胡
  1302. var pos = _.findIndex(this.masks, (m, i) => (i != chairId && m > 0));
  1303. if (pos != -1) {
  1304. return { code: C.FAILD, msg: C.TABLE_TURN_ERROR };
  1305. }
  1306. // 删除手牌
  1307. if (!this.logic.remove(this.handCards[chairId], card)) {
  1308. return { code: C.FAILD, msg: C.TABLE_CARD_ERROR };
  1309. }
  1310. if (this.masks[chairId] & 16){
  1311. this.logic.isGuoHuList[chairId][0] = true;/////TL++,设置过胡玩家的是否点击过胡为true 出牌
  1312. let guohudataTL = {
  1313. chairId:chairId,
  1314. msg: "下次摸牌之前将不能胡牌", /////过胡通知
  1315. }
  1316. let isGuoHuList = [[false,0],[false,0],[false,0],[false,0],];
  1317. isGuoHuList[chairId] = this.logic.isGuoHuList[chairId];
  1318. guohudataTL.isGuoHuList = isGuoHuList;
  1319. ////过胡通知
  1320. yield this.pushMsgAsync(chairId, 'sxjiang_event', { type: M.FHGUOHUTIP, data: guohudataTL });
  1321. this.logic.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡
  1322. }
  1323. // 置空权限
  1324. if (this.masks[chairId] > 0) this.masks[chairId] = 0;
  1325. // 置灰的牌
  1326. this.disCards = [];
  1327. // 调整手牌
  1328. this.logic.adjust(this.handCards[chairId]);
  1329. this.outCard = card;
  1330. this.outerId = chairId;
  1331. this.outCards[chairId].push(card);
  1332. // 天胡地胡
  1333. if (this.isTianhu) this.isTianhu = false;
  1334. if (this.isDihus[chairId]) this.isDihus[chairId] = false;
  1335. // 忽略牌
  1336. this.excepts[chairId] = {};
  1337. let sfyrkh = false;//////TL++,是否有人可胡,没有的话海底捞月之后直接结算
  1338. let pjhfsplist = {};
  1339. // 吃碰杠胡
  1340. for (let i = 0; i < this.ccount; ++i) {
  1341. let ocard = { chairId: String(chairId), card: String(card) };
  1342. // 排除自己
  1343. if (i != chairId) {
  1344. ocard.isGuoHuList = [[false,0],[false,0],[false,0],[false,0],]
  1345. let _isChi = false;
  1346. let isPeng = false;
  1347. let isGang = false;
  1348. let __isHu = false;
  1349. do {
  1350. // 检测吃牌
  1351. if (this.hasEat && i == (chairId + 1) % this.ccount && (!this.isZNZM)) {//// 以前是否可吃为可选项 只能自摸情况下不能吃
  1352. let ress = this.logic.chiAnalyze(this.handCards[i], card);
  1353. _isChi = (ress.length > 0);
  1354. }
  1355. // 忽略牌
  1356. if (this.excepts[i][card]) break;/////TL++zsyl.同一圈过碰之后不能再次碰的
  1357. // 检测碰牌
  1358. isPeng = this.logic.isPeng(this.handCards[i], card);
  1359. // 忽略牌
  1360. // if (this.excepts[i][card]) break;/////TL++.为了解决同一圈过碰之后不能再次碰的问题
  1361. let res = this.logic.gangAnalyze(this.handCards[i], card);
  1362. isGang = !!res;
  1363. this.logic.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡
  1364. let huRes = (!this.isZNZM) ? this.logic.huAnalyze(i,this.handCards[i], card, this.huCards[i]) : undefined;
  1365. // console.error("ssccAAA胡牌分析 huRes",huRes);
  1366. if (huRes) {
  1367. // let str3a = "table cpphcg:"+this.id + ",uid"+this.handCards[i];
  1368. // logger.info(str3a);////cssj
  1369. __isHu = true;
  1370. this.huRes[i] = huRes;
  1371. }
  1372. } while (0);
  1373. /////TL++,整个if
  1374. if(this.logic.leaveCount() == 0 && this.logic.isZHYZ){
  1375. if (_isChi) _isChi = false;
  1376. if (isPeng) isPeng = false;
  1377. if (isGang) isGang = false;
  1378. if(__isHu) sfyrkh = true
  1379. }
  1380. // 权限掩码
  1381. if (_isChi) this.masks[i] |= 2;
  1382. if (isPeng) this.masks[i] |= 4;
  1383. if (isGang) this.masks[i] |= 8;
  1384. if (__isHu) this.masks[i] |= 16;
  1385. }
  1386. else{
  1387. let isGuoHuList = [[false,0],[false,0],[false,0],[false,0],];
  1388. isGuoHuList[chairId] = this.logic.isGuoHuList[chairId];
  1389. ocard.isGuoHuList = isGuoHuList;
  1390. }
  1391. ocard.mask = String(this.masks[i]);
  1392. // 出牌通知
  1393. yield this.pushMsgAsync(i, 'sxjiang_event', { type: M.OUT_CARD, data: ocard });
  1394. if (i == chairId) {
  1395. // let pjhfcp = ocard
  1396. // pjhfcp.allMask = this.masks;
  1397. pjhfsplist = {
  1398. shouPai:this.logic.deepCloneTL(this.handCards),
  1399. lastCount:String(this.logic.leaveCount()),
  1400. ocard:this.logic.deepCloneTL(ocard),
  1401. outCards:this.logic.deepCloneTL(this.outCards),
  1402. isGuoHuList:this.logic.deepCloneTL(this.logic.isGuoHuList)
  1403. }
  1404. }
  1405. if(i == (this.ccount - 1)){/////TL++if条件判断,10月28号,为了实现能看到每个玩家的操作
  1406. pjhfsplist.maskList = this.logic.deepCloneTL(this.masks);/////TL++,10月28号,为了实现能看到每个玩家的操作
  1407. this.setPaijuHuiFangData(M.OUT_CARD,pjhfsplist);/////TL++ 牌局回放 push出牌数据
  1408. }
  1409. }
  1410. // 被杠玩家
  1411. this.gangOuter = -1;
  1412. // 围观通知
  1413. yield this.lookMsgAsync('sxjiang_event', { type: M.OUT_CARD, data: { chairId: String(chairId), card: String(card) } });
  1414. // 全无权限
  1415. for (let i = 0; i < this.ccount; ++i) {
  1416. if (this.masks[i] != 0) break;
  1417. // 切换用户
  1418. if (i == this.ccount - 1) {
  1419. // 下家摸牌
  1420. let nextId = (chairId + 1) % this.ccount;
  1421. ///////TL++,整个if,因为海底捞月需要玩家自己去判断要不要摸牌
  1422. // console.warn("000 声剩余声剩余声剩");
  1423. let lastCount = this.logic.leaveCount();/////TL++xg
  1424. this.touchCardAsync(nextId); ///////出牌摸牌
  1425. }
  1426. }
  1427. let str4 = "table end出牌---id:"+this.id + " ,uid "+chairId+" this.masks "+ this.masks +" card "+card;
  1428. logger.warn(str4);////cssj
  1429. return { code: C.OK };
  1430. });
  1431. proto.autoOutCard = cor(function* (moCard) {
  1432. if(this.masks[this.currentId] == 0 && this.everyIsAutoOut[this.currentId] && moCard != this.logic.baiDaCard) {
  1433. //杠后或者选择了自动出牌
  1434. if(!this.autoOutTimer){
  1435. this.autoOutTimer = this.app.timer.setTimeout(() =>
  1436. {
  1437. // console.error("开始定时器=====111 moCard "+moCard);
  1438. if(this.autoOutTimer)
  1439. {
  1440. clearTimeout(this.autoOutTimer);
  1441. this.autoOutTimer = null;
  1442. }
  1443. this.outCardAsync(this.currentId,moCard);
  1444. }
  1445. , 1100);//各玩家均没有操作的情况下延迟2秒更新杠后两张牌的状态
  1446. }
  1447. }
  1448. return;
  1449. })
  1450. ///////摸牌函数 参数ifGang是否因为杠而摸牌 TL++ 参数isBHMP 是否补花摸牌,为了判断是否花杠杠开 是否最后一张的海底捞月
  1451. proto.touchCardAsync = cor(function* (chairId,ifGang,isBHMP,ishdly) {
  1452. // console.warn("这不会死循环吧",chairId,isBHMP,this.buhuaTimeout);
  1453. // if(this.buhuaTimeout) {
  1454. // clearTimeout(this.buhuaTimeout);
  1455. // this.buhuaTimeout = null;
  1456. // }
  1457. // 状态校验
  1458. if (this.state != STATE.PLAYING) return;
  1459. if (this.winner.chs.length > 0 || !this.users[chairId]) return;
  1460. if(this.logic.isGuoHuList[chairId][0]) this.logic.isGuoHuList[chairId][0] = false;/////TL++,设置过胡玩家的是否点击过胡为false; 摸牌
  1461. // 当前顺序
  1462. this.currentId = chairId;
  1463. // 摸牌
  1464. // var moCard = this.logic.moCard();TL++zsyl
  1465. ////TL++
  1466. var moCard = { card: 0 };
  1467. // if(isBHMP) moCard.card = this.logic.buHuaMoDePai;//////TL++,补花摸上的牌
  1468. // else {
  1469. let isG = (ifGang && (ifGang == 1) || (ifGang == 2) || (ifGang == 3))
  1470. // console.warn("<<<<<<<<<",isG,ifGang)
  1471. moCard = this.logic.moCard(isG);
  1472. this.logic.moPaiTL();
  1473. // }
  1474. let moPaiIsCanHu = false;//////TL++,摸牌的人是否可以胡牌
  1475. // 是否流局
  1476. if (moCard.card <= 0) {
  1477. // console.warn("提前结算888");
  1478. yield this.concludeGameAsync(MODE.NOCARD);
  1479. return { code: C.OK };
  1480. }
  1481. let lastCount22 = this.logic.leaveCount();/////TL++xg
  1482. let pjhfsplist = {};
  1483. for (let i = 0; i < this.ccount; ++i) {
  1484. let touchCard = { currentId: String(chairId), touch: '0',lastCount : '0' };
  1485. // console.warn("1111WWWWWWWTTTTTT",i,chairId,moCard.card);
  1486. if (i == chairId) {
  1487. touchCard.touch = String(moCard.card);
  1488. // this.handCards[i].push(moCard.card);/////TL++zsyl
  1489. if(!isBHMP) this.handCards[i].push(moCard.card);/////TL++,因为在补花的时候已经将新发的牌放进手牌里了所以这里不用push
  1490. let __isHu = false;
  1491. // console.error("sscc111胡牌分析 摸牌 i",i);
  1492. this.logic.isLaGang = false;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡
  1493. // this.logic.chengBaoTL = [[],[],[],[]];////别人放弃拉杠之后还没想好要怎么清空,因为不清空也行
  1494. // console.warn("222摸牌的时候设置刚才是否有杠",i,ifGang,this.logic.isGGMG,this.logic.isGGAG,this.logic.isGGFXG);
  1495. let huRes = this.logic.huAnalyze(i,this.handCards[i], moCard.card, this.huCards[i], true);
  1496. // console.error("ssccBBB胡牌分析 huRes",huRes);
  1497. if (huRes) {
  1498. // let str3a = "table mpphcg:"+this.id + ",uid"+this.handCards[i];
  1499. // logger.info(str3a);////cssj
  1500. __isHu = true;
  1501. moPaiIsCanHu = true;/////TL++
  1502. this.huRes[i] = huRes;
  1503. }
  1504. let res = this.logic.anGangAnalyze(this.handCards[i]);
  1505. let isGang = (res.length > 0);
  1506. if (!isGang) {
  1507. res = this.logic.zmGangAnalyze(this.handCards[i], this.huCards[i]);
  1508. isGang = (res.length > 0);
  1509. }
  1510. if (isGang) this.masks[i] |= 8;
  1511. if (__isHu) this.masks[i] |= 16;
  1512. ////摸排时候的摸排玩家的胡牌提示
  1513. let hutipdataTL = this.logic.hutip(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////摸牌时调用胡牌提示
  1514. touchCard.hutipdata = hutipdataTL;
  1515. let isGuoHuList = [[false,0],[false,0],[false,0],[false,0],];
  1516. isGuoHuList[chairId] = this.logic.isGuoHuList[chairId];
  1517. touchCard.isGuoHuList = isGuoHuList;
  1518. }
  1519. else {
  1520. this.masks[i] = 0;
  1521. touchCard.hutipdata = {
  1522. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  1523. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  1524. };
  1525. touchCard.isGuoHuList = [[false,0],[false,0],[false,0],[false,0],]
  1526. }
  1527. touchCard.mask = String(this.masks[i]);
  1528. touchCard.lastCount = String(lastCount22);
  1529. this.logic.lastMoPaiChairID = this.currentId;
  1530. // 摸牌通知
  1531. // console.warn("222WWWWWWWTTTTTT",i,chairId,moCard.card);
  1532. yield this.pushMsgAsync(i, 'sxjiang_event', { type: M.TOUCH_CARD, data: touchCard});
  1533. if (i == chairId) {
  1534. pjhfsplist = {
  1535. shouPai:this.logic.deepCloneTL(this.handCards),
  1536. lastCount:String(this.logic.leaveCount()),
  1537. touchCard:this.logic.deepCloneTL(touchCard),
  1538. outCards:this.logic.deepCloneTL(this.outCards),
  1539. isGuoHuList:this.logic.deepCloneTL(this.logic.isGuoHuList)
  1540. }
  1541. }
  1542. if(i == (this.ccount - 1)){/////TL++if条件判断,10月28号,为了实现能看到每个玩家的操作
  1543. pjhfsplist.maskList = this.logic.deepCloneTL(this.masks);/////TL++,10月28号,为了实现能看到每个玩家的操作
  1544. this.setPaijuHuiFangData(M.TOUCH_CARD,pjhfsplist);/////TL++ 牌局回放 push摸牌数据
  1545. }
  1546. }
  1547. let str3 = "table 摸牌函数id:"+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +" card "+moCard.card;
  1548. logger.warn(str3);////cssj
  1549. // 围观通知
  1550. yield this.lookMsgAsync('sxjiang_event', { type: M.TOUCH_CARD, data: { currentId: String(chairId),lastCount:String(lastCount22)} });
  1551. yield this.autoOutCard(moCard.card);
  1552. return { code: C.OK };
  1553. });
  1554. // 放弃操作
  1555. proto.giveUpAsync = cor(function* (chairId) {
  1556. let str3 = "table 放弃操作id: "+this.id + " ,uid "+chairId+", this.masks "+ this.masks;
  1557. logger.warn(str3);////cssj
  1558. // 权限掩码
  1559. var mask = this.masks[chairId];
  1560. if (mask <= 0) {
  1561. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  1562. }
  1563. // console.warn("111放弃操作放弃操作放弃操作放弃操作放弃操作chairId,this.masks",chairId,this.masks,(mask & 16));
  1564. if (mask & 16) {////mask = 16~31时结果=16这个if能进去 0~15或者32~47之间结果=0这个if进不去
  1565. // console.warn("放弃操作里设置过胡为true",chairId, this.logic.isLaGang,this.logic.isGuoHuList,this.logic.everyAllTaiShu);
  1566. this.logic.isGuoHuList[chairId][0] = true;/////TL++,设置过胡玩家的是否点击过胡为true 点击过按钮
  1567. let guohudataTL = {
  1568. chairId:chairId,
  1569. msg: "下次摸牌之前将不能胡牌", /////过胡通知
  1570. }
  1571. let isGuoHuList = [[false,0],[false,0],[false,0],[false,0],];
  1572. isGuoHuList[chairId] = this.logic.isGuoHuList[chairId];
  1573. guohudataTL.isGuoHuList = isGuoHuList;
  1574. //////过胡通知
  1575. yield this.pushMsgAsync(chairId, 'sxjiang_event', { type: M.FHGUOHUTIP, data: guohudataTL });
  1576. if(this.logic.leaveCount() > 0){/////TL++
  1577. this.lgkhCount -= 1;/////TL++拉杠可胡玩家的数量
  1578. }
  1579. // console.warn("666拉杠胡%%%%%%%%%%%%%%%%%%%%%%",this.logic.isLaGang);
  1580. }
  1581. // 删除权限
  1582. this.masks[chairId] = 0;
  1583. // 是否自摸
  1584. if (this.currentId == chairId) {
  1585. return { code: C.OK };
  1586. }
  1587. // 忽略牌
  1588. if (this.outCard) {
  1589. let except = this.excepts[chairId];
  1590. except[this.outCard] = this.outCard;
  1591. }
  1592. // 放弃胡牌
  1593. if (mask & 16) {////mask = 16~31时结果=16这个if能进去 0~15或者32~47之间结果=0这个if进不去
  1594. this.logic.isGuoHuList[chairId][0] = true;/////TL++,设置过胡玩家的是否点击过胡为true 点击过按钮(这句没啥用,在这个函数开始的时候设置过了)
  1595. // console.warn("放弃操作里设置过胡为true",chairId, this.isGangHu,this.logic.isGuoHuList);
  1596. let winner = this.winner;
  1597. do {
  1598. // 一炮多响
  1599. if (this.isMHu) {
  1600. let __cHu = _.findIndex(this.masks, (m) => (m & 16));//////
  1601. // console.warn("允许一炮多想 放弃操作放弃操作放弃操作this.isMHu,__cHu",this.isGangHu,this.isMHu,__cHu);
  1602. if (__cHu != -1) break;
  1603. // 有人胡牌
  1604. if (winner.chs.length > 0) {
  1605. // console.warn("允许一炮多想 操作放弃操作放弃操作winner.chs",winner.chs);
  1606. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  1607. // console.warn("提前结算1111");
  1608. yield this.concludeGameAsync(MODE.NORMAL).then(() => ({ code: C.OK }));/////结算游戏
  1609. return { code: C.OK };
  1610. }
  1611. } else {///// 没炮多响
  1612. // console.warn("没炮多想 放弃操作放弃操作放弃操作winner.chs",this.isGangHu,winner.chs);
  1613. // 有人胡牌
  1614. if (winner.chs.length > 0) {
  1615. let dist = (winner.chs[0] - winner.lead + this.ccount) % this.ccount;
  1616. // let __cHu = _.findIndex(this.masks, (m, i) => (m & 16 && (i - winner.lead + this.ccount) % this.ccount < dist));////TL++,zsyl,
  1617. let __cHu = _.findIndex(this.masks, (m, i) => (m & 16));///TL++,以前是上面那句写法,有个问题:0打牌后1,2,3号玩家都能胡,1点胡2点过,3就没有机会选择是否胡牌
  1618. // console.warn("111没炮多想 放弃操作放弃操作放弃操作__cHu",__cHu);
  1619. if (__cHu != -1) break;
  1620. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  1621. // console.warn("提前结算2222");
  1622. yield this.concludeGameAsync(MODE.NORMAL).then(() => ({ code: C.OK }));/////结算游戏
  1623. return { code: C.OK };
  1624. } else {
  1625. let __cHu = _.findIndex(this.masks, (m) => (m & 16));
  1626. // console.warn("111没炮多想 放弃操作放弃操作放弃操作__cHu",__cHu);
  1627. if (__cHu != -1) break;
  1628. }
  1629. }
  1630. // 查找等待
  1631. let cGang = -1
  1632. let cPeng = -1;
  1633. let _cChi = -1;
  1634. // console.warn("这里是啥情况啊",this.masks);
  1635. for (let i = 0; i < this.masks.length; ++i) {
  1636. // if (i == this.currentId || i == chairId) continue;///////TL++zsyl 这种写法会导致拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  1637. if (i == chairId) continue;//////TL++,为了解决拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  1638. if (this.masks[i] == 9) {
  1639. cGang = i;
  1640. continue;
  1641. }
  1642. if (this.masks[i] == 5) {
  1643. cPeng = i;
  1644. continue;
  1645. }
  1646. if (this.masks[i] == 3) {
  1647. _cChi = i;
  1648. continue;
  1649. }
  1650. }
  1651. // console.warn("2222情况啊",cGang, this.gangType,this.gangCard);
  1652. // 杠碰吃
  1653. if (cGang != -1 && this.gangType > 0 && this.gangCard > 0) {
  1654. // console.warn("这里是放弃操作再次调用 杠 次");
  1655. return this.gangCardAsync(cGang, this.gangCard, this.gangType).then(() => ({ code: C.OK }));
  1656. } else if (cPeng != -1) {
  1657. return this.pengCardAsync(cPeng, this.outCard).then(() => ({ code: C.OK }));
  1658. } else if (_cChi != -1 && this._eatType > 0) {
  1659. return this.eatCardAsync(_cChi, this.outCard, this._eatType).then(() => ({ code: C.OK }));
  1660. }
  1661. } while (0);
  1662. }
  1663. // 放弃杠碰
  1664. if ((mask & 8) || (mask & 4)) {
  1665. let __cHu = _.findIndex(this.masks, (m) => (m & 16));
  1666. if (__cHu == -1) {
  1667. let _cChi = _.findIndex(this.masks, (m) => (m & 3));
  1668. if (_cChi != -1 && this._eatType > 0) {
  1669. return this.eatCardAsync(_cChi, this.outCard, this._eatType).then(() => ({ code: C.OK }));
  1670. }
  1671. }
  1672. }
  1673. // 全无权限
  1674. for (let i = 0; i < this.ccount; ++i) {
  1675. if (this.masks[i] != 0) break;
  1676. // 切换用户
  1677. if (i == this.ccount - 1) {
  1678. // 下家摸牌
  1679. let nextId = (this.currentId + 1) % this.ccount;
  1680. // return this.touchCardAsync(nextId).then(() => ({ code: C.OK }));//////放弃操作引起的摸牌 /////TL++zs
  1681. ///////TL++,整个if,因为海底捞月需要玩家自己去判断要不要摸牌
  1682. // console.warn("222 声剩余声剩余声剩");
  1683. let lastCount = this.logic.leaveCount();/////TL++xg
  1684. return this.touchCardAsync(nextId).then(() => ({ code: C.OK }));//////放弃操作引起的摸牌
  1685. }
  1686. }
  1687. return { code: C.OK };
  1688. });
  1689. // /////TL++,是否进行海底捞月的操作 处理前端海底捞月函数
  1690. proto.haiDiLaoYue = cor(function* (chairId,data) {
  1691. // console.warn("海底捞月海底捞月");
  1692. return { code: C.OK };
  1693. });
  1694. // 杠牌,1-普通杠, 2-暗杠, 3-自摸明杠
  1695. proto.gangCardAsync = cor(function* (chairId, card, type) {
  1696. let str3 = "table 杠牌,id: "+this.id + " ,uid "+chairId+", this.masks "+ this.masks +" ,card "+card;
  1697. logger.warn(str3);////cssj
  1698. // 参数校验
  1699. if (!type && (type < 1 || type > 3)) {
  1700. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1701. }
  1702. if (type == 1 && card != this.outCard) {
  1703. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1704. }
  1705. if (type > 1 && this.currentId != chairId) {
  1706. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1707. }
  1708. if (!(this.masks[chairId] & 8)) {
  1709. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  1710. }
  1711. if(!this.logic.isCanCPB(this.handCards[chairId],Logic.STYLE.GANG,type)){
  1712. return { code: C.FAILD, msg: C.TABLE_NOTONLYBD };
  1713. }
  1714. // 他人可胡
  1715. let __cHu = (type == 2) ? -1 : _.findIndex(this.masks, (m) => ((m & 16) && !(m & 8)));
  1716. // console.warn("111拉杠胡%%%%%%%%%%%%%%%%%%%%%%",__cHu,type);
  1717. if (__cHu == -1) {
  1718. let res = null;
  1719. if (type == 1 || type == 2) {
  1720. res = this.logic.gang(chairId,this.handCards[chairId], card, type);
  1721. } else if (type == 3) {
  1722. res = this.logic.zmGang(chairId,this.handCards[chairId], this.huCards[chairId], card);
  1723. }
  1724. if (!res) {
  1725. return { code: C.FAILD, msg: C.TABLE_GANG_ERROR };
  1726. }
  1727. /////TL++7月17日,这整个if的内容 和else的判断
  1728. let winner = this.winner;
  1729. if (winner.chs.length > 0) {
  1730. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  1731. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  1732. // console.warn("提前结算BBB");
  1733. yield this.concludeGameAsync(MODE.NORMAL);
  1734. }
  1735. else{
  1736. // 记录杠牌
  1737. if (type == 1) {
  1738. // 被杠玩家
  1739. this.gangOuter = this.outerId;
  1740. res.origin = this.outerId;
  1741. this.outCards[this.outerId].pop();
  1742. this.huCards[chairId].push(res);
  1743. this.logic.remove(this.handCards[chairId], res.cards);
  1744. } else if (type == 2) {
  1745. // 被杠玩家
  1746. this.gangOuter = -1;
  1747. this.huCards[chairId].push(res);
  1748. this.logic.remove(this.handCards[chairId], [card, card, card, card]);
  1749. this.logic.adjust(this.handCards[chairId]);
  1750. } else if (type == 3) {
  1751. // console.warn("333拉杠胡%%%%%%%%%%%%%%%%%%%%%%",this.logic.isLaGang,this.isGangHu);
  1752. let huCard = _.find(this.huCards[chairId], (o) => {
  1753. return (o.style == Logic.STYLE.PENG && o.cards[0] == card);
  1754. });
  1755. if (!huCard) {
  1756. return { code: C.FAILD, msg: C.TABLE_GANG_ERROR };
  1757. }
  1758. // 被杠玩家
  1759. this.gangOuter = -1;
  1760. // console.warn("拉杠胡%%%%%%%%%%%%%%%%%%%%%%" ,this.isGangHu);
  1761. // 抢杠胡
  1762. if (!this.isGangHu) {
  1763. this.lgkhCount = 0;/////TL++拉杠可胡玩家的数量
  1764. let allowIds = [], otherIds = [];
  1765. for (let i = 0; i < this.ccount; ++i) {
  1766. // 排除自己
  1767. if (i != chairId) {
  1768. this.logic.isLaGang = true;//////TL++,是否刚刚被拉杠用于判断是否被拉杠胡
  1769. // console.error("sscc222胡牌分析 杠牌i",i,this.logic.isLaGang);
  1770. let huRes = this.logic.huAnalyze(i,this.handCards[i], card, this.huCards[i]);
  1771. // console.error("ssccCCC胡牌分析 huRes",huRes);
  1772. // let lg2 = false;///TL++
  1773. if (huRes) {
  1774. // let str3a = "table lgphcg:"+this.id + ",uid"+this.handCards[i];
  1775. // logger.info(str3a);////cssj
  1776. if (!this.isGangHu) this.isGangHu = true;
  1777. //////////TL++,为了记录承包情况,第一个元素表示承包原因 1:海底捞月打出去被胡 2:被人拉杠胡 第二个元素承包的玩家座位号
  1778. // this.logic.chengBaoTL[chairId][this.logic.chengBaoTL[chairId].length] = [2,this.currentId];
  1779. // lg2 = true//////TL++
  1780. this.huRes[i] = huRes;
  1781. this.masks[i] |= 16;
  1782. this.lgkhCount += 1;/////TL++拉杠可胡玩家的数量
  1783. allowIds.push(this.users[i].id); continue;
  1784. }
  1785. }
  1786. // 其他玩家
  1787. otherIds.push(this.users[i].id);
  1788. }
  1789. // 有人可胡
  1790. if (allowIds.length > 0) {
  1791. // 置于等待
  1792. this.masks[chairId] = 9;
  1793. this.gangType = type;
  1794. this.gangCard = card;
  1795. // 抢杠通知
  1796. yield this.pushMsgAsync(otherIds, 'sxjiang_event', { type: M.MASK_HU, data: { mask: '0', card: String(card) } });
  1797. yield this.pushMsgAsync(allowIds, 'sxjiang_event', { type: M.MASK_HU, data: { mask: '16', card: String(card) } });
  1798. // console.warn("抢杠胡同盟会告知",allowIds);
  1799. return { code: C.OK };
  1800. }
  1801. }
  1802. huCard.style = Logic.STYLE.ZMGANG;
  1803. // console.warn("55拉杠胡%%%%%%%%%%%%%%%%%%%%%%",this.logic.isLaGang,this.gangType,this.gangCard = 0);
  1804. this.isGangHu = false;/////TL++,8月28日晚上,为了解决过胡拉杠之后就算自己已经摸牌也不能再次拉杠的问题
  1805. this.logic.remove(this.handCards[chairId], card);
  1806. this.logic.adjust(this.handCards[chairId]);
  1807. }
  1808. // if(this.chBanker == chairId) this.isZJYG = true;////本局庄家是否有杠
  1809. // 清空权限
  1810. this._eatType = 0;
  1811. this.gangType = 0;
  1812. this.gangCard = 0;
  1813. _.fill(this.masks, 0);
  1814. // 总杠次
  1815. this.gonCount += 1;
  1816. // 发送通知
  1817. // console.warn("333 声剩余声剩余声剩");
  1818. let lastCount = this.logic.leaveCount();/////TL++xg
  1819. let pjhfsplist = {
  1820. shouPai:this.logic.deepCloneTL(this.handCards),
  1821. lastCount:lastCount,
  1822. outCards:this.logic.deepCloneTL(this.outCards),
  1823. opData:{ chairId: String(chairId), type: String(type), card: String(card), lastCount: String(lastCount) }
  1824. }
  1825. this.setPaijuHuiFangData(M.GANG,pjhfsplist);/////TL++ 牌局回放 push杠操作数据
  1826. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.GANG, data: { chairId: String(chairId), type: String(type), card: String(card), lastCount: String(lastCount) } });
  1827. yield this.touchCardAsync(chairId, type); ///////杠牌摸牌
  1828. }
  1829. } else {
  1830. // 置于等待
  1831. this.masks[chairId] = 9;
  1832. this.gangType = type;
  1833. this.gangCard = card;
  1834. }
  1835. // let str4 = "table222 杠牌,id:"+this.id + ",uid"+chairId+","+ this.state +",card "+card;
  1836. // logger.info(str4);////cssj
  1837. return { code: C.OK };
  1838. });
  1839. // 碰牌
  1840. proto.pengCardAsync = cor(function* (chairId, card) {
  1841. let str3 = "table 碰牌id:%s "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +" ,card "+card;
  1842. logger.warn(str3);////cssj
  1843. // 参数校验
  1844. if (card != this.outCard || this.currentId == chairId) {
  1845. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1846. }
  1847. // 权限校验
  1848. if (!(this.masks[chairId] & 4)) {
  1849. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  1850. }
  1851. if(!this.logic.isCanCPB(this.handCards[chairId],Logic.STYLE.PENG,0)){
  1852. return { code: C.FAILD, msg: C.TABLE_NOTONLYBD };
  1853. }
  1854. // 他人可胡杠
  1855. var cHuGang = _.findIndex(this.masks, (m) => (((m & 16) || (m & 8)) && !(m & 4)));
  1856. // console.warn("碰牌按钮被点击了 他人可胡杠",cHuGang,this.masks);
  1857. if (cHuGang == -1) {
  1858. let res = this.logic.peng(chairId,this.handCards[chairId], card);
  1859. if (!res) {
  1860. return { code: C.FAILD, msg: C.TABLE_PENG_ERROR };
  1861. }
  1862. /////TL++7月17日,这整个if的内容 和else的判断
  1863. let winner = this.winner;
  1864. if (winner.chs.length > 0) {
  1865. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  1866. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  1867. // console.warn("提前结算AAA");
  1868. yield this.concludeGameAsync(MODE.NORMAL);
  1869. }
  1870. else{
  1871. // 记录碰牌
  1872. res.origin = this.outerId;
  1873. this.outCards[this.outerId].pop();
  1874. this.huCards[chairId].push(res);
  1875. this.logic.remove(this.handCards[chairId], [card, card]);
  1876. // 清空权限
  1877. this._eatType = 0;
  1878. this.gangType = 0;
  1879. this.gangCard = 0;
  1880. _.fill(this.masks, 0);
  1881. // 用户顺序
  1882. this.currentId = chairId;
  1883. for (let i = 0; i < this.ccount; ++i) {
  1884. let pengdata = {////这种一定要声明在for循环里面
  1885. chairId: String(chairId),
  1886. card: String(card)
  1887. }
  1888. if(i == chairId){
  1889. let hutipdataTL = this.logic.hutip(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////碰牌调用胡牌提示
  1890. pengdata.hutipdata = hutipdataTL;
  1891. }
  1892. else{
  1893. pengdata.hutipdata = {
  1894. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  1895. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  1896. };
  1897. }
  1898. yield this.pushMsgAsync(i, 'sxjiang_event', { type: M.PENG, data: pengdata });
  1899. }
  1900. let pengdatapg = {////碰的旁观数据
  1901. chairId: String(chairId),
  1902. card: String(card)
  1903. }
  1904. pengdatapg.hutipdata = {
  1905. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  1906. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  1907. };
  1908. yield this.lookMsgAsync('sxjiang_event', { type: M.PENG, data: pengdatapg });////TL++
  1909. ////20200831增加胡牌提示的时候把下面这句换成了上面那一段
  1910. // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.PENG, data: { chairId: String(chairId), card: String(card) } });
  1911. let pjhfsplist = {
  1912. shouPai:this.logic.deepCloneTL(this.handCards),
  1913. lastCount:String(this.logic.leaveCount()),
  1914. outCards:this.logic.deepCloneTL(this.outCards),
  1915. opData:{ chairId: String(chairId), card: String(card) }
  1916. }
  1917. this.setPaijuHuiFangData(M.PENG,pjhfsplist);/////TL++ 牌局回放 push碰操作数据
  1918. }
  1919. } else {
  1920. // 置于等待
  1921. this.masks[chairId] = 5;
  1922. // 查找等待 TL++下面这一段,为了解决A打出一张牌之后B可吃胡C可碰情况下 C先点碰B点吃会死掉的问题 这是原始代码的重大天然Bug
  1923. let cGang = -1
  1924. let cPeng = -1;
  1925. let _cChi = -1;
  1926. // console.warn("这里是啥情况啊",this.masks);
  1927. for (let i = 0; i < this.masks.length; ++i) {
  1928. // if (i == this.currentId || i == chairId) continue;///////TL++zsyl 这种写法会导致拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  1929. if (i == chairId) continue;//////TL++,为了解决拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  1930. if (this.masks[i] == 9) {
  1931. cGang = i;
  1932. continue;
  1933. }
  1934. if (this.masks[i] == 5) {
  1935. cPeng = i;
  1936. continue;
  1937. }
  1938. if (this.masks[i] == 3) {
  1939. _cChi = i;
  1940. continue;
  1941. }
  1942. }
  1943. // console.warn("ppppppppppp444 ",chairId,cGang,cPeng,_cChi);
  1944. // console.warn("2222情况啊",cGang, this.gangType,this.gangCard);
  1945. // 杠
  1946. if (cGang != -1 && this.gangType > 0 && this.gangCard > 0) {
  1947. return this.gangCardAsync(cGang, this.gangCard, this.gangType).then(() => ({ code: C.OK }));
  1948. }
  1949. }
  1950. // let str4 = "table 碰牌id:%s"+this.id + ",uid"+chairId+","+ this.state +" card "+card;
  1951. // logger.info(str4);////cssj
  1952. return { code: C.OK };
  1953. });
  1954. // 吃牌,1-@**左吃, 2-*@*中吃, 3-@**右吃
  1955. proto.eatCardAsync = cor(function* (chairId, card, type) {
  1956. let str3 = "table 吃牌id:%s "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +",card "+card;
  1957. logger.warn(str3);////cssj
  1958. // 参数校验
  1959. if (!type && (type < 1 || type > 3)) {
  1960. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1961. }
  1962. if (card != this.outCard) {
  1963. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1964. }
  1965. // 权限校验
  1966. if (!(this.masks[chairId] & 2)) {
  1967. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  1968. }
  1969. if(!this.logic.isCanCPB(this.handCards[chairId],Logic.STYLE.CHI,type)){
  1970. return { code: C.FAILD, msg: C.TABLE_NOTONLYBD };
  1971. }
  1972. // if(this.logic.isGuoHuList[chairId][0]) this.logic.isGuoHuList[chairId][0] = false;/////TL++,吃牌设置过胡玩家的是否点击过胡为false;
  1973. // 他人可胡杠碰
  1974. var cHuGangPeng = _.findIndex(this.masks, (m) => (((m & 16) || (m & 8) || (m & 4)) && !(m & 2)));
  1975. // console.warn("111他人可胡杠碰",cHuGangPeng);
  1976. if (cHuGangPeng == -1) {
  1977. let res = this.logic.chi(this.handCards[chairId], card, type);
  1978. if (!res) {
  1979. return { code: C.FAILD, msg: C.TABLE_PENG_ERROR };
  1980. }
  1981. /////TL++7月17日,这整个if的内容 和else的判断
  1982. let winner = this.winner;
  1983. // console.warn("222他人可胡杠碰",winner.chs.length);
  1984. if (winner.chs.length > 0) {
  1985. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  1986. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  1987. // console.warn("提前结算aaa");
  1988. yield this.concludeGameAsync(MODE.NORMAL);
  1989. }
  1990. else{
  1991. // 记录吃牌
  1992. res.origin = this.outerId;
  1993. this.outCards[this.outerId].pop();
  1994. this.huCards[chairId].push(res);
  1995. if (type == 1) {
  1996. this.logic.remove(this.handCards[chairId], [card + 1, card + 2]);
  1997. } else if (type == 2) {
  1998. this.logic.remove(this.handCards[chairId], [card - 1, card + 1]);
  1999. } else {
  2000. this.logic.remove(this.handCards[chairId], [card - 2, card - 1]);
  2001. }
  2002. // 清空权限
  2003. this._eatType = 0;
  2004. this.gangType = 0;
  2005. this.gangCard = 0;
  2006. _.fill(this.masks, 0);
  2007. // 用户顺序
  2008. this.currentId = chairId;
  2009. // 发送通知
  2010. for (let i = 0; i < this.ccount; ++i) {
  2011. let chidata = {
  2012. chairId: String(chairId),
  2013. type: String(type),
  2014. card: String(card)
  2015. }
  2016. if(i == chairId){
  2017. let hutipdataTL = this.logic.hutip(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////吃牌调用胡牌提示
  2018. chidata.hutipdata = hutipdataTL;
  2019. }
  2020. else{
  2021. chidata.hutipdata = {
  2022. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  2023. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  2024. };
  2025. }
  2026. yield this.pushMsgAsync(i, 'sxjiang_event', { type: M.CHI, data: chidata });
  2027. }
  2028. let chidatapg = { ////TL++吃牌旁观数据
  2029. chairId: String(chairId),
  2030. type: String(type),
  2031. card: String(card)
  2032. }
  2033. chidatapg.hutipdata = {
  2034. renyi:0,//////是否可胡任意牌,0表示不满足1表示满足
  2035. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  2036. };
  2037. yield this.lookMsgAsync('sxjiang_event', { type: M.CHI, data: chidatapg });////TL++吃牌旁观消息
  2038. ////20200901为了增加胡牌提示把下面这一段换成了上面那一段
  2039. // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.CHI, data: { chairId: String(chairId), type: String(type), card: String(card) } });
  2040. let pjhfsplist = {
  2041. shouPai:this.logic.deepCloneTL(this.handCards),
  2042. lastCount:String(this.logic.leaveCount()),
  2043. outCards:this.logic.deepCloneTL(this.outCards),
  2044. opData:{ chairId: String(chairId), type: String(type), card: String(card) }
  2045. }
  2046. this.setPaijuHuiFangData(M.CHI,pjhfsplist);/////TL++ 牌局回放 push吃操作数据
  2047. }
  2048. } else {
  2049. // 置于等待
  2050. this.masks[chairId] = 3;
  2051. this._eatType = type;
  2052. // 查找等待 TL++下面这一段,为了解决A打出一张牌之后B可吃胡C可碰情况下 C先点碰B点吃会死掉的问题 这是原始代码的重大天然Bug
  2053. let cGang = -1
  2054. let cPeng = -1;
  2055. let _cChi = -1;
  2056. // console.warn("这里是啥情况啊",this.masks);
  2057. for (let i = 0; i < this.masks.length; ++i) {
  2058. // if (i == this.currentId || i == chairId) continue;///////TL++zsyl 这种写法会导致拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  2059. if (i == chairId) continue;//////TL++,为了解决拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  2060. if (this.masks[i] == 9) {
  2061. cGang = i;
  2062. continue;
  2063. }
  2064. if (this.masks[i] == 5) {
  2065. cPeng = i;
  2066. continue;
  2067. }
  2068. if (this.masks[i] == 3) {
  2069. _cChi = i;
  2070. continue;
  2071. }
  2072. }
  2073. // console.warn("2222情况啊",cGang, this.gangType,this.gangCard);
  2074. // 杠碰吃
  2075. if (cGang != -1 && this.gangType > 0 && this.gangCard > 0) {
  2076. return this.gangCardAsync(cGang, this.gangCard, this.gangType).then(() => ({ code: C.OK }));
  2077. } else if (cPeng != -1) {
  2078. return this.pengCardAsync(cPeng, this.outCard).then(() => ({ code: C.OK }));
  2079. } else if (_cChi != -1 && this._eatType > 0) {
  2080. return this.eatCardAsync(_cChi, this.outCard, this._eatType).then(() => ({ code: C.OK }));
  2081. }
  2082. }
  2083. // let str4 = "table 吃牌id:"+this.id + ",uid"+chairId+","+ this.state +",card "+card;
  2084. // logger.info(str4);////cssj
  2085. return { code: C.OK };
  2086. });
  2087. // 操作是否自动出牌
  2088. proto.autoOutCardAsync = cor(function* (chairId) {
  2089. // console.warn("操作是否自动出牌 "+chairId);
  2090. if(this.everyIsAutoOut[chairId]) this.everyIsAutoOut[chairId] = 0;
  2091. else this.everyIsAutoOut[chairId] = 1;
  2092. return { code: C.OK,isAutoOut:this.everyIsAutoOut[chairId]};
  2093. })
  2094. // 胡牌 处理前端
  2095. proto.succCardAsync = cor(function* (chairId) {
  2096. let str3 = "table 胡牌:%s "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks;
  2097. logger.warn(str3);////cssj
  2098. // 权限校验
  2099. if (!(this.masks[chairId] & 16)) {
  2100. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  2101. }
  2102. // 删除权限
  2103. this.masks[chairId] = 0;
  2104. // 是否自摸
  2105. let winner = this.winner;
  2106. var isMoHu = (this.currentId == chairId);
  2107. if (isMoHu) {
  2108. winner.chs[0] = chairId;
  2109. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  2110. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push摸胡牌数据
  2111. // console.warn("提前结算444");
  2112. yield this.concludeGameAsync(MODE.NORMAL);
  2113. } else {
  2114. // 抢杠胡
  2115. if (this.isGangHu) {
  2116. winner.lead = this.currentId;
  2117. // 抢杠牌
  2118. if (this.gangType > 0 && this.gangCard > 0) {
  2119. this.logic.remove(this.handCards[this.currentId], this.gangCard);
  2120. this.masks[this.currentId] = 0;
  2121. this.gangType = 0; this.gangCard = 0;
  2122. }
  2123. } else {
  2124. // 点炮
  2125. winner.lead = this.outerId;
  2126. }
  2127. // 一炮多响
  2128. let __cHu = -1;
  2129. if (this.isMHu) {
  2130. // 胡牌者
  2131. winner.chs.push(chairId);
  2132. // 他人可胡
  2133. __cHu = _.findIndex(this.masks, (m) => ((m & 16)));
  2134. } else {
  2135. // 胡牌者
  2136. if (winner.chs.length <= 0) winner.chs[0] = chairId;
  2137. else {
  2138. let hutype = [];//this.logic.getReasultTypeTL(winner.chs[0],this.huCards[winner.chs[0]],false)
  2139. let hutypenew = []//this.logic.getReasultTypeTL(chairId,this.huCards[chairId],false)
  2140. winner.chs[0] = chairId;
  2141. }
  2142. // 他人可胡
  2143. __cHu = _.findIndex(this.masks, (m, i) => ((m & 16)))
  2144. }
  2145. // console.warn("22局部变量改变全局变量??",winner ,this.winner);
  2146. // console.warn("点击胡按钮",__cHu,this.masks);
  2147. if (__cHu == -1) {
  2148. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  2149. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  2150. // console.warn("提前结算555");
  2151. yield this.concludeGameAsync(MODE.NORMAL);
  2152. }
  2153. }
  2154. return { code: C.OK };
  2155. });
  2156. // 结算游戏
  2157. proto.concludeGameAsync = cor(function* (mode) {
  2158. /////增加下面这几行是为了保证每一把只执行一次结算方法
  2159. if(this.isYJJSGL){
  2160. // let strk = "table 结算游戏 id:了保证每一把只执行一次结算方法 "+this.id +"结算模式"+mode
  2161. // logger.info(strk);////cssj
  2162. return;
  2163. }
  2164. this.isYJJSGL = true;
  2165. this.isYJKSGL = false;/////是否已经执行过开始函数了
  2166. this.everyIsAutoOut = _.fill(Array(this.ccount), 0);
  2167. // console.warn("结算函数",mode);
  2168. let str1 = "table 结算游戏 id: "+this.id +" 结算模式 "+mode
  2169. logger.warn(str1);////cssj
  2170. //ts--end
  2171. // 结算数据
  2172. var winner = this.winner;
  2173. var data = { mode: String(mode), lead: String(winner.lead) };
  2174. var wins = this.logic.fillDeep(Array(this.ccount), {
  2175. win: 0,//总输赢
  2176. lucky: 0,
  2177. trans: 0,//明杠个数
  2178. dark: 0,//暗杠个数
  2179. penggang: 0,//碰杠个数
  2180. isPoChan: 0,
  2181. shiJiKouFen: 0,
  2182. gangfen: 0,
  2183. cardfen: 0,
  2184. jiangma: 0,
  2185. });
  2186. data.hutype = [];//this.logic.getReasultTypeTL(winner.chs[0],this.huCards[winner.chs[0]],true)///////TL++胡牌牌型 胡牌人的chairID
  2187. data.banker = this.chBanker;/////TL++
  2188. data.chengbao = [];
  2189. let isMZJYM = false;//是否满足无红中加一码
  2190. if(winner.chs.length == 1 && this.jiangmaType == 1 && this.hzCount > 0 && this.isWGHZJYM){
  2191. //无红中加1码,规则只能在红中个数大于0而且是159奖码情况下才能勾选
  2192. if(this.handCards[winner.chs[0]].indexOf(51) == -1){
  2193. //有多个赢家的时候无红中加一码不生效
  2194. isMZJYM = true;
  2195. }
  2196. }
  2197. let jiangmaInfo = this.logic.getJiangmaInfo(isMZJYM);
  2198. data.jiangmaList = jiangmaInfo.jiangmaList;
  2199. let jiangmaFen = jiangmaInfo.mafen;
  2200. let yjgs = 0;//赢家个数
  2201. // 计算输赢
  2202. for (let i = 0; i < wins.length; ++i) {
  2203. // 自摸
  2204. let isMoHu = winner.lead == -1;
  2205. // 胡牌者
  2206. if (winner.chs.indexOf(i) != -1) {
  2207. yjgs++;
  2208. // console.warn("结算承包数据",this.logic.chengBaoTL,isMoHu,cbqk);
  2209. if(this.logic.isLaGang){
  2210. //抢杠胡:被抢者替每家输2分
  2211. let lead = winner.lead;
  2212. let sy = 2 * this.cell
  2213. wins.forEach((w, c) => {
  2214. if (c != i) {
  2215. wins[lead].win -= sy;
  2216. wins[i].win += sy;
  2217. wins[lead].cardfen -= sy;
  2218. wins[i].cardfen += sy;
  2219. }
  2220. });
  2221. ////下面这段是计算奖码的分数
  2222. wins.forEach((w, c) => {
  2223. if (c != i) {
  2224. if(c == lead){//////点炮玩家
  2225. wins[lead].win -= jiangmaFen;
  2226. wins[i].win += jiangmaFen;
  2227. wins[lead].jiangma -= jiangmaFen;
  2228. wins[i].jiangma += jiangmaFen;
  2229. }
  2230. }
  2231. });
  2232. }
  2233. else{
  2234. //不是抢杠胡
  2235. if (isMoHu) {
  2236. //自摸每家输2分
  2237. let sy = 2 * this.cell
  2238. wins.forEach((w, c) => {
  2239. if (c != i) {
  2240. w.win -= sy;
  2241. wins[i].win += sy;
  2242. w.cardfen -= sy;
  2243. wins[i].cardfen += sy;
  2244. }
  2245. });
  2246. ////下面这段是计算奖码的分数
  2247. wins.forEach((w, c) => {
  2248. if (c != i) {
  2249. w.win -= jiangmaFen;
  2250. wins[i].win += jiangmaFen;
  2251. w.jiangma -= jiangmaFen;
  2252. wins[i].jiangma += jiangmaFen;
  2253. }
  2254. });
  2255. }
  2256. else {
  2257. //点炮者:给赢家输1分,其他人不输分
  2258. let lead = winner.lead;
  2259. // 点炮出钱
  2260. // if (this.isWOne) {/////TL++zsyl,次判断方式适用于点炮出钱
  2261. let hutype = [];
  2262. let sy = this.cell
  2263. wins.forEach((w, c) => {
  2264. if (c != i) {
  2265. if(c == lead){//////点炮玩家
  2266. w.win -= sy;
  2267. wins[i].win += sy;
  2268. w.cardfen -= sy;
  2269. wins[i].cardfen += sy;
  2270. }
  2271. }
  2272. });
  2273. ////下面这段是计算奖码的分数
  2274. wins.forEach((w, c) => {
  2275. if (c != i) {
  2276. if(c == lead){//////点炮玩家
  2277. wins[lead].win -= jiangmaFen;
  2278. wins[i].win += jiangmaFen;
  2279. wins[lead].jiangma -= jiangmaFen;
  2280. wins[i].jiangma += jiangmaFen;
  2281. }
  2282. }
  2283. });
  2284. }
  2285. }
  2286. wins[i].lucky = 1;
  2287. }
  2288. // let str2 = "table 222结算函数---id:"+this.id +"结算模式"+mode
  2289. // logger.info(str2);////cssj
  2290. if(!(mode != MODE.NORMAL && this.isHZHG)) {
  2291. // 杠牌 流局了而且勾选荒庄荒杠 的话则不计算杠分
  2292. let gangMul = 0;
  2293. for (let huCard of this.huCards[i]) {
  2294. if (huCard.style == Logic.STYLE.ZMGANG) {
  2295. gangMul += 1;
  2296. wins[i].penggang += 1;
  2297. } else if (huCard.style == Logic.STYLE.ANGANG) {
  2298. gangMul += 2;
  2299. wins[i].dark += 1;
  2300. } else if (huCard.style == Logic.STYLE.GANG){
  2301. //明杠谁点的杠谁付3分
  2302. wins[i].trans += 1;
  2303. wins[huCard.origin].win -= 3 * this.cell;
  2304. wins[i].win += 3 * this.cell;
  2305. wins[huCard.origin].gangfen -= 3 * this.cell;
  2306. wins[i].gangfen += 3 * this.cell;
  2307. }
  2308. }
  2309. if (gangMul > 0) {
  2310. wins.forEach((w, c) => {
  2311. if (c != i) {
  2312. w.win -= gangMul * this.cell;
  2313. wins[i].win += gangMul * this.cell;
  2314. w.gangfen -= gangMul * this.cell;
  2315. wins[i].gangfen += gangMul * this.cell;
  2316. }
  2317. });/////TL++杠牌有赢
  2318. }
  2319. }
  2320. // 手牌
  2321. let cards = { card: 0, groups: [], hands: [] };
  2322. if (wins[i].lucky) {
  2323. cards.card = this.huRes[i].card;
  2324. }
  2325. for (let huCard of this.huCards[i]) {
  2326. cards.groups.push({ style: huCard.style, card: huCard.cards[0] });
  2327. }
  2328. let handCard = this.handCards[i] || [];
  2329. let count = this.mcount - this.huCards[i].length * 3;
  2330. cards.hands = handCard.slice(0, count);
  2331. wins[i].cards = cards;
  2332. }
  2333. // let str3 = "table 333结算函数---id:"+this.id +",结算模式"+mode
  2334. // logger.info(str3);////cssj
  2335. //////TL++
  2336. let shiJiKouFen = [];
  2337. if(this.playerAllCount == 2) shiJiKouFen = [wins[0].win,wins[1].win];
  2338. else if(this.playerAllCount == 3) shiJiKouFen = [wins[0].win,wins[1].win,wins[2].win];
  2339. else if(this.playerAllCount == 4) shiJiKouFen = [wins[0].win,wins[1].win,wins[2].win,wins[3].win];
  2340. for (let i = 0; i < this.ccount; ++i) {
  2341. wins[i].shiJiKouFen = shiJiKouFen[i];
  2342. }
  2343. //console.warn("实际扣分XXX",shiJiKouFen,wins[0].win,wins[1].win,wins[2].win,wins[3].win)
  2344. // 胜负情况
  2345. data.wins = wins;
  2346. let bjsy = [];//本局每个人的输赢
  2347. for (let i = 0; i < this.ccount; ++i) {
  2348. bjsy[i] = wins[i].win;
  2349. }
  2350. this.sszjDataList[this.sszjDataList.length] = bjsy;
  2351. this.over += 1;// 局数+1
  2352. //ts++
  2353. let sszjScore = [];//ts++实时本局成绩
  2354. let sszjAllScore = [];//ts++实时总成绩
  2355. // 记录分数
  2356. for (let i = 0; i < this.ccount; ++i) {
  2357. let user = this.users[i];
  2358. if (user)
  2359. {
  2360. sszjScore[i] = shiJiKouFen[i];
  2361. this.score.writeScore(user.id,shiJiKouFen[i], 1);//设置分数
  2362. sszjAllScore[i] = this.score.getScore(user.id);
  2363. // if(this.gameKindTL == 2) sszjAllScore[i] -=200;
  2364. if(this.over == 1)
  2365. {
  2366. this.score.writeCost(user.id,this.cost, 0); //ts++设置消耗
  2367. }
  2368. }
  2369. }
  2370. let endmode=ENDMODE.PLAYING;
  2371. if(this.isGameOver())
  2372. {
  2373. this.isGameOk=true;
  2374. endmode=ENDMODE.NORMALEND;//局数完成--正常结束
  2375. }
  2376. data.isover = this.isGameOk;
  2377. data.nowTime = Date.now();
  2378. this.setPaijuHuiFangData(M.CONCLUDE,data);/////TL++ 牌局回放 push结算数据
  2379. /////TL++,用于记录玩家牌局回放的json文件名
  2380. this.pjhffileName[this.pjhffileName.length] = this.PJHF.getjsonFileName(this.over,this.recordid,this.ctime);
  2381. // let str4 = "table 444结算函数---id:%s"+this.id +"结算模式"+mode
  2382. // logger.info(str4);////cssj
  2383. //ts++胡的人
  2384. let hu=-1;
  2385. if (winner.chs.length >0 && winner.chs[0] >= 0 && winner.chs[0] <= 3)
  2386. {
  2387. hu=winner.chs[0];
  2388. }
  2389. //ts++实时战绩
  2390. //this.sszjs.push({_id: String(this.over),c0Score:bjsy[0],c1Score:bjsy[1], c2Score:bjsy[2], c3Score:bjsy[3],banker:this.chBanker,hu:hu,pao:winner.lead, fName:jsonFileName});
  2391. this.sszjs.push({_id: String(this.over),sszjScore:sszjScore,sszjAllScore:sszjAllScore,banker:this.chBanker,hu:hu,pao:winner.lead});
  2392. /////固定庄家,不固定的话解除下面这一段的注释
  2393. // 切换庄家
  2394. if(yjgs == 0){
  2395. //没有赢家,流局了,最后一个摸牌的人坐庄
  2396. this.chBanker = this.logic.lastMoPaiChairID;
  2397. }
  2398. else if(yjgs == 1){
  2399. //只有一个人赢了,谁赢谁做庄
  2400. this.chBanker = winner.chs[0];
  2401. }
  2402. else if(yjgs > 1) {
  2403. //一炮多响,放炮的人坐庄
  2404. this.chBanker = winner.lead
  2405. }
  2406. /////TL++,10月9号,为了解决冲刺时前端的玩家分数偶尔会显示负数的bug
  2407. data.playNowScore = [];
  2408. for (let i = 0; i < this.ccount; ++i) {
  2409. let user = this.users[i];
  2410. if (user)
  2411. {
  2412. data.playNowScore[i] = this.score.getScore(user.id);
  2413. }
  2414. }
  2415. // 重置本局
  2416. this.resetRound();
  2417. // 结算通知
  2418. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.CONCLUDE, data: data });
  2419. this.PJHF.writePJHFJson({"pjhfDataList":this.PaijuHuiFang},this.over,this.id)
  2420. this.logic.isZHYZ = false; /////TL++,是否最后一张
  2421. // yield this.pushMsgAsync(-1, 'sxjiang_event', { type: 100, data: {"pjhfDataList":this.PaijuHuiFang}});//////最终发送给前端的牌局回放
  2422. // let str6 = "table end 结算函数-id:"+this.id +"结算模式"+mode
  2423. // logger.info(str6);////cssj
  2424. yield this.endResultAsync(endmode);
  2425. });
  2426. // 发送聊天
  2427. proto.sendMsgAsync = cor(function* (chairId, msg) {
  2428. // console.error("sscc发送聊天+++++++++++++++++++++++++++++++++",chairId,msg)
  2429. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.CHAT, data: { chairId: String(chairId), msg: msg } });
  2430. return { code: C.OK };
  2431. });
  2432. // 收费聊天 礼物收费
  2433. proto.vsendMsgAsync = cor(function* (schairId, dchairId, msg) {
  2434. if (schairId == dchairId || !this.users[dchairId]) {
  2435. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  2436. }
  2437. let user = this.users[schairId];
  2438. if (!user) {
  2439. return { code: C.FAILD, msg: C.TABLE_NOT_USER };
  2440. }
  2441. let lwcost = this.LWKF[msg.type];//////TL++礼物扣费
  2442. if(lwcost > 0){
  2443. var player = yield this.app.models.Player.findByIdAsync(user.id, 'diamond');
  2444. if(player)
  2445. {
  2446. if (((player.diamond) || 0) < lwcost) {
  2447. return { code: C.FAILD, msg: C.GAME_DIAMOND_LOW };
  2448. }
  2449. let dSource=player.diamond;
  2450. let dNow=player.diamond-lwcost;
  2451. player.diamond -= lwcost;
  2452. yield player.saveAsync();
  2453. // 钻石记录
  2454. var diamondrecord = new this.app.models.DiamondRecord({
  2455. _id: uuid.v1(),
  2456. playerId: user.id,
  2457. dType: 5,//礼物
  2458. dSource: dSource,
  2459. dSwap: -lwcost,
  2460. dNow: dNow,
  2461. tableId: this.recordid
  2462. });
  2463. yield diamondrecord.saveAsync();
  2464. //ts++设置消耗
  2465. // this.score.writeCost(user.id,0, lwcost);
  2466. }
  2467. }
  2468. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.FEE_CHAT, data: { cost: String(lwcost),schairId: String(schairId), dchairId: String(dchairId), msg: msg } });
  2469. return { code: C.OK };
  2470. });
  2471. //ts++写分 endtype = { 正常: 0,局数完成: 1, 房主解散: 2, 申请解散: 3 ,超时解散: 4 };
  2472. proto.writeResultAsync = cor(function* (endmode) {
  2473. logger.warn("牌局写入-------------- " + this.id );
  2474. // console.warn("ts++---------牌局写入writeResultAsync",this.id);
  2475. let gameCost=0;//游戏消耗
  2476. let giftCost = 0;////道具消耗
  2477. this.etime = Date.now();
  2478. let users = [];
  2479. let localUsers = [];
  2480. var scorers = this.score.getUsers();
  2481. if (scorers.length > 0)
  2482. {
  2483. var scorersSort = _.sortBy(scorers, (i) => i.chairId);
  2484. for (let scorer of scorersSort) {
  2485. gameCost+=this.cost;
  2486. giftCost+=scorer.giftCost;
  2487. let userscore=scorer.score;
  2488. // if(this.gameKindTL == 2) userscore -= 200;
  2489. users.push({_id: scorer.playerId,chairId:scorer.chairId,userId: scorer.userId, name: scorer.name, sex: scorer.sex, headurl: scorer.headurl,over: scorer.over, score: userscore});
  2490. //, gameCost: scorer.gameCost,giftCost: scorer.giftCost,diamond: scorer.diamond
  2491. localUsers.push({_id: scorer.playerId,userId: scorer.userId, name: scorer.name, gameCost: scorer.gameCost,giftCost: scorer.giftCost,});
  2492. }
  2493. }
  2494. // if(this.isGameOk)////以前是解散的不算返利
  2495. if(this.over > 0)////改成只要玩家扣钻了就有返利
  2496. {
  2497. // this.agentRebate=gameCost;//parseInt(gameCost*0.5);
  2498. this.agentRebate=gameCost+giftCost;////礼物也算消耗进行返利
  2499. // console.warn("代理返利+++++",this.agentRebate);
  2500. }
  2501. else
  2502. {
  2503. this.agentRebate=0;
  2504. }
  2505. //console.warn("实时战绩",this.sszjs);//ts++
  2506. this.PJHF.getTSjsonFileName(100,this.recordid,this.ctime);/////TL++,用于记录玩家牌局回放的json文件名
  2507. // console.error("000HHHHHHHHHHHHHHHHHHHHHH",this.pjhffileName.length,this.pjhffileName);
  2508. let datats = {
  2509. _id: this.recordid,//记录
  2510. gameId: this.gameId,
  2511. tableNo: this.id,
  2512. ownerId: this.ownerId,
  2513. agentId: this.agentId,
  2514. type: this.type,
  2515. kind: this.gameKindTL,//玩法 2冲刺
  2516. other: this.other,//////TL++2人3人的游戏规则
  2517. playerCount: this.playerAllCount,//游戏人数
  2518. round: this.round,//
  2519. over: this.over,//游戏局数
  2520. ctime: this.ctime,//创建时间
  2521. stime: this.stime,//开始时间
  2522. time: this.etime,//结束时间
  2523. endMode: endmode,//结束类型
  2524. gameCost: gameCost,//游戏消耗
  2525. giftCost: giftCost,//礼物消耗
  2526. agentRebate: parseInt(this.agentRebate),//代理返利
  2527. sszjFile: this.logic.deepCloneTL(this.pjhffileName),
  2528. sszj: this.logic.deepCloneTL(this.sszjs),
  2529. users: users
  2530. }
  2531. this.PJHF.writeTSJson(datats,100,this.id);////在开始第一局的时候将桌子信息写入本地的json文件
  2532. var fhmjtable = new this.app.models.FHMJTables({
  2533. _id: this.recordid,//记录
  2534. gameId: this.gameId,
  2535. tableNo: this.id,
  2536. ownerId: this.ownerId,
  2537. agentId: this.agentId,
  2538. type: this.type,
  2539. kind: this.gameKindTL,//玩法 2冲刺
  2540. other: this.other,//////TL++2人3人的游戏规则
  2541. playerCount: this.playerAllCount,//游戏人数
  2542. round: this.round,//
  2543. over: this.over,//游戏局数
  2544. ctime: this.ctime,//创建时间
  2545. stime: this.stime,//开始时间
  2546. time: this.etime,//结束时间
  2547. endMode: endmode,//结束类型
  2548. gameCost: gameCost,//游戏消耗
  2549. giftCost: giftCost,//礼物消耗
  2550. agentRebate: parseInt(this.agentRebate),//代理返利
  2551. sszjFile: this.pjhffileName,
  2552. sszj: this.sszjs,
  2553. users: users
  2554. });
  2555. // console.warn("fhmjtable new",fhmjtable);
  2556. yield fhmjtable.saveAsync();
  2557. //下面是记录返利相关的
  2558. if(this.agentId && this.agentRebate>0){
  2559. yield this.lsetReabte.writeReabteInfo(this.agentId,this.etime,this.agentRebate,gameCost,giftCost,this.recordid,localUsers,this.gameId);
  2560. // yield this.lsetReabte.writePlayerCountInfo(this.agentId,this.etime,users,this.cost,this.isGameOk,this.gameId);
  2561. }
  2562. //下面是记录邀请新人按比例送钻这个活动的数据
  2563. if(!this.lconfigCommon) {
  2564. // console.warn("邀请新人送钻石活动 this.lconfigCommon 不存在 "+this.etime);
  2565. this.lconfigCommon = new configCommon(this.app);
  2566. }
  2567. yield this.lconfigCommon.yxActivityAsync(scorers,this.etime);
  2568. // logger.info("战绩写入fhmjtable.saveAsync()--------------",this.id);
  2569. });
  2570. // 结束信息 var endtype = { 局数完成: 1, 主动解散: 2, 断线解散: 3 ,超时解散: 4 };
  2571. proto.endResultAsync = cor(function* (endmode) {
  2572. // console.warn("ts++---------记录信息",this.id);
  2573. let str6 = "table 结束信息--id: "+this.id +" ,结算模式 "+endmode;
  2574. logger.warn(str6);////cssj
  2575. if(endmode>ENDMODE.PLAYING)//ts++关闭
  2576. {
  2577. let nowTime = Date.now();
  2578. if(this.state<STATE.END)//ts++防止重复写入
  2579. {
  2580. this.state = STATE.END;
  2581. if (this.endTimer) {
  2582. clearTimeout(this.endTimer);
  2583. this.endTimer = null;
  2584. }
  2585. if (this.overTimer) {
  2586. clearTimeout(this.overTimer);
  2587. this.overTimer = null;
  2588. }
  2589. // console.warn("ts++---------局数完成",this.over);
  2590. if(this.over>0)
  2591. {
  2592. var scorers = this.score.getUsers();
  2593. if (scorers.length > 0) {
  2594. let data = {
  2595. _id: this.recordid,
  2596. gameId: this.gameId,
  2597. tableNo: this.id,
  2598. ownerId: this.ownerId,
  2599. type:String(this.type),
  2600. kind: String(this.gameKindTL),
  2601. over: String(this.over),
  2602. round: String(this.round),
  2603. time: String(nowTime),
  2604. ctime: String(this.ctime),
  2605. keep: String(nowTime - this.stime),
  2606. other: this.other,
  2607. playerCount:this.playerAllCount,
  2608. agentId: this.agentId
  2609. };
  2610. let collects = [];
  2611. for (let scorer of scorers) {
  2612. let userscore=scorer.score;
  2613. // if(this.gameKindTL == 2) userscore -= 200;//TL++,因为总的结算界面的每个玩家的分数范围为-200 ~ 600
  2614. collects.push({ chairId:scorer.chairId,name: scorer.name, sex: scorer.sex, headurl: scorer.headurl, score: userscore });
  2615. }
  2616. data.users = _.sortBy(collects, (i) => -i.score);
  2617. //data.sszjFile=this.pjhffileName;
  2618. data.sszj=this.sszjs;
  2619. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.TOTAL_CONCLUDE, data: data });////汇总结算
  2620. }
  2621. //console.warn("ts++---------牌局写入");
  2622. yield this.writeResultAsync(endmode);
  2623. }
  2624. //console.warn("ts---------牌局结束");
  2625. for (let user of this.users) {
  2626. if (user) {
  2627. if (user.isOffline())
  2628. {
  2629. user.state = User.STATE.FREE;
  2630. user.state2 = User.STATE.FREE;
  2631. this.leaveUsers.push(user.id);
  2632. ///yield this.game.leaveTableAsync(user.id);
  2633. }
  2634. else
  2635. {
  2636. user.state = User.STATE.FREE;
  2637. user.state2 = User.STATE.FREE;
  2638. }
  2639. }
  2640. }
  2641. }
  2642. if(endmode==ENDMODE.SYSTEMEND)
  2643. {
  2644. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.TABLE_JIESAN });
  2645. }
  2646. if(this.leaveUsers.length>0)
  2647. {
  2648. this.app.timer.setTimeout(() => this.leaveUserTimeAsync(), 100);
  2649. }
  2650. // var gametable = yield this.app.models.GameTable.findByIdAsync(this.recordid, '_id tableNo agentId endMode');
  2651. // if(gametable){
  2652. // gametable.endMode = 1;
  2653. // yield gametable.saveAsync();
  2654. // }
  2655. this.game.deleteTable(this.id);//ts++删除房间
  2656. // let str5 = "table 结束信息22 关闭-id:"+this.id +"结算模式"+endmode;
  2657. // logger.info(str5);////cssj
  2658. }
  2659. else//普通结束
  2660. {
  2661. // let str5 = "table 结束信息 普通结束---id:"+this.id +"结算模式"+endmode
  2662. // logger.info(str5);////cssj
  2663. this.state = STATE.FREE2;
  2664. for (let user of this.users) {
  2665. if (user) user.state2 = User.STATE.FREE;
  2666. }
  2667. }
  2668. let str7 = "table end 结束信息---id:%s "+this.id +" 结算模式 "+endmode;
  2669. logger.warn(str7);////cssj
  2670. });
  2671. //ts++离开用户退出定时器
  2672. proto.leaveUserTimeAsync = cor(function* () {
  2673. // console.warn("离开用户退出定时器,离开用户数==%d",this.leaveUsers.length);////cssj
  2674. if(this.leaveUsers.length>0)
  2675. {
  2676. let userid = this.leaveUsers[0];
  2677. this.leaveUsers.splice(0, 1);
  2678. let str7 = "table end 离开用户退出定时器---id:%s "+this.id +" userid "+userid;
  2679. logger.warn(str7);////cssj
  2680. yield this.game.leaveTableAsync(userid);
  2681. }
  2682. if(this.leaveUsers.length>0)
  2683. {
  2684. this.app.timer.setTimeout(() => this.leaveUserTimeAsync(), 100);
  2685. }
  2686. });
  2687. // TL++,得到玩家位置
  2688. proto.sendLocationAsync = cor(function* (user,msg) {
  2689. /////设置玩家的经纬度
  2690. user.longitude = msg.longitude; // 经度,浮点数,范围为180 ~ -180。
  2691. user.latitude = msg.latitude; // 纬度,浮点数,范围为90 ~ -90
  2692. let tempData = {
  2693. userId: user.userId,
  2694. account: user.account,
  2695. longitude: msg.longitude,
  2696. latitude: msg.latitude
  2697. }
  2698. //////向其他玩家广播该玩家位置
  2699. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.COAST_PLAYERLOCATION, data: tempData });
  2700. return { code: C.OK, data: tempData };
  2701. });
  2702. // 玩家信息
  2703. proto.roleInfoAsync = cor(function* (chairId) {
  2704. // console.log("玩家信息玩家信息玩家信息");
  2705. var user = this.users[chairId];
  2706. if (!user) {
  2707. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  2708. }
  2709. var data = { userId: '0', ttCount: '0', winCount: '0', noCount: '0', runCount: '0' };
  2710. data.userId =user.userId;
  2711. return { code: C.OK, data: data };
  2712. });
  2713. //ts++请求结束定时器
  2714. proto.overTimeAsync = cor(function* (endmode) {
  2715. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.TABLE_JIESAN });
  2716. let str6 = "table 请求结束定时器---id: "+this.id +" ,endmode: "+endmode
  2717. logger.warn(str6);////cssj
  2718. yield this.endResultAsync(endmode);//ts++ 房主解散 写分
  2719. });
  2720. // 请求结束
  2721. proto.overTableAsync = cor(function* (user) {
  2722. // console.warn("ts+++++请求结束",user.chairId);
  2723. let str3 = "table 请求结束.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  2724. logger.warn(str3);////cssj
  2725. if(this.state == STATE.END)
  2726. {
  2727. this.leaveAsync(user);
  2728. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  2729. }
  2730. if(this.reqJieSan.indexOf(2) != -1) return;/////有发起人的时候
  2731. // console.warn("2222请求结束请求结束请求结束",this.reqJieSan);
  2732. //解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  2733. //jieSanType =1:游戏开始前房主申请解散 =2:游戏开始前非房主玩家退出房间 =3:游戏过程中玩家申请解散 =4游戏过程中是房主但没参与游戏退出房间 =5其他
  2734. if(this.gameNeverStart) {//游戏是否从未开始过,用于解散房间判断
  2735. if(user.userId == this.ownerUid){
  2736. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.TABLE_JIESAN });
  2737. // let str5 = "table 房主解散-id:"+this.id+ ",uid"+user.userId;
  2738. // logger.info(str5);////cssj
  2739. yield this.endResultAsync(ENDMODE.OWNEREND);//ts++ 房主解散 写分
  2740. return { code: C.OK, data:{jieSanType: 1}};
  2741. }
  2742. else{
  2743. this.leaveAsync(user);
  2744. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  2745. }
  2746. }
  2747. else
  2748. {
  2749. let chairId=user.chairId;
  2750. if(chairId >= 0 && chairId < 4 )
  2751. {
  2752. if(this.overFlag==0)//发起
  2753. {
  2754. this.overFlag = 1;
  2755. this.reqJieSan[0]=-1;
  2756. this.reqJieSan[1]=-1;
  2757. this.reqJieSan[2]=-1;
  2758. this.reqJieSan[3]=-1;
  2759. this.reqJieSan[chairId]=2;
  2760. let jsdata = [];//ts++实时本局成绩
  2761. jsdata[0] = this.reqJieSan[0];
  2762. jsdata[1] = this.reqJieSan[1];
  2763. jsdata[2] = this.reqJieSan[2];
  2764. jsdata[3] = this.reqJieSan[3];
  2765. this.JSFJTime = 60;//////解散倒计时60秒
  2766. this.SQJSTime = Date.now() + this.JSFJTime*1000;
  2767. if (!this.overTimer) this.overTimer = this.app.timer.setTimeout(() => this.overTimeAsync(ENDMODE.REGEND),this.JSFJTime*1000);//解散倒计时60秒
  2768. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.REQUEST_END, data: { chairId: String(chairId),time: this.JSFJTime,jsdata:jsdata}});
  2769. return { code: C.OK, data:{jieSanType: 3}};
  2770. }
  2771. else//同意
  2772. {
  2773. return this.agreeOverAsync(chairId);
  2774. }
  2775. }
  2776. else
  2777. {
  2778. return { code: C.FAILD, msg: C.TABLE_ALREADY_SQJS };
  2779. }
  2780. }
  2781. return { code: C.OK, data:{jieSanType: 5}};
  2782. });
  2783. // 拒绝结束
  2784. proto.refuseOverAsync = cor(function* (user) {
  2785. let str3 = "table 拒绝结束.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  2786. logger.warn(str3);////cssj
  2787. if(this.state == STATE.END)
  2788. {
  2789. this.leaveAsync(user);
  2790. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  2791. }
  2792. if(this.overFlag == 0) //ts++已经拒绝了
  2793. {
  2794. return { code: C.OK };
  2795. }
  2796. this.overFlag = 0;
  2797. let chairId=user.chairId;
  2798. // console.error("ts++----------拒绝结束",chairId);
  2799. this.reqJieSan[chairId]=0;//解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  2800. let jsdata = [];//ts++实时本局成绩
  2801. jsdata[0] = this.reqJieSan[0];
  2802. jsdata[1] = this.reqJieSan[1];
  2803. jsdata[2] = this.reqJieSan[2];
  2804. jsdata[3] = this.reqJieSan[3];
  2805. if (this.overTimer) {
  2806. clearTimeout(this.overTimer);
  2807. this.overTimer = null;
  2808. }
  2809. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.REFUSE_END, data: { chairId: String(chairId),time: 0,jsdata:jsdata} });
  2810. //this.reqJieSan = [[-1,-1],[-1,-1],[-1,-1],[-1,-1]];/////解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  2811. this.reqJieSan[0]=-1;
  2812. this.reqJieSan[1]=-1;
  2813. this.reqJieSan[2]=-1;
  2814. this.reqJieSan[3]=-1;
  2815. return { code: C.OK };
  2816. });
  2817. // 同意结束
  2818. proto.agreeOverAsync = cor(function* (user) {
  2819. let str3 = "table 同意结束.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  2820. logger.warn(str3);////cssj
  2821. if(this.state == STATE.END)
  2822. {
  2823. this.leaveAsync(user);
  2824. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  2825. }
  2826. if(this.overFlag == 0) //ts++已经拒绝了
  2827. {
  2828. return { code: C.OK };
  2829. }
  2830. let chairId=user.chairId;
  2831. // console.error("ts++----------同意结束",chairId);
  2832. this.reqJieSan[chairId] = 1;/////解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  2833. let jsdata = [];//ts++实时本局成绩
  2834. jsdata[0] = this.reqJieSan[0];
  2835. jsdata[1] = this.reqJieSan[1];
  2836. jsdata[2] = this.reqJieSan[2];
  2837. jsdata[3] = this.reqJieSan[3];
  2838. this.JSFJTime = Math.floor((this.SQJSTime - Date.now())/1000);
  2839. if(this.JSFJTime >= 25)this.JSFJTime -= 20;//////解散房间倒计时60秒
  2840. else this.JSFJTime = 10;
  2841. this.SQJSTime = Date.now() + this.JSFJTime*1000;
  2842. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.AGREE_END, data: { chairId: String(chairId),time: this.JSFJTime,jsdata:jsdata} });
  2843. let jsFlag = 0;
  2844. for (let i = 0; i < 4; ++i)
  2845. {
  2846. if(this.reqJieSan[i] >=1 )
  2847. {
  2848. jsFlag+=1;
  2849. }
  2850. }
  2851. if(jsFlag>=this.ccount || this.JSFJTime<=0)
  2852. {
  2853. if(this.backStartTimer)
  2854. {
  2855. clearTimeout(this.backStartTimer);
  2856. this.backStartTimer = null;
  2857. }
  2858. yield this.pushMsgAsync(-1, 'sxjiang_event', { type: M.TABLE_JIESAN });
  2859. // let str4 = "table 全部同意结束-id:%s"+this.id + ",uid"+user.userId+",state"+ this.state;
  2860. // logger.info(str4);////cssj
  2861. yield this.endResultAsync(ENDMODE.REGEND);//ts++ 结束
  2862. }
  2863. else
  2864. {
  2865. if (this.overTimer) {
  2866. clearTimeout(this.overTimer);
  2867. this.overTimer = null;
  2868. }
  2869. if (!this.overTimer) this.overTimer = this.app.timer.setTimeout(() => this.overTimeAsync(ENDMODE.REGEND),this.JSFJTime*1000);//解散倒计时60秒
  2870. }
  2871. // let str3 = "table end 同意结束-id:"+this.id + ",uid"+user.userId+",state"+ this.state;
  2872. // logger.info(str3);////cssj
  2873. return { code: C.OK, data: { chairId: String(chairId),time: this.JSFJTime, jieSanType: 1 }};
  2874. });
  2875. //////TL++,设置记录游戏过程中的记录数据
  2876. proto.setPaijuHuiFangData = function (_operateKind,_data){
  2877. let data = this.logic.deepCloneTL(_data);
  2878. data.operateKind = _operateKind;
  2879. this.PaijuHuiFang[this.PaijuHuiFang.length] = data;
  2880. };
  2881. // 得到玩家位置
  2882. proto.getLocationAsync = cor(function* () {
  2883. let location = [];
  2884. // 桌上玩家
  2885. for (let i = 0; i < this.users.length; ++i) {
  2886. let user = this.users[i];
  2887. if (user) {
  2888. location.push({
  2889. chairId: user.chairId,
  2890. longitude: user.longitude,
  2891. latitude: user.latitude,
  2892. headurl: user.headurl,
  2893. name: user.name
  2894. });
  2895. }
  2896. }
  2897. // console.warn("ts+++++玩家位置",location);
  2898. return { code: C.OK, data: location };
  2899. });