table.js 172 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722
  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').paohuzi || {};
  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. // 构造方法
  33. var Table = function (cPlayerId,cUserId,cName,cHead,game, id, cell, round, type,gameKindTL,playerAllCount,upId,other,agentId,yxndlbTime,yxndlbTip) {
  34. let str3 = "table构造方法.......id: "+id + " type " + type+" game "+game.id;
  35. logger.warn(str3);////cssj
  36. this.app = game.app;
  37. this.gameId = 10004;
  38. this.game = game;
  39. this.id = id;
  40. this.recordid = uuid.v1()+'_'+id;//ts++唯一记录
  41. this.upId = upId;//ts++上局的ID
  42. this.type = type;
  43. this.agentId=agentId;
  44. this.yxndlbTime = yxndlbTime;
  45. this.yxndlbTip = yxndlbTip;
  46. var num_cost = 50;
  47. num_cost =parseInt(COSTS[round]);
  48. this.other = other;//////TL++全名堂时可选游戏规则,非全名堂时没有可选规则
  49. console.warn("222创建房间的other",other,this.other," gameKindTL ",gameKindTL," type " ,type,id);
  50. this.gameKindTL = gameKindTL || 1;//游戏类型 = 1代表全名堂 = 2代表大小子 = 3表示土跑胡
  51. let otherstr = ""+other;
  52. this.fengDingValue = parseInt(otherstr[6])*100;////封顶值:0:不封顶,1:封顶100,2:封顶200,3:封顶300
  53. this.tunshuValue = parseInt(otherstr[5]);////充囤值:0:不充囤,1:充1囤,2:充2囤,3:充3囤,4:充4囤,5:充5囤
  54. let kexuanstr = " 可选规则: ";//
  55. if(this.gameKindTL == 1){
  56. if(parseInt(otherstr[1]) == 1) kexuanstr += " 点灯 ";//(全名堂)
  57. if(parseInt(otherstr[3]) == 1) kexuanstr += " 有丁 ";
  58. if(parseInt(otherstr[4]) == 1) kexuanstr += " 有捉小三 ";
  59. }
  60. else if(this.gameKindTL == 2){
  61. if(parseInt(otherstr[1]) == 1) kexuanstr += " 点灯 ";//(大小子)
  62. }
  63. this.chouPaiShu = 0;
  64. if(playerAllCount == 2) {
  65. if(parseInt(otherstr[2]) == 1) this.chouPaiShu = 20;////抽牌张数:0:不抽牌,1:抽20张牌
  66. }
  67. console.warn("游戏人数 抽牌张数 ",playerAllCount,this.chouPaiShu)
  68. console.warn("游戏类型 = 1代表全名堂 = 2代表大小子 = 3表示土跑胡 "+this.gameKindTL+kexuanstr)
  69. console.warn("封顶值 "+this.fengDingValue)
  70. console.warn("充囤值 "+this.tunshuValue)
  71. this.cost = num_cost;
  72. this.over = 0;
  73. this.round = round;
  74. this.stime = 0;
  75. this.ctime = Date.now();
  76. this.etime = 0;
  77. this.lconfigCommon = null;
  78. // 人数
  79. this.ccount = playerAllCount;//Logic.CHAIR_COUNT;
  80. this.mcount = Logic.CARDS_COUNT;
  81. // 房主
  82. this.ownerChairId = -1;//房主的chairid
  83. this.ownerId = cPlayerId;//房主Id
  84. this.ownerUid = cUserId;//房主的userID
  85. this.ownerName = cName;
  86. this.ownerHeadUrl = cHead;
  87. // 数据
  88. var logic = new Logic(type,gameKindTL,playerAllCount,other);
  89. this.logic = logic;
  90. this.score = new Score(this);
  91. this.handCards = Array(this.ccount);
  92. this.huCards = logic.fillDeep(Array(this.ccount), []);
  93. this.everyCPHX = _.fill(Array(this.ccount), 0);//每个玩家的吃碰胡息
  94. this.everyDongState = _.fill(Array(this.ccount), 0);//每个玩家的钻洞状态,0正常未钻洞,1本局钻洞了,2处于钻洞状态且非本局进洞的,3出洞了
  95. //(1,2状态下都是钻洞状态赢了没分,用两个状态仅仅是为了减少判断运算量,赢了没赢分之后状态变为3,状态3的玩家在重置本局数据时改为0)
  96. this.handHXInfos = Array(this.ccount);//手牌的胡息信息列表
  97. this.users = Array(this.ccount);
  98. this.chBanker = 0;
  99. this.moOrChu = 0;//现在是出牌阶段还是摸牌阶段,0表示都不是,1表示摸2表示出,用于点过之后判断应该是摸牌还是落牌,
  100. this.luo = false;
  101. this.outCards = logic.fillDeep(Array(this.ccount), []);
  102. this.outCard = 0;
  103. this.outerId = -1;
  104. this.moCard = 0;//TL++,为了实现可碰别人摸的牌
  105. this.moChair = -1;//TL++,为了实现判断是否自摸
  106. this.currentId = -1;
  107. this.isCanOut = false;//是否允许玩家手动出牌
  108. this.hutipdata = [{kehuData:[]},{kehuData:[]},{kehuData:[]}]//每个人的胡牌提示
  109. // 包含字,总杠次,保留量
  110. // this.hasWords = !(type & 2);/////TL++zs
  111. // this.hasWords = true;/////是否含有字牌/////TL++
  112. // this.gonCount = 0;
  113. // this.disCounts = [26, 14, 16, 26];/////TL++zs
  114. // this.disCounts = [1,1,1,1,];
  115. // 允许点炮
  116. this.hasEHu = true;///!!(type & 8);
  117. // 一炮多响
  118. this.isMHu = false;//!!(type & 16);
  119. // 允许杠胡
  120. this.hasGHu = true;///!!(type & 32);
  121. // 权限:16-胡,8-杠,4-碰,2-吃,1-等待,0-无
  122. this.masks = _.fill(Array(this.ccount), 0);
  123. this.chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃l牌时吃比数据
  124. //吃自己摸的或者别人打出的牌用上面的变量记录,吃上家摸得牌用下面变量记录
  125. this.chiBiArrxj = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //摸牌者下家吃摸牌者摸的牌时吃比数据
  126. // 等待杠类型,1-普通杠, 2-暗杠, 3-自摸明杠
  127. this.gangType = 0;
  128. this.gangCard = 0;
  129. this.bjsfyjp = false;//本局是否已进牌(庄家起手亮张已放入手中)
  130. this.sfwhkhqypkc = false;//偎牌玩家是否偎后可胡且有牌可出
  131. this.dqkthdwj = -1;//当前可提胡的玩家
  132. this.everysfdycpdt = [true,true,true];//每个玩家是否第一次判断提
  133. this.bckycpdp = 0;//本次可以吃碰的牌,为了给下面的everyGDCPP赋值
  134. //过碰可以吃,过吃不能吃,过碰不能碰,打出不能吃碰 (没有过吃可以碰的情况,因为过吃的时候肯定是过碰的,打出牌也不存在被自己碰的情况)
  135. this.everyGDCPP = [[],[],[]];//本局每个玩家过的吃碰牌,为了实现本局过掉碰此牌 或滑动打出过的牌 之后不可再次碰该牌
  136. // everyGDCPP的元素item是个数组(如item = [101,1]),说明:item[0]表示牌值,item[1]表示过掉类型,=1表滑动打出,=2表过吃,=3表过碰,=4表过吃碰
  137. //改成这种结构是为了实现过碰可以吃
  138. // 抢杠胡、被杠玩家
  139. this.isGangHu = false;
  140. this.paoForm = -1;//提供跑的玩家
  141. // 等待吃类型,1-@**左吃, 2-*@*中吃, 3-@**右吃
  142. this._eatType = 0;
  143. this._bi1Type = 0;
  144. this._bi2Type = 0;
  145. this.liangZi = 0;//当前的亮子(亮张,即摸上来的放在桌面上的牌)
  146. this.autoSysTimer = null;//自动系统操作定时器(比如有提必须提有偎必须偎等等操作自动进行定时器)
  147. this.autoOutTimer = null;
  148. this.bakuaiTimer = null;//延迟八块定时器
  149. this.ycMoTimer = null;//延迟摸牌定时器
  150. this.everyIsAutoOut = _.fill(Array(this.ccount), 0);
  151. // 胡牌者
  152. this.huRes = Array(this.ccount);
  153. this.winner = { lead: -1, chs: [] };
  154. this.paoHuQK = [-1,false,0];//这把跑胡情况,为了处理当前可跑不能胡但是跑完之后能胡的情况[可跑胡玩家,是否是跑胡,跑胡的牌]
  155. // 底分
  156. this.cell = cell;
  157. // 围观者
  158. this.lookers = [];
  159. //结束时的继线用户
  160. this.leaveUsers = [];
  161. // 状态
  162. this.state = STATE.FREE;
  163. // 申请结束标记
  164. this.overFlag = 0;
  165. this.overTimer = null;
  166. this.endTableTime = 60;//////TL++,申请解散房间之后60秒之后不操作则认为同意解散
  167. this.reqJieSan = [-1,-1,-1,-1];/////解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  168. //断线 结束定时器
  169. this.endTimer = null;
  170. //////以下全为TL++
  171. /////TL++,补花定时器,防止连续补花太快
  172. this.PJHF = new paiJuHuiFang();
  173. // this.buhuaTimeout = null;
  174. this.backStartTimer = null;//////重入之后系统会自动准备为了解决可能没牌的问题2秒之后才开始游戏
  175. this.PaijuHuiFang = [];////TL++,牌局回放
  176. // this.zhyzfgs = [-2,null,null];/////TL++,由于最后一张牌的摸牌被打断所以 用来记录最后一张牌的发牌函数的参数
  177. // this.isLianGang = [-1,false,-1];/////TL++,连杠的玩家座位号,是否连杠 杠的牌
  178. this.isYJJSGL = false;/////是否已经执行过结算函数了
  179. this.isYJKSGL = false;/////是否已经执行过开始函数了
  180. this.JSFJTimeout = null;//解散房间倒计时
  181. this.JSFJTime = 60;//解散房间倒计时60秒
  182. this.SQJSTime = null;//申请解散房间的时间,用于计算解散房间倒计时所剩的时间
  183. this.gameNeverStart = true;//游戏是否从未开始过,用于解散房间判断
  184. this.pjhffileName = [];//用于记录玩家牌局回放的json文件名
  185. this.playerPosList = [[],[],[],[]];//记录玩家的位置信息数组
  186. this.playerAllCount = playerAllCount || 3;//游戏人数 = 2表示2人局 = 3表示3人局
  187. this.isNeverStart = true;//游戏是否从未开始
  188. this.sszjDataList = [];//设置实时战绩的数据
  189. // this.isEveryZZ = false;//是否每一个人都做过庄
  190. // this.isZJYG = false;////本局庄家是否有杠
  191. this.chairArry = [0,1,2,3];//
  192. // this.isNeverTounchHU = false;/////是否从未点击过胡按钮
  193. this.sszjs = [];//ts++实时战绩
  194. this.LWKF = [10,10,10,10,10];//////TL++礼物扣费
  195. this.isGameOk=false;//ts++牌局正常结束
  196. this.agentRebate=0;//ts++本局的返利
  197. // delete require.cache[require.resolve('../../share/setReabte')];
  198. // setReabte = require('../../share/setReabte');
  199. this.lsetReabte = new setReabte(this.app);
  200. // this.logic.getIsHu([209,209,209,109,109,109,202,207,210,101,102,103,104,108,106,107,204,204,108,108],108)
  201. // this.logic.getIsHu([101,102,103,104,106,108,106,106,106,108,109,109,109,202,204,204,207,209,209,209,210],108)//测试判胡算法 28544915846122574
  202. // console.warn("??????????????????111");
  203. // this.logic.getIsHu([101,102,103,104,106,107,105,105,105,108,109,109,109,202,204,204,207,209,209,209,210],209)//测试判胡算法 28544915846122574 28544915846122574 29389340776254542 28544563753537139
  204. // console.warn("??????????????????222");
  205. // this.logic.getIsHu([101,102,103,104,106,107,108,108,108,108,109,109,109,202,204,204,207,209,209,209,210],108)//测试判胡算法
  206. // let ccc = [101,102,103,104,105,106,107,109,109,109,202,204,204,205,205,207,209,209,209,210];
  207. // let huRes = this.logic.huAnalyze(0,ccc, 108, [], false,false);
  208. // console.warn("是否可胡 ",JSON.stringify(huRes));
  209. // let Cards = [101,102,102,102,103,106,106,106,107,108,201,202,202,203,203,205,205,206,206,207,208]
  210. // let group1 = _.groupBy(Cards, function (n) { return n })
  211. // console.warn("?????? group1 ",JSON.stringify(group1));
  212. // let ccvv = group1['101'];
  213. // console.warn("?????? ccvv ",JSON.stringify(ccvv),ccvv.length);
  214. // let xx = [[202,207,210],[202,207,210],[102,107,110],[102,107,110],[206,205,204],[104],[105,105],[106,103]];
  215. // let yy = [ 206, 207, 205, 105, 105 ];
  216. // this.logic.removes2(xx,yy)
  217. // console.warn("<<<<<<<<<<<< ",xx);
  218. };
  219. // 导出状态
  220. Table.STATE = STATE;
  221. //ts++ 结束模式
  222. Table.ENDMODE = ENDMODE;
  223. // 导出类
  224. module.exports = Table;
  225. // 原型对象
  226. var proto = Table.prototype;
  227. // 是否站满
  228. proto.isFull = function () {
  229. return (this.lookers.length >= 5);
  230. };
  231. // 是否准备
  232. proto.isReady = function () {
  233. for (let user of this.users) {
  234. if (!user || !user.isReady()) return false;
  235. }
  236. return true;
  237. };
  238. // ts++是否二次准备
  239. proto.isReady2 = function () {
  240. for (let user of this.users) {
  241. if (!user || !user.isReady2()) return false;
  242. }
  243. return true;
  244. };
  245. // 是否游戏中
  246. proto.isPlaying = function () {
  247. return this.state > STATE.FREE;
  248. };
  249. // 是否全在线
  250. proto.isOnline = function () {
  251. for (let user of this.users) {
  252. if (user && user.isOffline()) return false;
  253. }
  254. return true;
  255. };
  256. // 是否全断线
  257. proto.isOffline = function () {
  258. for (let user of this.users) {
  259. if (!user || !user.isOffline()) return false;
  260. }
  261. return true;
  262. };
  263. // 是否空桌
  264. proto.isEmpty = function () {
  265. if (this.lookers.length > 0) return false;
  266. for (let i = 0; i < this.users.length; ++i) {
  267. if (this.users[i]) return false;
  268. }
  269. return true;
  270. };
  271. // 局数完成
  272. proto.isGameOver = function () {
  273. let str3 = "table 局数完成 .......id: "+ this.id + " this.over " + this.over;
  274. logger.warn(str3);////cssj
  275. return (this.over >= this.round);
  276. };
  277. // 重置本局
  278. proto.resetRound = function () {
  279. _.fill(this.handCards, null);
  280. _.fill(this.handHXInfos, null);
  281. _.fill(this.masks, 0);
  282. this.chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  283. this.chiBiArrxj = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //摸牌者下家吃摸牌者摸的牌时吃比数据
  284. this.liangZi = 0;//当前的亮子(亮张,即摸上来的放在桌面上的牌)
  285. this.moOrChu = 0;//现在是出牌阶段还是摸牌阶段,0表示都不是,1表示摸2表示出3表示吃碰杠之后4表示起手发牌之后出牌之前,用于点过之后判断应该是摸牌还是落牌,
  286. this.luo = false;
  287. if (this.autoSysTimer) {
  288. clearTimeout(this.autoSysTimer);
  289. this.autoSysTimer = null;
  290. }
  291. if(this.autoOutTimer)
  292. {
  293. clearTimeout(this.autoOutTimer);
  294. this.autoOutTimer = null;
  295. }
  296. if(this.bakuaiTimer){
  297. clearTimeout(this.bakuaiTimer);
  298. this.bakuaiTimer = null;
  299. }
  300. if(this.ycMoTimer){
  301. clearTimeout(this.ycMoTimer);
  302. this.ycMoTimer = null;
  303. }
  304. this.everyIsAutoOut = _.fill(Array(this.ccount), 0);
  305. _.fill(this.huRes, null);
  306. // this.gonCount = 0;
  307. this.winner.chs = [];
  308. this.winner.lead = -1;
  309. this.paoHuQK = [-1,false,0];//这把跑胡情况,为了处理当前可跑不能胡但是跑完之后能胡的情况[可跑胡玩家,是否是跑胡]
  310. this.logic.fillDeep(this.huCards, []);
  311. this.everyCPHX = _.fill(Array(this.ccount), 0);//每个玩家的吃碰胡息
  312. for (var i = 0; i < this.everyDongState.length; i++) {
  313. if(this.everyDongState[i] == 1) this.everyDongState[i] = 2;
  314. if(this.everyDongState[i] == 3) this.everyDongState[i] = 0;
  315. }
  316. this.logic.fillDeep(this.outCards, []);
  317. this.outCard = 0;
  318. this.outerId = -1;
  319. this.moCard = 0;//TL++,为了实现可碰别人摸的牌
  320. this.currentId = -1;
  321. this.isCanOut = false;//是否允许玩家手动出牌(重置)
  322. this.hutipdata = [{kehuData:[]},{kehuData:[]},{kehuData:[]}]//每个人的胡牌提示
  323. this._eatType = 0;
  324. this._bi1Type = 0;
  325. this._bi2Type = 0;
  326. this.gangType = 0;
  327. this.gangCard = 0;
  328. this.bjsfyjp = false;//本局是否已进牌(庄家起手亮张已放入手中)
  329. this.sfwhkhqypkc = false;//偎牌玩家是否偎后可胡且有牌可出
  330. this.dqkthdwj = -1;//当前可提胡的玩家
  331. this.everysfdycpdt = [true,true,true];//每个玩家是否第一次判断提
  332. this.bckycpdp = 0;//本次可以吃碰的牌,为了给下面的everyGDCPP赋值
  333. this.everyGDCPP = [[],[],[]];//本局每个玩家过的吃碰牌,为了实现本局过掉吃碰此牌之后不可再次吃碰该牌
  334. this.isGangHu = false;
  335. };
  336. // 发送消息
  337. proto.pushMsgAsync = cor(function* (cidOrIds, route, msg) {
  338. // console.warn("444WWWWWWWTTTTTT",cidOrIds, route, msg);
  339. var playerIds = [];
  340. if (Array.isArray(cidOrIds)) playerIds = cidOrIds;
  341. else {
  342. if (cidOrIds < 0 || cidOrIds >= this.users.length) {
  343. for (let user of this.users) {
  344. if (user) playerIds.push(user.id);
  345. }
  346. for (let lker of this.lookers) {
  347. playerIds.push(lker.id);
  348. }
  349. } else {
  350. let user = this.users[cidOrIds];
  351. if (user) playerIds.push(user.id);
  352. // console.warn("555WWWWWWWTTTTTT",cidOrIds, route, user.name);
  353. }
  354. }
  355. if (playerIds.length > 0) {
  356. let channelId = 'xct:' + this.id;
  357. // console.warn("666WWWWWWWTTTTTT",cidOrIds, route, playerIds,msg);
  358. return this.app.controllers.push._pushAsync(channelId, playerIds, route, msg);
  359. }
  360. });
  361. // 围观消息
  362. proto.lookMsgAsync = cor(function* (route, msg) {
  363. var playerIds = [];
  364. for (let lker of this.lookers) {
  365. playerIds.push(lker.id);
  366. }
  367. if (playerIds.length > 0) {
  368. let channelId = 'xct:' + this.id;
  369. return this.app.controllers.push._pushAsync(channelId, playerIds, route, msg);
  370. }
  371. });
  372. // 获得桌子信息
  373. proto.getTableInfo = function () {
  374. // 桌子信息
  375. let endTableTime = Math.floor((this.SQJSTime - Date.now())/1000);
  376. var tableInfo = {
  377. id: this.id,
  378. gameId: this.gameId,
  379. type: this.type,
  380. cost: this.cost,
  381. over: this.over,
  382. round: this.round,
  383. users: [],
  384. lookers: [],
  385. ownerId: -1,//this.ownerChairid
  386. ownerUserId: this.ownerUid,////TL++,房主的userID
  387. ownerName: this.ownerName,//////TL++,房主的昵称
  388. ownerHeadUrl: this.ownerHeadUrl,//////TL++,房主的头像地址
  389. gameKindTL: this.gameKindTL,////游戏类型 = 1代表全名堂 = 2代表大小子 = 3表示土跑胡
  390. playerAllCount: this.playerAllCount,////游戏人数 = 2表示2人局 = 3表示3人局 = 4表示4人局
  391. other: this.other,
  392. creatTime : this.ctime,
  393. nowTime : Date.now(),
  394. state: this.state,
  395. isCanOut: this.isCanOut,//是否允许玩家手动出牌
  396. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  397. everyDongState: this.everyDongState,//每个玩家的钻洞状态,0正常未钻洞,1钻洞中赢了没分
  398. dengshuValue: this.logic.dengshuValue,//-1:未勾选点灯规则,>-1:已勾选点灯规则下剩余的灯数,
  399. sszjDataList: this.sszjDataList,////TL++,设置实时战绩的数据
  400. isZHYZ: this.logic.isZHYZ, /////TL++,是否最后一张
  401. playerPosList: this.playerPosList,/////TL++玩家位置数据
  402. chairArry: this.chairArry,/////TL++
  403. isNeverStart: this.isNeverStart,/////TL++,游戏是否从未开始
  404. overFlag:this.overFlag,//ts++房间解散标识
  405. endTableTime:endTableTime,
  406. recordid:this.recordid,
  407. yxndlbTime:this.yxndlbTime,
  408. yxndlbTip:this.yxndlbTip,
  409. reqJieSan:this.reqJieSan
  410. };
  411. // 正在游戏
  412. var isPlaying = this.isPlaying();
  413. if (isPlaying) {
  414. let zjlzsfkbh = false;//庄家起手亮子是否可被胡,用于判断发牌之后重入要不要显示亮张,如果可胡则显示庄家起手亮张否则不显示
  415. if(this.moOrChu == 4){
  416. zjlzsfkbh = _.findIndex(this.masks, (m) => (m > 0)) != -1;//庄家是否可提
  417. }
  418. tableInfo.banker = this.chBanker;
  419. tableInfo.stime = Date.now() - this.stime;
  420. tableInfo.currentId = this.currentId;
  421. tableInfo.moOrChu = this.moOrChu;//现在是出牌阶段还是摸牌阶段,0表示都不是,1表示摸2表示出,用于点过之后判断应该是摸牌还是落牌,
  422. tableInfo.zjlzsfkbh = zjlzsfkbh;//庄家起手亮子是否可被胡,用于判断发牌之后重入要不要显示亮张,如果可胡则显示庄家起手亮张否则不显示
  423. tableInfo.liangZi = this.liangZi;//当前的亮子(亮张,即摸上来的放在桌面上的牌)
  424. tableInfo.lastCount = this.logic.leaveCount();
  425. tableInfo.isGangHu = this.isGangHu;
  426. tableInfo.gangCard = this.gangCard;
  427. //////TL++,游戏过程中重入
  428. //////TL++ end,游戏过程中重入
  429. }
  430. // 桌上玩家
  431. for (let i = 0; i < this.users.length; ++i) {
  432. let user = this.users[i];
  433. if (user) {
  434. let score = this.score.getScore(user.id);
  435. let uinfo = {
  436. account: user.account, name: user.name, sex: user.sex, headurl: user.headurl,
  437. state: user.state2, score: score, chairId: user.chairId
  438. };
  439. if (isPlaying) {
  440. let huCards = [];
  441. for (let huCard of this.huCards[i]) {
  442. huCards.push({ style: huCard.style, type: huCard.type, card: huCard.card, origin: huCard.origin });
  443. }
  444. uinfo.huCards = huCards;
  445. uinfo.outCards = this.outCards[i];
  446. let handCard = this.handCards[i] || [];
  447. uinfo.handCount = this.logic.getSPZS(handCard);
  448. }
  449. tableInfo.users.push(uinfo);
  450. }
  451. }
  452. // 围观玩家
  453. for (let i = 0; i < this.lookers.length; ++i) {
  454. let user = this.lookers[i];
  455. if (user) {
  456. tableInfo.lookers.push({ account: user.account, name: user.name, sex: user.sex, headurl: user.headurl });
  457. }
  458. }
  459. return tableInfo;
  460. };
  461. // 回到桌子
  462. proto.backAsync = cor(function* (user) {
  463. let str3 = "table回到桌子.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  464. logger.warn(str3);////cssj
  465. user.offlinetime=0;//ts++
  466. var data = { chairId: String(user.chairId) };
  467. var chairId = user.chairId;
  468. let isGuoHuList = [[false,0],[false,0],[false,0],[false,0],];
  469. if (chairId != -1) {
  470. // 加入频道
  471. var connectorId = user.connectorId || '';
  472. if (connectorId) {
  473. let channelId = 'xct:' + this.id;
  474. yield this.app.controllers.push._joinAsync(channelId, user.id, connectorId);
  475. }
  476. // 恢复状态
  477. if (this.state == STATE.FREE) {
  478. yield this.readyGameAsync(user);
  479. } else if (this.state == STATE.PLAYING) {
  480. //user.state = User.STATE.PLAYING;//ts--
  481. user.state2 = User.STATE.PLAYING;//ts++
  482. data.mask = String(this.masks[chairId]);
  483. data.yGDCPP = this.everyGDCPP[chairId];//已过的吃碰牌
  484. let chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  485. if (this.masks[chairId] & 2) {
  486. let mpwjdxj = (this.moChair + 1) % this.ccount;//摸牌玩家的下家
  487. if(this.moOrChu == 1 && mpwjdxj == chairId) chiBiArr = this.chiBiArrxj;
  488. else chiBiArr = this.chiBiArr; //吃牌时吃比数据
  489. }
  490. data.chiBiArr = chiBiArr;
  491. data.handCards = this.handCards[chairId];
  492. // console.warn("handHXInfos ",JSON.stringify(this.handHXInfos));
  493. let handHXInfo = this.logic.deepCloneTL(this.handHXInfos[chairId]);
  494. // console.warn("handHXInfo==== ",JSON.stringify(handHXInfo));
  495. data.handHXInfos = handHXInfo;
  496. // 状态通知
  497. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  498. }else if (this.state == STATE.FREE2) {//ts++二次准备
  499. //user.state = User.STATE.PLAYING;//ts--
  500. user.state2 = User.STATE.READY;
  501. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  502. if (this.isReady2() && !this.isGameOk)
  503. {
  504. if(!this.backStartTimer){
  505. this.backStartTimer = this.app.timer.setTimeout(() => this.backStartTimeAsync(), 2 * 1000);//延迟2秒开始游戏
  506. }
  507. }
  508. }
  509. // 取消计时
  510. if (this.isOnline() && this.endTimer) {
  511. clearTimeout(this.endTimer);
  512. this.endTimer = null;
  513. }
  514. isGuoHuList[chairId] = this.logic.isGuoHuList[chairId];
  515. }
  516. // 数据处理
  517. data.fee = this.score.isFeed(user.id) ? '0' : '1';
  518. data.table = this.getTableInfo();
  519. let hutipdata = {
  520. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  521. };
  522. if(chairId != -1){
  523. data.table.hutipdata = this.hutipdata[chairId]//每个人的胡牌提示
  524. }
  525. else{
  526. data.table.hutipdata = hutipdata;
  527. }
  528. let isAutoOut = 0;
  529. if (chairId != -1) {
  530. isAutoOut = this.everyIsAutoOut[chairId];
  531. }
  532. data.table.isAutoOut = isAutoOut;
  533. data.table.isGuoHuList = isGuoHuList;
  534. return { code: C.OK, data: data };
  535. });
  536. //ts++重入后自动开始
  537. proto.backStartTimeAsync = cor(function* () {
  538. yield this.startGameAsync();
  539. });
  540. // 加入桌子
  541. proto.joinAsync = cor(function* (user) {
  542. // 撤出删除队列
  543. //this.game.cancelDelete(this.id);
  544. // 加入桌子之前
  545. yield this.beforeJoinAsync(user);
  546. // 加入围观者
  547. this.lookers.push(user);
  548. // 加入桌子之后
  549. yield this.afterJoinAsync(user);
  550. // 数据返回处理
  551. var data = { chairId: String(user.chairId) };
  552. data.fee = this.score.isFeed(user.id) ? '0' : '1';
  553. data.table = this.getTableInfo();
  554. return { code: C.OK, data: data };
  555. });
  556. // 加入桌子之前
  557. proto.beforeJoinAsync = cor(function* (user) {
  558. var connectorId = user.connectorId || '';
  559. if (connectorId) {
  560. let channelId = 'xct:' + this.id;
  561. return this.app.controllers.push._joinAsync(channelId, user.id, connectorId);
  562. }
  563. });
  564. // 加入桌子之后
  565. proto.afterJoinAsync = cor(function* (user) {
  566. // 加入通知
  567. return this.pushMsgAsync(-1, 'paohuzi_event', {
  568. type: M.JOIN, data: { account: user.account, userId: user.userId, name: user.name, sex: user.sex, headurl: user.headurl,playerPosList: this.playerPosList }
  569. });
  570. });
  571. // 坐下桌子
  572. proto.seatAsync = cor(function* (user, chairId) {
  573. // let chairId = this.chairArry[_chairId];
  574. // console.warn("坐下桌子不不vvvvvv",chairId,_chairId,this.chairArry,this.users.length);
  575. // 参数校验
  576. if (chairId < 0 || chairId >= this.ccount) {
  577. return { code: C.FAILD, msg: C.CHAIR_NOT_FOUND };
  578. }
  579. if (this.users[chairId]) {
  580. // console.warn("坐下桌子死了vv000",this.users[chairId]);
  581. // console.warn("坐下桌子死了vvvvvv",this.users.length,this.users);
  582. return { code: C.FAILD, msg: C.CHAIR_HAS_SOMEONE };
  583. }
  584. // 查找玩家
  585. var player = yield this.app.models.Player.findByIdAsync(user.id, 'diamond cost');
  586. if (!player) {
  587. return { code: C.FAILD, msg: C.PLAYER_NOT_FOUND };
  588. }
  589. if (this.users[chairId]) {
  590. return { code: C.FAILD, msg: C.CHAIR_HAS_SOMEONE };
  591. }
  592. // 调换座位
  593. if (user.chairId != -1) {
  594. return this.changeChairAsync(user, chairId);
  595. }
  596. // 围观玩家
  597. var pos = _.findIndex(this.lookers, (u) => (u.id == user.id));
  598. if (pos == -1) {
  599. return { code: C.FAILD, msg: C.TABLE_NOT_USER };
  600. }
  601. //ts++
  602. let dSource=player.diamond;
  603. let dNow=player.diamond;
  604. //坐下花费
  605. var costdata = null;
  606. if (!this.score.isFeed(user.id)) {
  607. if (player.diamond < this.cost) {
  608. return { code: C.FAILD, msg: C.GAME_DIAMOND_LOW };
  609. }//////TL++zsyl 1000局测完之后要放出来的
  610. player.diamond -= this.cost;
  611. player.cost = (player.cost || 0) + this.cost;
  612. dNow-=this.cost;
  613. this.score.addUser(user.id,chairId,user.userId, user.name, user.sex, user.headurl,user.diamond,this.gameKindTL);
  614. costdata = { cost: String(this.cost) };
  615. }
  616. // 坐下处理
  617. this.lookers.splice(pos, 1);
  618. this.users[chairId] = user;
  619. user.chairId = chairId;
  620. user.state = User.STATE.READY;
  621. yield this.afterSeatAsync(user);
  622. if (player.isModified())
  623. {
  624. yield player.saveAsync();/////只有第一次坐下的时候才会执行
  625. // 钻石记录
  626. var diamondrecord = new this.app.models.DiamondRecord({
  627. _id: uuid.v1(),
  628. playerId: user.id,
  629. dType: 3,//坐下
  630. dSource: dSource,
  631. dSwap: -1*this.cost,
  632. dNow: dNow,
  633. tableId: this.recordid
  634. });
  635. yield diamondrecord.saveAsync();
  636. // console.warn("ts++坐下-------------------钻石记录");
  637. if (costdata) yield this.pushMsgAsync(chairId, 'paohuzi_event', { type: M.COST_FEE, data: costdata });
  638. }
  639. // if (this.isReady()) yield this.pushMsgAsync(this.ownerChairid, 'paohuzi_event', { type: M.START_BUTTON });//////TL++zsyl所有人准备之后通知房主点击开始游戏
  640. if (this.state == STATE.FREE && this.isReady() && !this.isGameOk) {
  641. yield this.randomChangeChairTL();
  642. }
  643. return { code: C.OK, chairId: String(chairId) };
  644. });
  645. // 调换座位 自己坐下之后点击另外一个位子的时候调用这个方法 这个参数user输出之后相当的长
  646. proto.changeChairAsync = cor(function* (user, chairId) {
  647. if (this.state != STATE.FREE) {
  648. return { code: C.FAILD, msg: C.TABLE_NOT_FREE };
  649. }
  650. if (this.users[chairId]) {
  651. return { code: C.FAILD, msg: C.CHAIR_HAS_SOMEONE };
  652. }
  653. return { code: C.OK, chairId: String(chairId) };
  654. });
  655. // 坐下桌子之后
  656. proto.afterSeatAsync = cor(function* (user) {
  657. let posListTL = {
  658. chairId: user.chairId,
  659. headurl: user.headurl,
  660. longitude: user.longitude, // 经度,浮点数,范围为180 ~ -180。
  661. latitude: user.latitude, // 纬度,浮点数,范围为90 ~ -90
  662. }
  663. this.playerPosList[user.chairId] = posListTL/////TL++记录玩家的位置信息数组
  664. // 坐下通知
  665. let score = this.score.getScore(user.id);
  666. yield this.pushMsgAsync(-1, 'paohuzi_event', {///////发送坐下
  667. type: M.SEAT, data: {
  668. account: user.account,
  669. name: user.name,
  670. sex: user.sex,
  671. headurl: user.headurl,
  672. state: String(user.state),
  673. score: String(score),
  674. chairId: String(user.chairId),
  675. userId: String(user.userId),
  676. playerPosList: this.playerPosList, /////TL++记录玩家的位置信息数组
  677. }
  678. });
  679. });
  680. //////TL++,在首次游戏开始的时候随机打乱用户的座位
  681. proto.randomChangeChairTL = cor(function* () {
  682. // console.warn("111在首次游戏开始的时候随机打乱用户的座位",this.users[0].name,this.users[1].name,this.users[2].name,this.users[3].name);
  683. // console.warn("1在首次游戏开始的时候随机打乱用户的座位",this.users[0].chairId,this.users[1].chairId,this.users[2].chairId,this.users[3].chairId);
  684. if(this.playerAllCount > 2){
  685. let changeResult = [];
  686. if (this.over <= 0) {///////本房间开始的第一局游戏
  687. // for (let i = 0; i < this.ccount; i++) {/////这种随机4次可能会导致4次随机之后和打乱之前的顺序一样所以弃用
  688. for (let i = 0; i < 1; i++) {
  689. let oldchaieID = i;
  690. let olduser = this.users[i];
  691. let newchaieID = Math.floor(Math.random()*this.playerAllCount);////// 区间[0,3]取整数
  692. while (newchaieID == oldchaieID) {
  693. newchaieID = Math.floor(Math.random()*this.playerAllCount);////// 区间[0,3]取整数
  694. }
  695. let newuser = this.users[newchaieID];
  696. // console.warn("222在首次游戏开始的时候随机打乱用户的座位",oldchaieID,newchaieID);
  697. // console.warn("xxxxxxxxx删除有没有用啊",this.users.length);
  698. delete this.users[newchaieID];
  699. delete this.users[oldchaieID];
  700. // console.warn("xxxxxxxxx22删除有没有用啊",this.users.length);
  701. this.users[newchaieID] = olduser;
  702. this.users[newchaieID].chairId = newchaieID;
  703. // this.users[newchaieID].id = newuser.id;
  704. this.users[oldchaieID] = newuser;
  705. this.users[oldchaieID].chairId = oldchaieID;
  706. // this.users[oldchaieID].id = olduser.id;
  707. changeResult.push([oldchaieID,newchaieID])
  708. }
  709. /////TL++
  710. for (let i = 0; i < this.users.length; ++i) {
  711. this.score.setUserChair(this.users[i].id,this.users[i].chairId)
  712. }
  713. let daluanData = [];
  714. var isPlaying = this.isPlaying();
  715. for (let i = 0; i < this.users.length; ++i) {
  716. let user = this.users[i];
  717. if (user) {
  718. let score = this.score.getScore(user.id);
  719. let uinfo = {
  720. account: user.account, name: user.name, sex: user.sex, headurl: user.headurl,
  721. state: user.state, score: score, chairId: user.chairId
  722. };
  723. if (isPlaying) {
  724. let huCards = [];
  725. for (let huCard of this.huCards[i]) {
  726. huCards.push({ style: huCard.style, type: huCard.type, card: huCard.card, origin: huCard.origin });
  727. }
  728. uinfo.huCards = huCards;
  729. uinfo.outCards = this.outCards[i];
  730. let handCard = this.handCards[i] || [];
  731. uinfo.handCount = handCard.length;
  732. }
  733. daluanData.push(uinfo);
  734. }
  735. }
  736. // this.score.delUser(user.id);
  737. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.CHAIR_DALUAN, data: { daluanData:daluanData } });
  738. }
  739. }
  740. // console.warn("444在首次游戏开始的时候随机打乱用户的座位",changeResult);
  741. // this.starTimer = this.app.timer.setTimeout(() => this.startGameAsync(), 500);
  742. yield this.startGameAsync()/////TL++,在首次游戏的时候随机打乱用户的座位
  743. });
  744. // 站起桌子
  745. proto.standAsync = cor(function* (user) {
  746. let str3 = "table 站起桌子.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  747. logger.warn(str3);////cssj
  748. var chairId = user.chairId;
  749. if (chairId != -1) {
  750. user.state = User.STATE.FREE;
  751. delete this.users[chairId];
  752. delete this.handCards[chairId];
  753. user.chairId = -1;
  754. this.lookers.push(user);
  755. yield this.afterStandAsync(user, chairId);
  756. }
  757. return { code: C.OK };
  758. });
  759. // 站起桌子之后
  760. proto.afterStandAsync = cor(function* (user, chairId) {
  761. // 站起通知
  762. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.STAND, data: { chairId: String(chairId) } });
  763. /////TL++,作坐下的玩家离开桌子之后将他的位置信息从位置列表里面删除
  764. if(chairId != -1) this.playerPosList[chairId] = [];
  765. //是否退费
  766. // console.warn("ts++++++++站起桌子之后");
  767. var scorer = this.score.getUser(user.id);
  768. if (scorer && scorer.over <= 0) {
  769. // console.warn("ts++没有开始游戏退分",user.id);
  770. this.score.delUser(user.id);
  771. let player = yield this.app.models.Player.findByIdAsync(user.id, 'diamond cost');
  772. if (player) {
  773. // console.warn("ts++没有开始游戏退分",player.diamond);
  774. let dSource=player.diamond;
  775. let dNow=player.diamond+this.cost;
  776. player.diamond += this.cost;
  777. player.cost -= this.cost;
  778. yield player.saveAsync();
  779. // 退费 钻石记录
  780. var diamondrecord = new this.app.models.DiamondRecord({
  781. _id: uuid.v1(),
  782. playerId: user.id,
  783. dType: 4,//退费
  784. dSource: dSource,
  785. dSwap: this.cost,
  786. dNow: dNow,
  787. tableId: this.recordid
  788. });
  789. yield diamondrecord.saveAsync();
  790. // console.warn("ts++退分-------------------钻石记录");
  791. }
  792. }
  793. else
  794. {
  795. if(user.cost==0 && user.spreadId)//ts++推荐人奖励
  796. {
  797. ////20200928因为现在的spreadId存的是userId,所以上面那段用不了了
  798. if(!this.lconfigCommon) {
  799. // console.warn("邀请新人送钻石活动 this.lconfigCommon 不存在 "+this.etime);
  800. this.lconfigCommon = new configCommon(this.app);
  801. }
  802. let yxhdxx = this.lconfigCommon.getActiveOpenTime(1);//邀请新人送钻石活动是否开启和开始结束时间的信息
  803. let isKQ = false;//邀请新人送钻石活动是否开启
  804. if(yxhdxx && yxhdxx.open && yxhdxx.startTime && yxhdxx.endTime) isKQ = true;
  805. // console.warn("获取配置信息 yxhdxx "+JSON.stringify(yxhdxx));
  806. if(isKQ && this.etime >= yxhdxx.startTime && this.etime < yxhdxx.endTime){
  807. var cpopts = {};
  808. cpopts['userId'] = parseInt(user.spreadId);
  809. let spreadList = yield this.app.models.Player.findMongoAsync(cpopts, 'spreadCount spreadRebate', { sort: { stime: 1 } });//
  810. if(spreadList.length == 1){
  811. spreadList[0].spreadCount += 1;
  812. spreadList[0].spreadRebate += 100;
  813. yield spreadList[0].saveAsync();
  814. }
  815. }
  816. }
  817. yield this.lsetReabte.updateDaterebateRecord(this.agentId,this.etime);
  818. }
  819. });
  820. // 玩家断线
  821. proto.offlineAsync = cor(function* (user) {
  822. let str3 = "table 玩家断线.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  823. logger.warn(str3);////cssj
  824. if (user.chairId != -1) {
  825. //user.state = User.STATE.OFFLINE;//ts--
  826. user.state2 = User.STATE.OFFLINE;//ts++
  827. user.offlinetime = Date.now();//ts++断线
  828. var channelId = 'xct:' + this.id;
  829. yield this.app.controllers.push._quitAsync(channelId, user.id);
  830. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  831. // 计时结算
  832. if (!this.endTimer) this.endTimer = this.app.timer.setTimeout(() => this.overTimeAsync(ENDMODE.OFFLINEEND),600000);/////断线10分钟自动结算
  833. // let str4 = "table 玩家断线---id:"+this.id + ",uid"+user.userId+" "+ this.state;
  834. // logger.info(str4);////cssj
  835. }
  836. });
  837. // 离开桌子
  838. proto.leaveAsync = cor(function* (user) {
  839. let str3 = "table 离开桌子.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  840. logger.warn(str3);////cssj
  841. // this.leavePlayerID = user.id;//////TL++,旁观为房主的话离开之后由于从观战者列表里面删除了,导致发消息的时候他收不到离开桌子的消息
  842. // console.warn("离开桌子、、、、、、、");
  843. yield this.beforeLeaveAsync(user);
  844. var chairId = user.chairId;
  845. // yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.LEAVE, data: { account: user.account } });/////TL++zs,原来在下面
  846. if (chairId != -1) {
  847. delete this.users[chairId];
  848. delete this.handCards[chairId];
  849. yield this.afterStandAsync(user, chairId);
  850. } else {
  851. let pos = _.findIndex(this.lookers, (u) => (u.id == user.id));
  852. if (pos != -1) this.lookers.splice(pos, 1);
  853. }
  854. return this.afterLeaveAsync(user);
  855. });
  856. // 离开桌子之前
  857. proto.beforeLeaveAsync = cor(function* (user) {
  858. var channelId = 'xct:' + this.id;
  859. return this.app.controllers.push._quitAsync(channelId, user.id);
  860. });
  861. // 离开桌子之后
  862. proto.afterLeaveAsync = cor(function* (user) {
  863. // 离开通知
  864. /////TL++zsyl 在此之前离开玩家已经从玩家列表或者旁观者列表中删除了所以把下面这句提到前面去了
  865. return this.pushMsgAsync(-1, 'paohuzi_event', { type: M.LEAVE, data: { account: user.account } });
  866. });
  867. // 玩家准备
  868. proto.readyGameAsync = cor(function* (user) {
  869. let str3 = "table 玩家准备.......id: "+ this.id + " user.chairId: " + user.chairId + " this.over: " + this.over + " user.name: " + user.name ;
  870. logger.warn(str3);////cssj
  871. // let str3 = "table 玩家准备---id:"+this.id + ",uid"+user.userId+","+ this.state;
  872. // logger.info(str3);////cssj
  873. if(this.state==STATE.FREE2)//ts++二次空闲
  874. {
  875. user.state2 = User.STATE.READY;
  876. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  877. if (this.isReady2() && !this.isGameOk) yield this.startGameAsync();
  878. }
  879. else
  880. {
  881. user.state = User.STATE.READY;
  882. user.state2 = User.STATE.READY;
  883. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.STATE_CHANGE, data: { chairId: String(user.chairId), state: String(user.state2), state2: String(user.state2) } });
  884. // console.warn("玩家准备玩家准备玩家准备 ",this.isReady() ,this.isGameOver());
  885. if (this.isReady() && !this.isGameOk) yield this.startGameAsync();
  886. }
  887. // let str4 = "table 222玩家准备---id:"+this.id + ",uid"+user.userId+","+ this.state;
  888. // logger.info(str4);////cssj
  889. return { code: C.OK };
  890. });
  891. // 开始游戏
  892. proto.startGameAsync = cor(function* () {
  893. //this.backStartTimer = null;//////重入之后系统会自动准备为了解决可能没牌的问题2秒之后才开始游戏
  894. let str4 = "table 开始游戏---id:"+this.id +" ,state "+ this.state +" 当前局 "+ (this.over+1);
  895. logger.warn(str4);////cssj
  896. if(this.isYJKSGL){
  897. return;
  898. }
  899. this.isYJKSGL = true;/////是否已经执行过开始函数了
  900. this.isYJJSGL = false;/////是否已经执行过结算函数了
  901. if(this.backStartTimer)
  902. {
  903. clearTimeout(this.backStartTimer);
  904. this.backStartTimer = null;
  905. }
  906. // 状态设置
  907. this.state = STATE.PLAYING;
  908. //this.setUserState(-1, User.STATE.PLAYING);//ts--
  909. //ts++设置为游戏状态
  910. for (let user of this.users)
  911. {
  912. if (user) {
  913. if(user.state == User.STATE.PLAYING)//ts++已经开始
  914. {
  915. if(user.state2 == User.STATE.READY)
  916. {
  917. user.state2 = User.STATE.PLAYING
  918. user.offlinetime = 0;
  919. }
  920. }
  921. else//ts++第一次开始
  922. {
  923. user.state = User.STATE.PLAYING
  924. user.state2 = User.STATE.PLAYING
  925. user.offlinetime = 0;
  926. }
  927. }
  928. }
  929. //ts++end
  930. let whdata = yield this.app.models.WHstate.findByIdReadOnlyAsync('wh', 'rebaterate yxndlbTime yxndlbTip');
  931. // console.warn("22检查是否维护状态",whdata);
  932. if (whdata) {
  933. if(whdata.yxndlbTime) this.yxndlbTime = whdata.yxndlbTime;
  934. if(whdata.yxndlbTip) this.yxndlbTip = whdata.yxndlbTip;
  935. }
  936. this.PaijuHuiFang = [];////TL++,牌局回放 重置数据
  937. this.lgkhCount = 0;/////TL++拉杠可胡玩家的数量
  938. this.logic.isZHYZ = false;/////是不是最后1张
  939. // 初始信息
  940. if (this.over <= 0) {///////本房间开始的第一局游戏
  941. this.stime = Date.now();
  942. // this.chBanker = this.ownerChairid;///////TL++zsyl
  943. this.chBanker = 0;
  944. //this.game.cancelDelete(this.id);//////TL++游戏第一次开始时候关闭房间20分钟未开始删除桌子
  945. this.pjhffileName[this.pjhffileName.length] = this.PJHF.getjsonFileName(0,this.recordid,this.ctime);/////TL++,用于记录玩家牌局回放的json文件名
  946. // console.error("000HHHHHHHHHHHHHHHHHHHHHH",this.pjhffileName.length,this.pjhffileName);
  947. this.PJHF.writePJHFJson(this.getTableInfo(),0,this.id);////在开始第一局的时候将桌子信息写入本地的json文件
  948. this.isNeverStart = false;/////TL++,游戏是否从未开始
  949. // yield this.randomChangeChairTL()/////TL++,在首次游戏的时候随机打乱用户的座位
  950. }
  951. this.gameNeverStart = false;/////TL++,游戏是否从未开始过,用于解散房间判断
  952. this.currentId = this.chBanker;
  953. var handCards = this.logic.handCards(this.chBanker,this.PJHF,this.over,this.recordid,this.ctime);
  954. let scoreListTL = []
  955. for (let i = 0; i < this.users.length; ++i) {
  956. let user = this.users[i];
  957. if (user) {
  958. let score = this.score.getScore(user.id);
  959. scoreListTL[i] = score
  960. }
  961. }
  962. // 掷骰子
  963. var sttGame = {
  964. banker: String(this.chBanker),
  965. stime: String(Date.now() - this.stime),
  966. setCardFileName: String(this.logic.setCardFileName),////TL++设置手牌的文件名
  967. scoreListTL:scoreListTL,/////TL++,每个玩家当前的分数列表
  968. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  969. everyDongState: this.everyDongState,//每个玩家的进洞状态
  970. dengshuValue: this.logic.dengshuValue,//-1:未勾选点灯规则,>-1:已勾选点灯规则下剩余的灯数,
  971. yxndlbTime:this.yxndlbTime,
  972. yxndlbTip:this.yxndlbTip,
  973. };
  974. // console.warn("游侠开始*******************this.chBanker",this.chBanker);
  975. this.setPaijuHuiFangData(M.START_GAME,sttGame);/////TL++ 牌局回放 push游戏开始
  976. // 开始通知
  977. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.START_GAME, data: sttGame });
  978. var moCard = { card: 0 };
  979. moCard = this.logic.moCard();
  980. this.logic.moPaiTL();
  981. this.liangZi = moCard.card;
  982. this.moChair = this.chBanker;//TL++,为了实现判断是否自摸
  983. var lastCount = this.logic.leaveCount();/////TL++
  984. let fpssfyrkh = false;//发牌时是否有人可胡
  985. for (let i = 0; i < handCards.length; ++i) {
  986. let isTouch = (i == this.chBanker);
  987. let huRes2 = this.logic.huAnalyze(i,handCards[i].cards, moCard.card, this.huCards[i], isTouch,true);
  988. // console.warn("发牌时这是判断所有玩家是否能胡=== ",i,huRes2,handCards[i].cards);
  989. if (!huRes2) {
  990. //庄家的三提五坎判断要在手牌里加入庄家亮张,闲家的三提五坎的判断不能把庄家亮子算在里面
  991. huRes2 = this.logic.stwkAnalyze(i,handCards[i].cards, moCard.card, this.huCards[i], isTouch,isTouch);
  992. }
  993. if (huRes2) {
  994. this.huRes[i] = huRes2;
  995. this.masks[i] |= 16;
  996. let isstwk = false;
  997. //下面这个if为了实现三提五坎不允许过胡
  998. if(this.logic.isFPJD()){
  999. let addzh = this.logic.arr2ToArr1(handCards[i].cards,false);
  1000. if(isTouch){
  1001. addzh = addzh.concat(moCard.card);/////不是自己抓的就把这张牌拼接进手牌中
  1002. addzh = this.logic.sort(addzh);
  1003. }
  1004. let spcards2 = this.logic.groupCards(addzh);
  1005. // console.warn("MMMMM+++++++++++++= ",spcards2,handCards[i].cards);
  1006. if(this.logic.isSANTIWUKAN(spcards2, this.huCards[i],[],[])){
  1007. isstwk = true;
  1008. }
  1009. }
  1010. // console.warn(">>>>>>>>>>>>>. ",isstwk);
  1011. if(!isstwk) this.masks[i] |= 64;
  1012. fpssfyrkh = true;
  1013. }
  1014. }
  1015. this.isCanOut = false;//是否允许玩家手动出牌(发牌)
  1016. for (let i = 0; i < handCards.length; ++i) {
  1017. this.handCards[i] = handCards[i].cards;/////TL++zsyl
  1018. this.handHXInfos[i] = handCards[i].hxinfo;/////TL++zsyl
  1019. let scards = {
  1020. mask: String(this.masks[i]),
  1021. isCanOut: this.isCanOut,//是否允许玩家手动出牌
  1022. touch: moCard.card,
  1023. cards: this.handCards[i],
  1024. hxInfos: this.handHXInfos[i],
  1025. lastCount: String(lastCount)
  1026. };
  1027. // 发牌通知
  1028. // console.error("sscc发牌通知 4条应该=================",i,handCards.lengt);
  1029. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.SEND_CARD, data: scards });
  1030. }
  1031. let pjhfsplist = {
  1032. shouPai:this.logic.deepCloneTL(this.handCards),
  1033. handHXInfos:this.logic.deepCloneTL(this.handHXInfos),
  1034. touch: moCard.card,
  1035. maskList:this.logic.deepCloneTL(this.masks),/////TL++,10月28号,为了实现能看到每个玩家的操作
  1036. lastCount:String(this.logic.leaveCount())
  1037. }
  1038. this.setPaijuHuiFangData(M.SEND_CARD,pjhfsplist);/////TL++ 牌局回放 push发牌数据
  1039. // 围观通知
  1040. var cardCounts = _.fill(Array(this.ccount), 0);
  1041. for (let i = 0; i < cardCounts.length; ++i) {
  1042. cardCounts[i] = this.logic.getSPZS(this.handCards[i]);
  1043. }
  1044. let lookerData = { cardCounts: cardCounts, lastCount: String(lastCount), touch: moCard.card };
  1045. yield this.lookMsgAsync('paohuzi_event', { type: M.SEND_CARD, data: lookerData });
  1046. this.moOrChu = 4;//现在是出牌阶段还是摸牌阶段,0表示都不是,1表示摸2表示出3表示吃碰杠之后4表示起手发牌之后出牌之前,用于点过之后判断应该是摸牌还是落牌,
  1047. let str3 = "table 222开始游戏---id:"+this.id +","+ this.state;
  1048. logger.warn(str3);////cssj
  1049. if(!fpssfyrkh){//发牌时是否有人可胡
  1050. let ycsj = 3500;//开始动画1秒,洗牌动画1秒,手牌上移的发牌动画0.5秒,庄家起手亮张的摸牌动画0.5秒,亮张展示时间0.5秒
  1051. this.app.timer.setTimeout(() => this.jinCardAsync(), ycsj);
  1052. }
  1053. return { code: C.OK };
  1054. });
  1055. // 进牌(发牌时庄家亮的那张牌进到庄家手里,仅在没有人胡那张牌或者弃胡之后才会调用这个)
  1056. //type=1时判断玩家提胡操作,type=2时操作这张牌进入庄家手里或庄家提
  1057. proto.jinCardAsync = cor(function* () {
  1058. this.bjsfyjp = true;//本局是否已进牌(庄家起手亮张已放入手中)
  1059. let str3 = "table 进牌---id:"+this.id + " ,uid "+this.chBanker+" card "+this.liangZi;
  1060. logger.warn(str3);////cssj
  1061. //只有发牌时别人都不能胡时这张牌(card)才能进入庄家手里,
  1062. //其余情况任何人摸得任何牌都不会进入任何人手里(可以进入某人的吃碰跑牌里)
  1063. let res = this.logic.addACardToCards(this.handCards[this.chBanker],this.liangZi);
  1064. this.handCards[this.chBanker] = _.cloneDeep(res.handCards);
  1065. this.handHXInfos[this.chBanker] = _.cloneDeep(res.handHXInfos);
  1066. //至此是发牌时没有人能胡,下面是判断庄家是否能提,此时不会形成偎牌,庄家亮的那张牌可以和手牌组成坎
  1067. let bankerGangeRes = [];
  1068. let newCards = this.logic.arr2ToArr1(this.handCards[this.chBanker],true);
  1069. bankerGangeRes = this.logic.anGangAnalyze(newCards);
  1070. // console.warn("庄家起手亮张可提的结果 ",bankerGangeRes);
  1071. let isGang = (bankerGangeRes.length > 0);
  1072. if (isGang) this.masks[this.chBanker] |= 8;
  1073. let zjsfkt = _.findIndex(this.masks, (m) => (m & 8));//庄家是否可提
  1074. if(zjsfkt == -1) this.isCanOut = true;//是否允许玩家手动出牌(发牌)
  1075. for (let i = 0; i < this.handCards.length; ++i) {
  1076. let scards = {
  1077. mask: String(this.masks[i]),
  1078. isCanOut: this.isCanOut,//是否允许玩家手动出牌
  1079. touch: this.liangZi,
  1080. };
  1081. // ////发牌的胡牌提示
  1082. if (i == this.chBanker) {
  1083. scards.cards = this.handCards[i];
  1084. scards.hxInfos = this.handHXInfos[i];
  1085. ////游戏开始时候的庄家的胡牌提示
  1086. this.hutipdata[i] = this.logic.hutip(this.chBanker,this.handCards[i],this.huCards[i],this.huCards,this.outCards);//每个人的胡牌提示
  1087. scards.hutipdata = this.hutipdata[i];//起手发牌调用胡牌提示
  1088. }
  1089. else{
  1090. this.hutipdata[i] = this.logic.hutip2(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);//每个人的胡牌提示
  1091. scards.hutipdata = this.hutipdata[i];//起手发牌调用胡牌提示
  1092. }
  1093. // 进牌通知
  1094. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.PAOHUZI_JIN, data: scards });
  1095. }
  1096. // 围观通知
  1097. var cardCounts = _.fill(Array(this.ccount), 0);
  1098. for (let i = 0; i < cardCounts.length; ++i) {
  1099. cardCounts[i] = this.logic.getSPZS(this.handCards[i]);
  1100. }
  1101. let lookerData = { cardCounts: cardCounts, isCanOut: this.isCanOut, touch: this.liangZi };
  1102. yield this.lookMsgAsync('paohuzi_event', { type: M.PAOHUZI_JIN, data: lookerData });
  1103. let pjhfsplist = {
  1104. mask: String(this.masks[this.chBanker]),
  1105. touch: this.liangZi,
  1106. cards:this.handCards[this.chBanker],
  1107. hxInfos:this.handHXInfos[this.chBanker],
  1108. }
  1109. this.setPaijuHuiFangData(M.PAOHUZI_JIN,pjhfsplist);/////TL++ 牌局回放 push发牌数据
  1110. if(zjsfkt != -1){
  1111. let gcard = bankerGangeRes[0].card;//this.liangZi;////暗杠可以不传card
  1112. yield this.autoSysOperate(500,zjsfkt,"ti",gcard,bankerGangeRes[0].type);
  1113. }
  1114. return { code: C.OK };
  1115. });
  1116. // 调整牌
  1117. proto.adjustCardAsync = cor(function* (chairId, isfy,card,oldIndex,newIndex) {
  1118. let str3 = "table 调整牌---id:"+this.id + " ,uid "+chairId+" card "+card+" isfy "+isfy+" oldIndex "+ oldIndex +" newIndex "+ newIndex;
  1119. logger.warn(str3);////cssj
  1120. // 调整手牌
  1121. let ylspcount = this.logic.getSPZS(this.handCards[chairId]);//调整前原来手牌数量
  1122. let res = {};
  1123. if (!isfy){//是否复原形式调整牌,若是则不需要传上面那些参数
  1124. res = this.logic.changeRes(this.handCards[chairId],this.handHXInfos[chairId],card,oldIndex,newIndex);
  1125. }
  1126. else{
  1127. res = this.logic.changeRes2(this.handCards[chairId]);
  1128. }
  1129. let ocard = {
  1130. chairId: String(chairId),
  1131. changeRes: res.changeRes,
  1132. };
  1133. if(res.changeRes == 0){
  1134. let xzspcount = this.logic.getSPZS(this.handCards[chairId]);//调整前原来手牌数量
  1135. if(ylspcount == xzspcount){//加这个if是为了防止上面代码执行中手牌发生比如偎提跑导致改变
  1136. this.handCards[chairId] = _.cloneDeep(res.handCards);
  1137. this.handHXInfos[chairId] = _.cloneDeep(res.handHXInfos);
  1138. }
  1139. ocard.cards = this.handCards[chairId];
  1140. ocard.hxInfos = this.handHXInfos[chairId];
  1141. ocard.hutipdata = this.hutipdata[chairId];
  1142. }
  1143. // console.warn("调整牌之后 返回给前端 ",ocard);
  1144. // 调整牌通知
  1145. yield this.pushMsgAsync(chairId, 'paohuzi_event', { type: M.ADJUST_CARD, data: ocard });
  1146. return { code: C.OK };
  1147. });
  1148. // 获得是否允许手动出牌
  1149. proto.getIsCanOut = cor(function* () {
  1150. console.warn("是否允许手动出牌 ",this.isCanOut);
  1151. return {isCanOut: this.isCanOut};
  1152. });
  1153. // 出牌(这个方法仅仅前端滑动出牌时被调用)
  1154. proto.outCardAsync = cor(function* (chairId, card,oldIndex) {
  1155. let str3 = "table 出牌---id:"+this.id + " ,uid "+chairId+" currentId "+ this.currentId+" masks "+ this.masks +" card "+card+" oldIndex "+oldIndex;
  1156. logger.warn(str3);////cssj
  1157. // console.warn("出牌出剖出牌",chairId,this.buhuaTimeout);///// 您正在补花,请稍后出牌。/////TL++,正在补花的时候不允许玩家出牌
  1158. // if(this.buhuaTimeout) return { code: C.FAILD, msg: C.GAME_BUHUA_ING };
  1159. // 校验顺序
  1160. if (this.currentId != chairId) {
  1161. return { code: C.FAILD, msg: C.TABLE_TURN_ERROR };
  1162. }
  1163. if(this.autoOutTimer)
  1164. {
  1165. clearTimeout(this.autoOutTimer);
  1166. this.autoOutTimer = null;
  1167. }
  1168. // 吃椪杠胡
  1169. var pos = _.findIndex(this.masks, (m, i) => (i != chairId && m > 0));
  1170. if (pos != -1) {
  1171. return { code: C.FAILD, msg: C.TABLE_TURN_ERROR };
  1172. }
  1173. // 删除手牌之后调整手牌
  1174. let scres = this.logic.removeACardByPos(this.handCards[chairId],this.handHXInfos[chairId],card,oldIndex);
  1175. if(scres.changeRes == 0){
  1176. this.handCards[chairId] = _.cloneDeep(scres.handCards);
  1177. this.handHXInfos[chairId] = _.cloneDeep(scres.handHXInfos);
  1178. }
  1179. else{
  1180. return { code: C.FAILD, msg: C.TABLE_CARD_ERROR, changeRes: scres.changeRes };
  1181. }
  1182. this.luo = false;
  1183. this.moOrChu = 2;//现在是出牌阶段还是摸牌阶段,0表示都不是,1表示摸2表示出,用于点过之后判断应该是摸牌还是落牌,
  1184. this.liangZi = card;
  1185. this.isCanOut = false;//是否允许玩家手动出牌(出牌)
  1186. this.logic.chuPaiTL()////TL++,统计出牌个数,为了判断天胡和地胡
  1187. // 置空权限
  1188. if (this.masks[chairId] > 0) this.masks[chairId] = 0;
  1189. this.outCard = card;
  1190. this.outerId = chairId;
  1191. this.dqkthdwj = -1;
  1192. // 判断出牌里是否有人可杠
  1193. let sfyrkg = false;//是否有人可杠,有人可杠的话就不用判断其他人的吃碰了
  1194. for (let i = 0; i < this.ccount; ++i) {
  1195. // 排除自己
  1196. if (i == chairId || sfyrkg) continue;
  1197. let isGang = false;
  1198. do {
  1199. let res = this.logic.gangAnalyze(this.handCards[i], card);//处理跑牌情况6
  1200. isGang = !!res;
  1201. if(!isGang) {
  1202. let brnewCards = this.logic.arr2ToArr1(this.handCards[i],true);
  1203. let brres = this.logic.zmGangAnalyze3(brnewCards, this.huCards[i],card);//处理跑牌情况5
  1204. if(brres.length == 1){
  1205. res = brres[0];
  1206. isGang = !!res;
  1207. }
  1208. }
  1209. } while (0);
  1210. if (isGang) sfyrkg = true;
  1211. }
  1212. var kgdr = -1;//可杠的人
  1213. var kglx = -1;//可杠类型
  1214. let chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  1215. // 判断出牌里别人吃碰杠
  1216. for (let i = 0; i < this.ccount; ++i) {
  1217. // 排除自己
  1218. if (i == chairId) continue;
  1219. let _isChi = false;
  1220. let isPeng = false;
  1221. let isGang = false;
  1222. do {
  1223. // console.warn("出牌忽略牌 走到这里了 this.everyGDCPP ",this.everyGDCPP);
  1224. let cphsfwpkc = this.logic.getSFWPKC(this.handCards[i],this.handHXInfos[i]);//吃碰之后是否无牌可出
  1225. // 忽略牌
  1226. if (!sfyrkg && !cphsfwpkc){/////TL++zsyl.过吃碰之后不能再次吃碰的
  1227. let gdsfkc = this.logic.getIsCanCP(this.everyGDCPP[i],card,1);//过掉是否可吃
  1228. let gdsfkp = this.logic.getIsCanCP(this.everyGDCPP[i],card,2);//过掉是否可碰
  1229. // 检测吃牌
  1230. if (gdsfkc && i == (chairId + 1) % this.ccount) {
  1231. let ress = this.logic.chiAnalyze(this.handCards[i], card);
  1232. _isChi = (ress.length > 0);
  1233. // console.warn("出牌调用判断吃111 ",card,_isChi,ress);
  1234. }
  1235. // 检测碰牌
  1236. if(gdsfkp && this.logic.isPeng(this.handCards[i], card)){
  1237. isPeng = true;//若碰完无牌可出的话将不能碰
  1238. }
  1239. }
  1240. let res = this.logic.gangAnalyze(this.handCards[i], card);//处理跑牌情况6
  1241. // console.warn("判断跑111 ",i,JSON.stringify(this.handCards[i]), card,res);
  1242. isGang = !!res;
  1243. if(isGang) {
  1244. kgdr = i;
  1245. kglx = 1;
  1246. }
  1247. else{
  1248. let brnewCards = this.logic.arr2ToArr1(this.handCards[i],true);
  1249. let brres = this.logic.zmGangAnalyze3(brnewCards, this.huCards[i],card);//处理跑牌情况5
  1250. // console.warn("到这里了嘛???2222 ",i,brres);
  1251. if(brres.length == 1){
  1252. res = brres[0];
  1253. isGang = !!res;
  1254. if(isGang) {
  1255. kgdr = i;
  1256. kglx = 4;
  1257. }
  1258. }
  1259. }
  1260. } while (0);
  1261. // 权限掩码
  1262. if (_isChi && kgdr == -1) {
  1263. chiBiArr = this.logic.getChiBiArr(this.handCards[i], card);
  1264. // console.warn("出牌调用判断吃222 ",chiBiArr);
  1265. if(chiBiArr.chi.length > 0){
  1266. let cdpsszs = chiBiArr.cdpsszs;//要吃的牌手上张数
  1267. if(cdpsszs == 0) this.masks[i] |= 2;
  1268. else if(cdpsszs == 1 && chiBiArr.bi1.length > 0) this.masks[i] |= 2;
  1269. else if(cdpsszs == 2 && chiBiArr.bi1.length > 0 && chiBiArr.bi2.length > 0) this.masks[i] |= 2;
  1270. }
  1271. if(this.masks[i] & 2) this.chiBiArr = chiBiArr; //吃牌时吃比数据
  1272. }
  1273. if (isPeng) this.masks[i] |= 4;
  1274. if (isGang) this.masks[i] |= 8;
  1275. if(this.masks[i] > 0 && (!(this.masks[i] & 8) && !(this.masks[i] & 32))) this.masks[i] |= 64;
  1276. }
  1277. this.everyGDCPP[chairId].push([card,1]);
  1278. let sfqwqx = _.findIndex(this.masks, (m) => (m > 0)) == -1;//是否全无权限
  1279. this.logic.everyCPGS[chairId]++;
  1280. let pjhfsplist = {};
  1281. // 发送出牌消息
  1282. for (let i = 0; i < this.ccount; ++i) {
  1283. let ocard = { chairId: String(chairId), card: String(card) };
  1284. ocard.isGuoHuList = [[false,0],[false,0],[false,0],[false,0]]
  1285. ocard.chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  1286. // 排除自己
  1287. if (i != chairId) {
  1288. if((this.masks[i] & 2)){
  1289. ocard.chiBiArr = chiBiArr
  1290. }
  1291. }
  1292. ocard.cards = this.handCards[chairId];
  1293. ocard.hxInfos = this.handHXInfos[chairId];
  1294. if(i == chairId){
  1295. let hutipItem = {kehuData:[]}//每个人的胡牌提示
  1296. for (var x = 0; x < this.hutipdata[chairId].kehuData.length; x++) {
  1297. if(this.hutipdata[chairId].kehuData[x].canTing == card){
  1298. hutipItem.kehuData[0] = this.hutipdata[chairId].kehuData[x];
  1299. hutipItem.kehuData[0].canTing = 100;
  1300. }
  1301. }
  1302. this.hutipdata[chairId] = hutipItem;
  1303. }
  1304. this.logic.updateSYPS(i,[card],this.handCards[i],this.huCards,this.outCards,this.hutipdata[i]);
  1305. ocard.hutipdata = this.hutipdata[i];
  1306. ocard.isCanOut = this.isCanOut;//是否允许玩家手动出牌
  1307. ocard.mask = String(this.masks[i]);
  1308. ocard.yGDCPP = this.everyGDCPP[i];//已过的吃碰牌
  1309. ocard.chiBiArr = chiBiArr;
  1310. // 出牌通知
  1311. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.OUT_CARD, data: ocard });
  1312. if (i == chairId) {
  1313. // let pjhfcp = ocard
  1314. // pjhfcp.allMask = this.masks;
  1315. pjhfsplist = {
  1316. shouPai:this.logic.deepCloneTL(this.handCards),
  1317. handHXInfos:this.logic.deepCloneTL(this.handHXInfos),
  1318. lastCount:String(this.logic.leaveCount()),
  1319. ocard:this.logic.deepCloneTL(ocard),
  1320. outCards:this.logic.deepCloneTL(this.outCards),
  1321. isGuoHuList:this.logic.deepCloneTL(this.logic.isGuoHuList)
  1322. }
  1323. }
  1324. if(i == (this.ccount - 1)){/////TL++if条件判断,10月28号,为了实现能看到每个玩家的操作
  1325. pjhfsplist.maskList = this.logic.deepCloneTL(this.masks);/////TL++,10月28号,为了实现能看到每个玩家的操作
  1326. this.setPaijuHuiFangData(M.OUT_CARD,pjhfsplist);/////TL++ 牌局回放 push出牌数据
  1327. }
  1328. }
  1329. this.bckycpdp = 0;//本次可以吃碰的牌,为了给下面的everyGDCPP赋值
  1330. for (let i = 0; i < this.masks.length; ++i) {
  1331. if ((this.masks[i] & 2) || (this.masks[i] & 4)) {
  1332. this.bckycpdp = card;//本次可以吃碰的牌,为了给下面的everyGDCPP赋值
  1333. break;
  1334. }
  1335. }
  1336. // 围观通知
  1337. yield this.lookMsgAsync('paohuzi_event', { type: M.OUT_CARD, data: { chairId: String(chairId), card: String(card) } });
  1338. let str4 = "table end出牌---id:"+this.id + " ,uid "+chairId+" this.masks "+ this.masks +" card "+card;
  1339. logger.warn(str4);////cssj
  1340. if(sfqwqx) {
  1341. // 下家摸牌
  1342. let nextId = (chairId + 1) % this.ccount;
  1343. // console.warn("出牌函数里 这里摸牌 ",nextId);
  1344. this.outCards[chairId].push(card);
  1345. // console.warn("出牌函数里this.outCards[chairId] ",this.outCards[chairId]);
  1346. this.touchCardAsync(nextId); ///////出牌摸牌
  1347. }
  1348. if(kgdr != -1) this.app.timer.setTimeout(() => this.yanchiAsync(3,kgdr,card,kglx), 600);
  1349. return { code: C.OK };
  1350. });
  1351. //系统自动操作
  1352. proto.autoSysOperate = cor(function* (ycsj,chairId,operate,moCard,type) {
  1353. console.error("系统自动操作=====参数 ",ycsj,chairId,operate,moCard,type);
  1354. if (this.autoSysTimer) {
  1355. clearTimeout(this.autoSysTimer);
  1356. this.autoSysTimer = null;
  1357. }
  1358. if(!this.autoSysTimer){
  1359. this.autoSysTimer = this.app.timer.setTimeout(() =>
  1360. {
  1361. if(this.autoSysTimer)
  1362. {
  1363. clearTimeout(this.autoSysTimer);
  1364. this.autoSysTimer = null;
  1365. }
  1366. console.error("系统自动操作=====2222 ",chairId,operate,moCard,type);
  1367. if(operate == "hu") this.succCardAsync(chairId);
  1368. else if(operate == "ti") this.gangCardAsync(chairId,moCard,type);
  1369. }
  1370. , ycsj);//发牌时能胡自动胡,庄家能提自动提
  1371. }
  1372. return;
  1373. })
  1374. //在庄家打出第一张手牌之后,处理闲家手上的所有提,因为庄家的提在进牌函数中已经处理
  1375. //每个闲家每局最多执行1次,因为只有第一次轮到该玩家行动时手上才可能会有因为发牌形成的多个提
  1376. ///////摸牌函数 参数ifGang是否因为杠而摸牌 TL++ 参数isLuo 是否落牌摸牌,用于判断前端动画
  1377. proto.touchCardAsync = cor(function* (chairId) {
  1378. // 状态校验
  1379. if (this.state != STATE.PLAYING) return;
  1380. if (this.winner.chs.length > 0 || !this.users[chairId]) return;
  1381. if(this.ycMoTimer){
  1382. clearTimeout(this.ycMoTimer);
  1383. this.ycMoTimer = null;
  1384. }
  1385. this.isCanOut = false;//是否允许玩家手动出牌(摸牌)
  1386. if(this.logic.isGuoHuList[chairId][0]) this.logic.isGuoHuList[chairId][0] = false;/////TL++,设置过胡玩家的是否点击过胡为false; 摸牌
  1387. this.dqkthdwj = -1;
  1388. // 当前顺序
  1389. this.currentId = chairId;
  1390. this.moChair = chairId;//TL++,为了实现判断是否自摸
  1391. if(this.everysfdycpdt[chairId]){
  1392. //下面是处理起手时非庄家的提
  1393. let qsCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  1394. let qstres = this.logic.anGangAnalyze(qsCards);//处理提牌情况1
  1395. if(qstres.length > 0){
  1396. let str11 = "table 摸牌函数里面clqssfzjdt id:"+this.id + " ,uid "+chairId+" ,ggs "+ qstres.length;
  1397. logger.warn(str11);////cssj
  1398. this.masks[chairId] |= 8;
  1399. //庄家打牌之后轮到闲家摸牌,在闲家摸牌之前先提掉该玩家手上所有的提
  1400. // return yield this.gangCardAsync(chairId,qstres[0].card,2);
  1401. this.app.timer.setTimeout(() => this.yanchiAsync(3,chairId,qstres[0].card,2), 600);
  1402. return { code: C.OK };
  1403. }
  1404. //处理起手时非庄家的提结束
  1405. }
  1406. // 摸牌
  1407. var moCard = { card: 0 };
  1408. moCard = this.logic.moCard();
  1409. this.logic.moPaiTL();
  1410. let str1 = "table 摸牌函数id:"+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +" card "+moCard.card;
  1411. logger.warn(str1);////cssj
  1412. let oldLiangzi = this.liangZi;
  1413. this.moOrChu = 1;//现在是出牌阶段还是摸牌阶段,0表示都不是,1表示摸2表示出,用于点过之后判断应该是摸牌还是落牌,
  1414. this.liangZi = moCard.card;//当前的亮子(亮张,即摸上来的放在桌面上的牌)
  1415. let moPaiIsCanHu = false;//////TL++,摸牌的人是否可以胡牌
  1416. this.moCard = moCard.card;
  1417. // 是否流局
  1418. if (moCard.card <= 0) {
  1419. // console.warn("提前结算888");
  1420. yield this.concludeGameAsync(MODE.NOCARD);
  1421. return { code: C.OK };
  1422. }
  1423. let lastCount22 = this.logic.leaveCount();/////TL++xg
  1424. //下面是判断摸牌者的偎跑提胡权限
  1425. let zzpsfgd = this.logic.getIsGuo(this.everyGDCPP[chairId],moCard.card);//这张牌是否过掉过
  1426. let isWei = this.logic.weiAnalyze(this.handCards[chairId],moCard.card, zzpsfgd);
  1427. let zjisGang = null;
  1428. let brisGang = -1;//别人可杠的chairId
  1429. let zjGangType = 0;//这张牌杠的类型
  1430. let zjGangChair = -1;//这张牌杠的玩家
  1431. if(!isWei){
  1432. let zjnewCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  1433. zjnewCards.push(moCard.card);
  1434. let zjres = this.logic.anGangAnalyze(zjnewCards);//处理提牌情况2
  1435. // console.warn("摸牌函数 zjres ",chairId,moCard.card,JSON.stringify(zjnewCards),JSON.stringify(zjres),zjres.length);
  1436. zjisGang = (zjres.length > 0);
  1437. if (zjisGang) {
  1438. zjGangType = 2;
  1439. zjGangChair = this.currentId;
  1440. }
  1441. else{
  1442. zjres = this.logic.zmGangAnalyze1(zjnewCards, this.huCards[chairId]);//处理提牌情况3
  1443. zjisGang = (zjres.length > 0);
  1444. if (zjisGang) {
  1445. zjGangType = 5;
  1446. zjGangChair = this.currentId;
  1447. }
  1448. }
  1449. }
  1450. else{
  1451. zjGangChair = this.currentId;
  1452. }
  1453. if (isWei) this.masks[chairId] |= 32;
  1454. if (zjisGang) this.masks[chairId] |= 8;
  1455. // let zjisHu = false;//摸牌者是否能胡
  1456. // let mpzhuRes = this.logic.huAnalyze(chairId,this.handCards[chairId], moCard.card, this.huCards[chairId], true,true);
  1457. // if (mpzhuRes) {
  1458. // zjisHu = true;
  1459. // }
  1460. // console.warn("摸牌 走到这里了 isWei zjisGang ",isWei,zjisGang,zjGangType);
  1461. // if (_zjisHu) this.masks[chairId] |= 16;
  1462. this.everysfdycpdt[chairId] = false;
  1463. // 判断摸牌里别人吃碰杠
  1464. for (let i = 0; i < this.ccount; ++i) {
  1465. let touchCard = { currentId: String(chairId), touch: String(moCard.card),lastCount : '0' };
  1466. let cphsfwpkc = this.logic.getSFWPKC(this.handCards[i],this.handHXInfos[i]);//吃碰之后是否无牌可出
  1467. let __isHu = false;
  1468. if(!isWei){
  1469. // if(!zjisGang || zjGangType == 5){
  1470. //20250301为了解决自己提情况3时别人可胡的bug,把上面那句改成下面这句了
  1471. if(!zjisGang){
  1472. let isTouch = (i == chairId);
  1473. let huRes = this.logic.huAnalyze(i,this.handCards[i], moCard.card, this.huCards[i], isTouch,true);
  1474. if(this.everyDongState[chairId] == 1) huRes = null;
  1475. let isNeedFJCPP = false;//是否需要放进吃碰牌
  1476. if(huRes && this.logic.getMPSSFNP(moCard.card, this.huCards[i],isTouch)){
  1477. // console.warn("这里面是---------判断要不要把判胡的这张牌放进吃碰牌组成跑牌 ",i,huRes);
  1478. for (var kk = 0; kk < huRes.cards.length; kk++) {
  1479. if(huRes.cards[kk].indexOf(moCard.card) != -1){
  1480. if(huRes.hxInfos.styles[kk] == Logic.STYLE.JIAO){
  1481. isNeedFJCPP = true;//为了实现已碰七自己或别人摸到7时可以和自己手上两个柒组成绞牌这种情况的最优解
  1482. break;
  1483. }
  1484. }
  1485. }
  1486. }
  1487. if(!huRes || isNeedFJCPP){
  1488. //这里面是判断当前可跑不能胡但是跑完之后能胡的情况
  1489. let huResFZH = this.logic.paohuAnalyze(i,this.handCards[i], moCard.card, this.huCards[i], isTouch,false);
  1490. if(huResFZH){
  1491. huRes = huResFZH;
  1492. if(this.everyDongState[chairId] == 1) huRes = null;
  1493. if(huRes) this.paoHuQK = [i,true,moCard.card];//这把跑胡情况,为了处理当前可跑不能胡但是跑完之后能胡的情况[可跑胡玩家,是否是跑胡]
  1494. }
  1495. // console.warn("这里面是判断当前可跑不能胡但是跑完之后能胡的情况 ",i,this.paoHuQK);
  1496. }
  1497. // if(isTouch) console.warn("摸牌里判断可胡=========== ",i,moCard.card,this.handCards[i],huRes);
  1498. if (huRes) {
  1499. // let str3a = "table mpphcg:"+this.id + ",uid"+this.handCards[i];
  1500. // logger.info(str3a);////cssj
  1501. __isHu = true;
  1502. this.huRes[i] = huRes;
  1503. }
  1504. if (__isHu) this.masks[i] |= 16;
  1505. // console.warn("这里面是判断当前可跑不能胡但是跑完之后能胡的情况222 ",i,__isHu);
  1506. }
  1507. if(!zjisGang && (!__isHu)){//下面这段是摸牌者不能偎提其他人不可胡时判断跑,如果有跑会在下面自动跑
  1508. let brnewCards = this.logic.arr2ToArr1(this.handCards[i],true);
  1509. brnewCards.push(moCard.card);
  1510. let brres = this.logic.zmGangAnalyze(brnewCards, this.huCards[i]);//处理跑牌情况2和跑牌情况3
  1511. if(brres.length == 1) {
  1512. zjGangType = 3;
  1513. }
  1514. if(brres.length == 0 && i != chairId){
  1515. //上面是用自己碰牌跑别人和自己摸的牌,下面是用自己偎的牌跑别人摸的牌
  1516. brres = this.logic.zmGangAnalyze2(brnewCards, this.huCards[i]);//处理跑牌情况4
  1517. //下面是用自己手上的坎跑别人摸得牌(防止出现自己摸得牌自己要吃别人要碰结果被自己吃走了)
  1518. if(brres.length == 0){
  1519. let brgres = this.logic.gangAnalyze(this.handCards[i], moCard.card);//处理跑牌情况1
  1520. let gsjsfhf = !!brgres;
  1521. if(gsjsfhf){
  1522. brres.push(brgres);
  1523. zjGangType = 1;
  1524. }
  1525. }
  1526. else{
  1527. if(brres.length == 1) {
  1528. zjGangType = 3;
  1529. }
  1530. }
  1531. }
  1532. // console.warn("到这里了嘛???444 ",i,brres);
  1533. if(brres.length > 0){//跑别人摸的牌
  1534. brisGang = i;
  1535. zjGangChair = i;
  1536. if(this.masks[i] & 16 && i == chairId) this.masks[i] = 0;
  1537. this.masks[i] |= 8;
  1538. }
  1539. }
  1540. if(!isWei && !zjisGang && brisGang == -1 && !cphsfwpkc && i != chairId){
  1541. let gdsfkp = this.logic.getIsCanCP(this.everyGDCPP[i],moCard.card,2);//过掉是否可碰
  1542. if(gdsfkp && this.logic.isPeng(this.handCards[i], moCard.card)){//碰别人摸的牌
  1543. this.masks[i] |= 4;//若碰完无牌可出的话将不能碰
  1544. this.masks[i] |= 64;
  1545. }
  1546. }
  1547. }
  1548. }
  1549. // console.warn("摸牌忽略牌 走到这里了 this.everyGDCPP ",this.everyGDCPP);
  1550. //下面是判断摸牌玩家的吃
  1551. let zjcphsfwpkc = this.logic.getSFWPKC(this.handCards[chairId],this.handHXInfos[chairId]);//吃碰之后是否无牌可出
  1552. let chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  1553. let gdsfkc = this.logic.getIsCanCP(this.everyGDCPP[chairId],moCard.card,1);//过掉是否可吃
  1554. // console.warn("//////////////////////////000 ",chairId,zjcphsfwpkc , brisGang ,isWei ,zjisGang , gdsfkc);
  1555. // console.warn("//////////////////////////111 ",chairId,this.masks[chairId],(this.masks[chairId] & 8));
  1556. let mpzsfnp = this.logic.getMPZSFNP(moCard.card, this.huCards[chairId]);//摸牌者是否能跑
  1557. if(!zjcphsfwpkc && brisGang == -1 && !isWei && !zjisGang && gdsfkc && !mpzsfnp){
  1558. // console.warn("//////////////////////////???")
  1559. let _isChi = false;
  1560. let ress = this.logic.chiAnalyze(this.handCards[chairId], moCard.card);
  1561. // console.warn("//////////////////////////??? ",ress)
  1562. _isChi = (ress.length > 0);
  1563. if (_isChi) {
  1564. chiBiArr = this.logic.getChiBiArr(this.handCards[chairId], moCard.card);
  1565. if(chiBiArr.chi.length > 0){
  1566. let cdpsszs = chiBiArr.cdpsszs;//要吃的牌手上张数
  1567. if(cdpsszs == 0) this.masks[chairId] |= 2;
  1568. else if(cdpsszs == 1 && chiBiArr.bi1.length > 0) this.masks[chairId] |= 2;
  1569. else if(cdpsszs == 2 && chiBiArr.bi1.length > 0 && chiBiArr.bi2.length > 0) this.masks[chairId] |= 2;
  1570. }
  1571. if(this.masks[chairId] & 2) this.chiBiArr = chiBiArr; //吃牌时吃比数据
  1572. }
  1573. }
  1574. //下面是判断摸牌玩家下家的吃
  1575. let mpwjdxj = (chairId + 1) % this.ccount;//摸牌玩家的下家
  1576. let cphsfwpkcxj = this.logic.getSFWPKC(this.handCards[mpwjdxj],this.handHXInfos[mpwjdxj]);//吃碰之后是否无牌可出
  1577. let chiBiArrxj = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  1578. let gdsfkcxj = this.logic.getIsCanCP(this.everyGDCPP[mpwjdxj],moCard.card,1);//过掉是否可吃
  1579. if(!cphsfwpkcxj && brisGang == -1 && !isWei && !zjisGang && gdsfkcxj){
  1580. let _isChi = false;
  1581. let ress = this.logic.chiAnalyze(this.handCards[mpwjdxj], moCard.card);
  1582. _isChi = (ress.length > 0);
  1583. if (_isChi) {
  1584. chiBiArrxj = this.logic.getChiBiArr(this.handCards[mpwjdxj], moCard.card);
  1585. if(chiBiArrxj.chi.length > 0){
  1586. let cdpsszs = chiBiArrxj.cdpsszs;//要吃的牌手上张数
  1587. if(cdpsszs == 0) this.masks[mpwjdxj] |= 2;
  1588. else if(cdpsszs == 1 && chiBiArrxj.bi1.length > 0) this.masks[mpwjdxj] |= 2;
  1589. else if(cdpsszs == 2 && chiBiArrxj.bi1.length > 0 && chiBiArrxj.bi2.length > 0) this.masks[mpwjdxj] |= 2;
  1590. }
  1591. if(this.masks[mpwjdxj] & 2) this.chiBiArrxj = chiBiArrxj; //吃牌时吃比数据
  1592. }
  1593. }
  1594. let pjhfsplist = {};
  1595. // 发送摸牌消息
  1596. for (let i = 0; i < this.ccount; ++i) {
  1597. let touchCard = { currentId: String(chairId), touch: String(moCard.card),lastCount : '0' };
  1598. let xxchiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  1599. if (i == chairId && (this.masks[i] & 2)) {
  1600. xxchiBiArr = chiBiArr
  1601. }
  1602. else if (i == mpwjdxj && (this.masks[i] & 2)) {
  1603. xxchiBiArr = chiBiArrxj
  1604. }
  1605. if (isWei && i != chairId && !zzpsfgd) touchCard.touch = "100";//为了实现偎牌闷着摸牌
  1606. if(this.masks[i] > 0 && (!(this.masks[i] & 8) && !(this.masks[i] & 32))) this.masks[i] |= 64;
  1607. if(i != chairId && (this.masks[i] & 16)) this.masks[i] |= 64;
  1608. touchCard.isLuo = this.luo;
  1609. this.logic.updateSYPS(i,[oldLiangzi],this.handCards[i],this.huCards,this.outCards,this.hutipdata[i]);
  1610. touchCard.hutipdata = this.hutipdata[i];
  1611. touchCard.isCanOut = this.isCanOut;//是否允许玩家手动出牌
  1612. touchCard.chiBiArr = xxchiBiArr;
  1613. touchCard.mask = String(this.masks[i]);
  1614. touchCard.yGDCPP = this.everyGDCPP[i];//已过的吃碰牌
  1615. touchCard.lastCount = String(lastCount22);
  1616. this.logic.lastMoPaiChairID = this.currentId;
  1617. // 摸牌通知
  1618. // console.warn("222WWWWWWWTTTTTT",i,chairId,moCard.card);
  1619. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.TOUCH_CARD, data: touchCard});
  1620. if (i == chairId) {
  1621. pjhfsplist = {
  1622. shouPai:this.logic.deepCloneTL(this.handCards),
  1623. lastCount:String(this.logic.leaveCount()),
  1624. touchCard:this.logic.deepCloneTL(touchCard),
  1625. outCards:this.logic.deepCloneTL(this.outCards),
  1626. isGuoHuList:this.logic.deepCloneTL(this.logic.isGuoHuList)
  1627. }
  1628. }
  1629. if(i == (this.ccount - 1)){/////TL++if条件判断,10月28号,为了实现能看到每个玩家的操作
  1630. pjhfsplist.maskList = this.logic.deepCloneTL(this.masks);/////TL++,10月28号,为了实现能看到每个玩家的操作
  1631. this.setPaijuHuiFangData(M.TOUCH_CARD,pjhfsplist);/////TL++ 牌局回放 push摸牌数据
  1632. }
  1633. }
  1634. let str3 = "table 摸牌函数id:222 "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +" card "+moCard.card;
  1635. logger.warn(str3);////cssj
  1636. // 围观通知
  1637. let pgData = { currentId: String(chairId),touch: String(moCard.card), isLuo:this.luo,lastCount:String(lastCount22)}
  1638. yield this.lookMsgAsync('paohuzi_event', { type: M.TOUCH_CARD, data: pgData });
  1639. this.bckycpdp = 0;//本次可以吃碰的牌,为了给下面的everyGDCPP赋值
  1640. for (let i = 0; i < this.masks.length; ++i) {
  1641. if ((this.masks[i] & 2) || (this.masks[i] & 4)) {
  1642. this.bckycpdp = moCard.card;//本次可以吃碰的牌,为了给下面的everyGDCPP赋值
  1643. break;
  1644. }
  1645. }
  1646. this.luo = true;
  1647. let zdType = 0;//自动类型
  1648. // 全无权限
  1649. for (let i = 0; i < this.ccount; ++i) {
  1650. if (this.masks[i] != 0) break;
  1651. if (i == this.ccount - 1){
  1652. zdType = 1;
  1653. //玩家对摸的牌全无权限,接下来应该给下个玩家摸牌
  1654. this.outCards[this.currentId].push(this.liangZi);
  1655. // console.warn("放弃函数里this.outCards[chairId] ",this.outCards[chairId]);
  1656. zjGangChair = (this.currentId + 1) % this.ccount;
  1657. }
  1658. }
  1659. if (isWei) zdType = 2;
  1660. else if (zjisGang) zdType = 3;
  1661. else if (brisGang > -1) zdType = 3;
  1662. // console.warn("mopai gang==============",zdType,isWei,zjisGang,zjGangChair,brisGang,zjGangType);
  1663. this.paoForm = -1;//提供跑的玩家
  1664. if(zdType == 3) this.paoForm = chairId;//提供跑的玩家
  1665. if(zdType) this.app.timer.setTimeout(() => this.yanchiAsync(zdType,zjGangChair,moCard.card,zjGangType), 2100);
  1666. return { code: C.OK };
  1667. });
  1668. //延迟执行,在出牌之后有可跑1时和摸牌之后有人偎提跑时调用
  1669. proto.yanchiAsync = cor(function* (type,chairId,card,zjGangType) {
  1670. if(type == 1) return yield this.touchCardAsync(chairId);
  1671. else if(type == 2) return yield this.weiCardAsync(chairId,card);
  1672. else if(type == 3) return yield this.gangCardAsync(chairId,card,zjGangType);
  1673. });
  1674. // 放弃操作
  1675. proto.giveUpAsync = cor(function* (chairId) {
  1676. let str3 = "table 放弃操作id: "+this.id + " ,uid "+chairId+", this.masks "+ this.masks;
  1677. logger.warn(str3);////cssj
  1678. // 权限掩码
  1679. var mask = this.masks[chairId];
  1680. if (mask <= 0) {
  1681. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  1682. }
  1683. if (mask & 2) {
  1684. let mpwjdxj = (this.moChair + 1) % this.ccount;//摸牌玩家的下家
  1685. if(this.moOrChu == 1 && mpwjdxj == chairId){
  1686. this.chiBiArrxj = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //摸牌者下家吃摸牌者摸的牌时吃比数据
  1687. }
  1688. else{
  1689. this.chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  1690. }
  1691. }
  1692. // 删除权限
  1693. this.masks[chairId] = 0;
  1694. // 忽略牌 代表每个玩家本局过吃碰的牌
  1695. if ((mask & 2) && (mask & 4)){
  1696. if(this.bckycpdp) this.everyGDCPP[chairId].push([this.bckycpdp,4]);
  1697. }
  1698. else{
  1699. if ((mask & 2)){
  1700. if(this.bckycpdp) this.everyGDCPP[chairId].push([this.bckycpdp,2]);
  1701. }
  1702. if ((mask & 4)){
  1703. if(this.bckycpdp) this.everyGDCPP[chairId].push([this.bckycpdp,3]);
  1704. }
  1705. }
  1706. console.warn("放弃 走到这里了 this.everyGDCPP ",this.everyGDCPP);
  1707. // 放弃胡牌
  1708. if (mask & 16) {////mask = 16~31时结果=16这个if能进去 0~15或者32~47之间结果=0这个if进不去
  1709. this.logic.isGuoHuList[chairId][0] = true;/////TL++,设置过胡玩家的是否点击过胡为true 点击过按钮
  1710. let fqdata = {
  1711. chairId:chairId,
  1712. isGuoHuList: this.logic.isGuoHuList[chairId],
  1713. isCanOut: this.isCanOut,
  1714. }
  1715. let pjhfghsj = {
  1716. chairId:chairId,
  1717. isGuoHuList: this.logic.deepCloneTL(this.logic.isGuoHuList),
  1718. isCanOut: this.isCanOut,
  1719. }
  1720. // console.warn("放弃操作里设置过胡为true",chairId, this.isGangHu,this.logic.isGuoHuList);
  1721. let winner = this.winner;
  1722. do {
  1723. if(this.paoHuQK[0] == chairId && this.paoHuQK[1]){
  1724. this.paoHuQK = [-1,false,0];//这把跑胡情况,为了处理当前可跑不能胡但是跑完之后能胡的情况[可跑胡玩家,是否是跑胡]
  1725. }
  1726. //下面这段是摸牌者不能偎提其他人过胡时判断跑,如果有跑会在下面自动跑
  1727. if(this.moOrChu == 1){
  1728. let brnewCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  1729. brnewCards.push(this.liangZi);
  1730. let brres = this.logic.zmGangAnalyze(brnewCards, this.huCards[chairId]);//处理跑牌情况2和跑牌情况3
  1731. if(brres.length == 1) {
  1732. this.gangType = 3;
  1733. }
  1734. if(brres.length == 0){
  1735. //上面是用自己碰牌跑别人和自己摸的牌,下面是用自己偎的牌跑别人摸的牌
  1736. brres = this.logic.zmGangAnalyze2(brnewCards, this.huCards[chairId]);//处理跑牌情况4
  1737. //下面是用自己手上的坎跑别人摸得牌(防止出现自己摸得牌自己要吃别人要碰结果被自己吃走了)
  1738. if(brres.length == 0){
  1739. let brgres = this.logic.gangAnalyze(this.handCards[chairId], this.liangZi);//处理跑牌情况1
  1740. let gsjsfhf = !!brgres;
  1741. if(gsjsfhf){
  1742. brres.push(brgres);
  1743. this.gangType = 1;
  1744. }
  1745. }
  1746. else{
  1747. if(brres.length == 1) {
  1748. this.gangType = 3;
  1749. }
  1750. }
  1751. }
  1752. if(brres.length > 0){//跑别人摸的牌
  1753. this.masks[chairId] = 9;
  1754. this.gangCard = this.liangZi;
  1755. }
  1756. }
  1757. // 有人胡牌
  1758. if (winner.chs.length > 0) {
  1759. // let dist = (winner.chs[0] - winner.lead + this.ccount) % this.ccount;
  1760. // let __cHu = _.findIndex(this.masks, (m, i) => (m & 16 && (i - winner.lead + this.ccount) % this.ccount < dist));////TL++,zsyl,
  1761. ///TL++,以前是上面那句写法,有个问题:0打牌后1,2,3号玩家都能胡,1点胡2点过,3就没有机会选择是否胡牌
  1762. let __cHu = _.findIndex(this.masks, (m, i) => (m & 16));
  1763. // console.warn("111没炮多想 放弃操作放弃操作放弃操作__cHu",__cHu);
  1764. if (__cHu != -1) break;
  1765. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  1766. // console.warn("提前结算2222");
  1767. yield this.concludeGameAsync(MODE.NORMAL).then(() => ({ code: C.OK }));/////结算游戏
  1768. return { code: C.OK };
  1769. } else {
  1770. let __cHu = _.findIndex(this.masks, (m) => (m & 16));
  1771. // console.warn("111没炮多想 放弃操作放弃操作放弃操作__cHu",__cHu);
  1772. if (__cHu != -1) break;//break之后都后面的代码就不执行了
  1773. }
  1774. // console.warn("这里是啥情况啊---222 ",mask)
  1775. // 查找等待
  1776. let cGang = -1
  1777. let cPeng = -1;
  1778. let _cChi = -1;
  1779. // console.warn("这里是啥情况啊",this.masks);
  1780. for (let i = 0; i < this.masks.length; ++i) {
  1781. // if (i == this.currentId || i == chairId) continue;///////TL++zsyl 这种写法会导致拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  1782. // if (i == chairId) continue;//////TL++,为了解决拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  1783. if (this.masks[i] == 9) {
  1784. cGang = i;
  1785. continue;
  1786. }
  1787. if (this.masks[i] == 5) {
  1788. cPeng = i;
  1789. continue;
  1790. }
  1791. if (this.masks[i] == 3) {
  1792. _cChi = i;
  1793. continue;
  1794. }
  1795. }
  1796. // console.warn("2222情况啊",cGang, this.gangType,this.gangCard);
  1797. let sfqsfpjd = this.logic.isFPJD();//是否起手发牌阶段
  1798. // console.warn("放弃操作 sfqsfpjd ",chairId, sfqsfpjd);
  1799. // 杠碰吃
  1800. if (cGang != -1 && this.gangType > 0 && this.gangCard > 0) {
  1801. // console.warn("这里是放弃操作再次调用 杠 次",cGang, this.gangCard, this.gangType);
  1802. return this.gangCardAsync(cGang, this.gangCard, this.gangType).then(() => ({ code: C.OK }));
  1803. } else if (cPeng != -1) {
  1804. // console.warn("到这里了吗???? ",cPeng,this.moOrChu,this.moCard,this.outCard,this.liangZi);
  1805. if(this.moOrChu == 1){
  1806. return this.pengCardAsync(cPeng, this.liangZi).then(() => ({ code: C.OK }));
  1807. }
  1808. return this.pengCardAsync(cPeng, this.outCard).then(() => ({ code: C.OK }));
  1809. } else if (_cChi != -1 && this._eatType > 0) {
  1810. if(this.moOrChu == 1){
  1811. return this.eatCardAsync(_cChi, this.liangZi, this._eatType,this._bi1Type,this._bi2Type).then(() => ({ code: C.OK }));
  1812. }
  1813. return this.eatCardAsync(_cChi, this.outCard, this._eatType,this._bi1Type,this._bi2Type).then(() => ({ code: C.OK }));
  1814. } else if (sfqsfpjd && !this.bjsfyjp){//本局是否已进牌(庄家起手亮张已放入手中)) {
  1815. return this.jinCardAsync().then(() => ({ code: C.OK }));
  1816. }
  1817. else {
  1818. // console.warn("????????????????================= ",this.dqkthdwj);
  1819. if(this.dqkthdwj == chairId) {
  1820. this.isCanOut = true;//是否允许玩家手动出牌(提后可胡点过)
  1821. fqdata.isCanOut = this.isCanOut;
  1822. pjhfghsj.isCanOut = this.isCanOut;
  1823. this.dqkthdwj = -1;
  1824. yield this.pushMsgAsync(chairId, 'paohuzi_event', { type: M.GIVE_UP, data:fqdata });
  1825. this.setPaijuHuiFangData(M.GIVE_UP,pjhfghsj);/////TL++ 牌局回放 push过牌数据
  1826. return { code: C.OK };
  1827. }
  1828. }
  1829. } while (0);
  1830. yield this.pushMsgAsync(chairId, 'paohuzi_event', { type: M.GIVE_UP, data:fqdata });
  1831. this.setPaijuHuiFangData(M.GIVE_UP,pjhfghsj);/////TL++ 牌局回放 push过牌数据
  1832. }
  1833. // 放弃杠碰
  1834. if ((mask & 8) || (mask & 4) || (mask & 2)) {
  1835. let __cHu = _.findIndex(this.masks, (m) => (m & 16));
  1836. if (__cHu == -1) {
  1837. let _cChi = _.findIndex(this.masks, (m) => (m & 3));
  1838. if (_cChi != -1 && this._eatType > 0) {
  1839. if(this.moOrChu == 1){
  1840. return this.eatCardAsync(_cChi, this.liangZi, this._eatType,this._bi1Type,this._bi2Type).then(() => ({ code: C.OK }));
  1841. }
  1842. return this.eatCardAsync(_cChi, this.outCard, this._eatType,this._bi1Type,this._bi2Type).then(() => ({ code: C.OK }));
  1843. }
  1844. }
  1845. }
  1846. // console.warn("table 放弃 到这里了?? ",this.masks,this.moOrChu,this.sfwhkhqypkc);
  1847. // console.warn("table 放弃 到这里了?? ",this.masks,this.moOrChu,this.sfwhkhqypkc);
  1848. // 全无权限
  1849. for (let i = 0; i < this.ccount; ++i) {
  1850. if (this.masks[i] != 0) break;
  1851. // 切换用户
  1852. if (i == this.ccount - 1) {
  1853. if(this.sfwhkhqypkc) {
  1854. this.sfwhkhqypkc = false;//偎牌玩家是否偎后可胡且有牌可出
  1855. return { code: C.OK };
  1856. }
  1857. //玩家对打出的牌点过至全无权限,接下来应该给下个玩家摸牌
  1858. this.outCards[this.currentId].push(this.liangZi);
  1859. // console.warn("放弃函数里this.outCards[chairId] ",this.outCards[chairId]);
  1860. let nextId = (this.currentId + 1) % this.ccount;
  1861. return this.touchCardAsync(nextId).then(() => ({ code: C.OK }));//////放弃操作引起的摸牌
  1862. }
  1863. }
  1864. return { code: C.OK };
  1865. });
  1866. // /////TL++,是否进行海底捞月的操作 处理前端海底捞月函数
  1867. proto.haiDiLaoYue = cor(function* (chairId,data) {
  1868. // console.warn("海底捞月海底捞月");
  1869. return { code: C.OK };
  1870. });
  1871. // 杠牌,1-跑1跑6, 2-提牌情况1和2, 3-跑2跑3跑4, 4-跑牌情况5, 5-提牌情况3
  1872. proto.gangCardAsync = cor(function* (chairId, card, type) {
  1873. let str3 = "table 杠牌,id: "+this.id + " ,uid "+chairId+", this.masks "+ this.masks +" ,card "+card+" ,type "+type+" ,currentId "+this.currentId+" ,everysfdycpdt "+this.everysfdycpdt;
  1874. logger.warn(str3);////cssj
  1875. // 参数校验
  1876. if (!type || (type < 1 || type > 5)) {
  1877. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1878. }
  1879. // if (type == 1 && card != this.outCard) {
  1880. // return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1881. // }
  1882. if ((type == 2) && this.currentId != chairId) {
  1883. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1884. }
  1885. if (type == 3 && !card) {
  1886. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  1887. }
  1888. if (!(this.masks[chairId] & 8)) {
  1889. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  1890. }
  1891. let sfltlg = false;//是否连提两个,用于判断是否需要进子
  1892. // 他人可胡
  1893. let __cHu = (type == 2) ? -1 : _.findIndex(this.masks, (m) => ((m & 16) && !(m & 8)));
  1894. let gwjsfdyct = this.everysfdycpdt[chairId];//该玩家是否第一次提
  1895. // console.warn("111拉杠胡%%%%%%%%%%%%%%%%%%%%%%",__cHu,type,gwjsfdyct);
  1896. if (__cHu == -1) {
  1897. let res = null;
  1898. if (type == 1 || type == 2 || type == 4 || type == 5) {
  1899. if(this.everysfdycpdt[chairId]){//是否第一次判断提,因为每局没判断过提或者没摸过牌的话第一次判断提可能会有多个提
  1900. res = this.logic.gang2(chairId,this.handCards[chairId],this.huCards[chairId], card, type);
  1901. if(res.length >= 2) sfltlg = true;//是否连提两个,用于判断是否需要进子
  1902. if(res.length == 0) res = null;
  1903. }
  1904. else{
  1905. res = this.logic.gang(chairId,this.handCards[chairId],this.huCards[chairId], card, type);
  1906. }
  1907. } else if (type == 3) {
  1908. let zjnewCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  1909. zjnewCards.push(card);
  1910. res = this.logic.zmGang(chairId,zjnewCards, this.huCards[chairId], card);
  1911. }
  1912. // console.warn("走到这里了嘛??????????????",res,this.handCards[chairId], this.huCards[chairId]);
  1913. if (!res) {
  1914. return { code: C.FAILD, msg: C.TABLE_GANG_ERROR };
  1915. }
  1916. /////TL++7月17日,这整个if的内容 和else的判断
  1917. let winner = this.winner;
  1918. if (winner.chs.length > 0) {
  1919. // console.warn("gang ??????????????????111 ",winner);
  1920. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  1921. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  1922. // console.warn("提前结算BBB");
  1923. yield this.concludeGameAsync(MODE.NORMAL);
  1924. }
  1925. else{
  1926. // console.warn("gang ??????????????????222 ",type,this.currentId);
  1927. // 记录杠牌
  1928. if (type == 1) {// 明杠
  1929. res.origin = this.outerId;
  1930. // this.outCards[this.outerId].pop();
  1931. if(this.everysfdycpdt[chairId]){
  1932. this.huCards[chairId].push(res[0]);
  1933. }
  1934. else{
  1935. this.huCards[chairId].push(res);
  1936. }
  1937. let yscdsz = [card, card, card];
  1938. let scspRes = this.logic.removes2(this.handCards[chairId], yscdsz);//删除手牌结果
  1939. this.handCards[chairId] = _.cloneDeep(scspRes.handCards);
  1940. this.handHXInfos[chairId] = _.cloneDeep(scspRes.handHXInfos);
  1941. } else if (type == 2) {// 暗杠
  1942. // console.warn("gang ??????????????????333 ",type);
  1943. if(this.everysfdycpdt[chairId]){
  1944. // console.warn("起手发牌的时候 ",this.logic.moPaiCountTL,res);
  1945. for (var i = 0; i < res.length; i++) {
  1946. this.huCards[chairId].push(res[i]);
  1947. let yscdsz = [res[i].cards[0], res[i].cards[0], res[i].cards[0], res[i].cards[0]];//要删除的数组
  1948. // console.warn("要删除的数组 ",yscdsz);
  1949. let scspRes = this.logic.removes2(this.handCards[chairId], yscdsz);//删除手牌结果
  1950. this.handCards[chairId] = _.cloneDeep(scspRes.handCards);
  1951. this.handHXInfos[chairId] = _.cloneDeep(scspRes.handHXInfos);
  1952. }
  1953. }
  1954. else{
  1955. this.huCards[chairId].push(res);
  1956. let yscdsz = [card, card, card];
  1957. let scspRes = this.logic.removes2(this.handCards[chairId], yscdsz);//删除手牌结果
  1958. this.handCards[chairId] = _.cloneDeep(scspRes.handCards);
  1959. this.handHXInfos[chairId] = _.cloneDeep(scspRes.handHXInfos);
  1960. }
  1961. // this.logic.remove(this.handCards[chairId], [card, card, card, card]);
  1962. // this.logic.adjust(this.handCards[chairId]);
  1963. } else if (type == 3) {// 自摸明杠 跑牌情况2:当别人从墩上摸得牌,是自己已经碰的牌
  1964. let huCard = _.find(this.huCards[chairId], (o) => {
  1965. return (o.style == Logic.STYLE.PENG && o.cards[0] == card);
  1966. });
  1967. if (!huCard) {
  1968. huCard = _.find(this.huCards[chairId], (o) => {
  1969. return (o.style == Logic.STYLE.WEI && o.cards[0] == card);
  1970. });
  1971. }
  1972. if (!huCard) {
  1973. return { code: C.FAILD, msg: C.TABLE_GANG_ERROR };
  1974. }
  1975. // console.warn("拉杠胡%%%%%%%%%%%%%%%%%%%%%%" ,this.isGangHu);
  1976. huCard.style = Logic.STYLE.ZMGANG;
  1977. if(huCard.cards.length == 3) huCard.cards.push(card);
  1978. this.isGangHu = false;/////TL++,8月28日晚上,为了解决过胡拉杠之后就算自己已经摸牌也不能再次拉杠的问题
  1979. } else if (type == 4) {// 跑牌情况5:当别人滑动手牌打出的牌,是自己已经偎的牌
  1980. let huCard = _.find(this.huCards[chairId], (o) => {
  1981. return (o.style == Logic.STYLE.WEI && o.cards[0] == card);
  1982. });
  1983. if (!huCard) {
  1984. return { code: C.FAILD, msg: C.TABLE_GANG_ERROR };
  1985. }
  1986. huCard.style = Logic.STYLE.ZMGANG;
  1987. if(huCard.cards.length == 3) huCard.cards.push(card);
  1988. } else if (type == 5) {// 提牌情况3:自己摸上来的牌是自己已经“偎牌”的牌
  1989. let huCard = _.find(this.huCards[chairId], (o) => {
  1990. return (o.style == Logic.STYLE.WEI && o.cards[0] == card);
  1991. });
  1992. if (!huCard) {
  1993. return { code: C.FAILD, msg: C.TABLE_GANG_ERROR };
  1994. }
  1995. huCard.style = Logic.STYLE.ANGANG;
  1996. if(huCard.cards.length == 3) huCard.cards.push(card);
  1997. }
  1998. this.everyCPHX[chairId] = this.logic.getCPHX(this.huCards[chairId]);
  1999. // 清空权限
  2000. this._eatType = 0;
  2001. this._bi1Type = 0;
  2002. this._bi2Type = 0;
  2003. this.gangType = 0;
  2004. this.gangCard = 0;
  2005. _.fill(this.masks, 0);
  2006. // 总杠次
  2007. // this.gonCount += 1;
  2008. let otherCards = [];//起手发牌阶段的暗杠可能会有好几个
  2009. if(this.everysfdycpdt[chairId] && res && res.length >= 2){
  2010. for (var i = 0; i < res.length; i++) {
  2011. if(card == res[i].cards[0]) continue;
  2012. otherCards.push(res[i].cards[0]);
  2013. }
  2014. }
  2015. this.currentId = chairId;
  2016. let gwjsfjz = this.logic.isNeedJinZi(this.handCards[chairId],this.huCards[chairId]);//该玩家是否需要进子
  2017. //下面判断&& !this.everysfdycpdt[chairId] 是因为闲家起手两个提,在庄家出牌之后闲家连提2个(八块)之后需要给这个玩家摸牌,
  2018. if(gwjsfjz && !this.logic.isFPJD() && !this.everysfdycpdt[chairId]){//庄家必须出一张牌
  2019. let nextId = (this.currentId + 1) % this.ccount;
  2020. this.currentId = nextId;
  2021. }
  2022. let phktdp = 0;//该玩家跑后可提的牌
  2023. if(type == 1 && this.everysfdycpdt[chairId]){
  2024. //下面是处理起手时非庄家的提
  2025. let qsCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  2026. let qstres = this.logic.anGangAnalyze(qsCards);
  2027. if(qstres.length > 0){
  2028. this.masks[chairId] |= 8;
  2029. //庄家打牌之后轮到闲家摸牌,在闲家摸牌之前先提掉该玩家手上所有的提
  2030. phktdp = qstres[0].card;
  2031. }
  2032. //处理起手时非庄家的提结束
  2033. }
  2034. this.everysfdycpdt[chairId] = false;//=========
  2035. if(phktdp) this.everysfdycpdt[chairId] = true;
  2036. let huRes = null;
  2037. // console.warn("下面是刚里面判jindong ",chairId,this.everyDongState[chairId]);
  2038. // if(this.everyDongState[chairId] != 1) {
  2039. let isTouch = false;
  2040. if(type == 1) isTouch = false;
  2041. if(type == 2) isTouch = true;
  2042. else isTouch = chairId == this.paoForm;//提供跑的玩家
  2043. //本局钻洞了本局就不能胡了
  2044. // console.warn("下面是刚里面判胡 ",chairId,this.handCards[chairId]);
  2045. huRes = this.logic.huAnalyze(chairId,this.handCards[chairId], card, this.huCards[chairId], isTouch,false);
  2046. if(type == 1 && this.moOrChu == 2) huRes = null;//加这句是为了实现闲家(手牌有208的坎和一对)不能胡发牌后庄家打出的208
  2047. if(type == 4) huRes = null;//加这句是为了实现不能胡别人打出的(比如自己偎102之后不能胡别人打出的102)
  2048. if(this.everyDongState[chairId] == 1) huRes = null;
  2049. // console.warn("加这句是为了防止跑之后还能胡过-------------------- ",type,this.moOrChu);
  2050. //加这句是为了防止可跑可胡时点过胡之后自动跑之后还提示胡过
  2051. if(type == 1 || type == 3) huRes = null;//加这句是为了防止可跑可胡时点过胡之后自动跑之后还提示胡过
  2052. // (type=1时的跑1情况在摸牌函数里进行判胡了,走到这里来是已经在别人摸牌时候点过胡之后开始自动跑完到这里)
  2053. // (type=1时的跑6情况在上面已经判断过了不能胡别人打出的)
  2054. // (type=3表示的跑2跑3跑4和和type=1的跑1情况一样,在摸牌函数里进行的是否可胡判断)
  2055. // }
  2056. if (huRes) {
  2057. this.huRes[chairId] = huRes;
  2058. this.masks[chairId] |= 16;
  2059. let isstwk = false;
  2060. if(this.logic.isFPJD()){
  2061. if(this.logic.isSANTIWUKAN(this.handCards[chairId], this.huCards[chairId],[],[])){
  2062. isstwk = true;
  2063. }
  2064. }
  2065. if(!isstwk){
  2066. this.masks[chairId] |= 64;
  2067. if(type == 2 || type == 5) this.dqkthdwj = chairId;
  2068. }
  2069. // yield this.autoSysOperate(600,chairId,"hu",card);
  2070. }
  2071. // 发送通知
  2072. // console.warn("gang this.huCards[chairId]",phktdp,this.huCards[chairId]);
  2073. let lastCount = this.logic.leaveCount();/////TL++xg
  2074. this.isCanOut = true;//是否允许玩家手动出牌(杠牌)
  2075. if(phktdp || huRes){//跑后可提胡
  2076. this.isCanOut = false;//是否允许玩家手动出牌(杠牌)
  2077. }
  2078. for (let i = 0; i < this.ccount; ++i) {
  2079. let gangData = {
  2080. chairId: String(chairId),
  2081. currentId: this.currentId,
  2082. mask: String(this.masks[i]),
  2083. isCanOut: this.isCanOut,//是否允许玩家手动出牌
  2084. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2085. type: String(type),
  2086. card: String(card),
  2087. otherCards: _.cloneDeep(otherCards),
  2088. }
  2089. if(i == chairId){
  2090. gangData.cards = this.handCards[chairId];
  2091. gangData.hxInfos = this.handHXInfos[chairId];
  2092. if(this.logic.isXYBCP(this.handCards[i],this.huCards[i])){
  2093. this.hutipdata[i] = this.logic.hutip2(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////杠牌调用胡牌提示
  2094. }
  2095. else {
  2096. this.hutipdata[i] = this.logic.hutip(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////杠牌调用胡牌提示
  2097. }
  2098. gangData.hutipdata = this.hutipdata[i];
  2099. let pjhfsplist = {
  2100. shouPai:this.logic.deepCloneTL(this.handCards),
  2101. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2102. handHXInfos:this.logic.deepCloneTL(this.handHXInfos),
  2103. outCards:this.logic.deepCloneTL(this.outCards),
  2104. opData:gangData
  2105. }
  2106. this.setPaijuHuiFangData(M.GANG,pjhfsplist);/////TL++ 牌局回放 push杠操作数据
  2107. }
  2108. else{
  2109. this.logic.updateSYPS(i,[card],this.handCards[i],this.huCards,this.outCards,this.hutipdata[i]);
  2110. gangData.hutipdata = this.hutipdata[i];
  2111. }
  2112. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.GANG, data: gangData });
  2113. }
  2114. this.moOrChu = 3;
  2115. let gangDatapg = {
  2116. chairId: String(chairId),
  2117. currentId: this.currentId,
  2118. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2119. type: String(type),
  2120. card: String(card),
  2121. otherCards: _.cloneDeep(otherCards),
  2122. cards: this.handCards[chairId],
  2123. }
  2124. gangDatapg.hutipdata = {
  2125. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  2126. };
  2127. yield this.lookMsgAsync('paohuzi_event', { type: M.GANG, data: gangDatapg });////TL++
  2128. //下面这个if是庄家处理起手的3提五坎
  2129. if(phktdp){//跑后可提
  2130. // console.warn("跑后可提=============this.currentId ",chairId,this.currentId);
  2131. // return yield this.gangCardAsync(chairId,phktdp,2);
  2132. this.app.timer.setTimeout(() => this.yanchiAsync(3,chairId,phktdp,2), 600);
  2133. return { code: C.OK };
  2134. }
  2135. // console.warn("下面这个if是庄家处理起手的3提五坎 ",chairId,this.logic.isFPJD() , res.length);
  2136. if(!huRes && !this.logic.isFPJD()){//庄家必须出一张牌
  2137. let ckspsl = this.logic.getSPZS(this.handCards[chairId]);
  2138. // console.warn("?????????????????============= ",chairId,this.currentId,gwjsfjz,ckspsl,sfltlg);
  2139. if(gwjsfjz){
  2140. // console.warn("111111................111",gwjsfdyct);
  2141. // return this.touchCardAsync(this.currentId).then(() => ({ code: C.OK }));//////2个提的时候不用出牌给下家摸牌
  2142. let sffsbk = true;//是否发送八块
  2143. if(gwjsfdyct) sffsbk = false;
  2144. // console.warn("111111................111",sffsbk,gwjsfdyct);
  2145. return this.yanchiBaKuai(chairId,this.currentId,sffsbk).then(() => ({ code: C.OK }));
  2146. }
  2147. else {
  2148. if(ckspsl%3 == 1){
  2149. let nextId = (this.currentId + 1) % this.ccount;
  2150. // console.warn("111111................222",gwjsfdyct,this.currentId);
  2151. // if(gwjsfdyct) nextId = this.currentId;//编号1 的设置牌会出错故去掉了 去掉之后编号2 的设置牌会出错
  2152. // 为了解决上面的困境把上面的判断修改为了下面这样
  2153. let sffsbk = true;//是否发送八块
  2154. if(gwjsfdyct) {//该玩家是第一次提
  2155. let gwjcppltpgs = this.logic.getCPPLTPGS(this.huCards[chairId]);//该玩家吃碰牌里提跑个数
  2156. // console.warn("-----------------=========--------- ",gwjcppltpgs);
  2157. if(gwjcppltpgs == 1) {
  2158. nextId = this.currentId;
  2159. sffsbk = false;
  2160. }
  2161. }
  2162. // return this.touchCardAsync(nextId).then(() => ({ code: C.OK }));//////没有2个提的时候给摸牌
  2163. return this.yanchiBaKuai(this.currentId,nextId,sffsbk).then(() => ({ code: C.OK }));
  2164. }
  2165. else if(ckspsl%3 == 0){
  2166. // console.warn("111111................333");
  2167. if(sfltlg || this.everyDongState[chairId] == 1){
  2168. let nextId = (this.currentId + 1) % this.ccount;
  2169. // console.warn("111111................444");
  2170. // return this.touchCardAsync(nextId).then(() => ({ code: C.OK }));//////连提2个的时候给下家摸牌
  2171. return this.yanchiBaKuai(this.currentId,nextId,true).then(() => ({ code: C.OK }));
  2172. }
  2173. else{
  2174. let strcc = "table 杠牌出错了,id: "+this.id + " ,uid "+chairId+", ckspsl "+ ckspsl +" ,card "+card+" ,type "+type+" ,everysfdycpdt "+this.everysfdycpdt;
  2175. logger.error(strcc);////cssj
  2176. }
  2177. }
  2178. }
  2179. }
  2180. }
  2181. } else {
  2182. // 置于等待
  2183. this.masks[chairId] = 9;
  2184. this.gangType = type;
  2185. this.gangCard = card;
  2186. }
  2187. // let str4 = "table222 杠牌,id:"+this.id + ",uid"+chairId+","+ this.state +",card "+card;
  2188. // logger.info(str4);////cssj
  2189. return { code: C.OK };
  2190. });
  2191. // 偎牌
  2192. proto.weiCardAsync = cor(function* (chairId, card) {
  2193. let str3 = "table 偎牌id:%s "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +" ,card "+card;
  2194. logger.warn(str3);////cssj
  2195. // 参数校验
  2196. if (this.currentId != chairId) {
  2197. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  2198. }
  2199. // 权限校验
  2200. if (!(this.masks[chairId] & 32)) {
  2201. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  2202. }
  2203. let zzpsfgd = this.logic.getIsGuo(this.everyGDCPP[chairId],card);//这张牌是否过掉过
  2204. // console.warn("偎牌 zzpsfgd card everyGDCPP ",zzpsfgd,card,this.everyGDCPP[chairId]);
  2205. let res = this.logic.weiAnalyze(this.handCards[chairId], card, zzpsfgd);
  2206. if (!res) {
  2207. return { code: C.FAILD, msg: C.TABLE_PENG_ERROR };
  2208. }
  2209. // 记录偎牌
  2210. res.origin = this.currentId;
  2211. this.huCards[chairId].push(res);
  2212. this.everyCPHX[chairId] = this.logic.getCPHX(this.huCards[chairId]);
  2213. let yscdsz = [res.cards[0], res.cards[0]];//要删除的数组
  2214. let scspRes = this.logic.removes2(this.handCards[chairId], yscdsz);//删除手牌结果
  2215. this.handCards[chairId] = _.cloneDeep(scspRes.handCards);
  2216. this.handHXInfos[chairId] = _.cloneDeep(scspRes.handHXInfos);
  2217. // 清空权限
  2218. _.fill(this.masks, 0);
  2219. // 用户顺序
  2220. this.currentId = chairId;
  2221. let wpwjsfwpkc = this.logic.getSFWPKC2(this.handCards[chairId],this.handHXInfos[chairId]);//偎牌玩家是否无牌可出
  2222. if(this.everyDongState[chairId] != 1 && wpwjsfwpkc){
  2223. let sphxs = _.sum(this.handHXInfos[chairId].hxValues);//手牌胡息数
  2224. let cphx = this.everyCPHX[chairId];
  2225. if(sphxs+cphx < this.logic.khMinHX){
  2226. //至此是偎牌之后息数不够且无牌可出进洞了
  2227. this.everyDongState[chairId] = 1;//本局钻洞了
  2228. }
  2229. // console.warn("这里是偎牌之后无牌可出",this.handHXInfos[chairId].hxValues,sphxs,cphx);
  2230. }
  2231. this.isCanOut = true;//是否允许玩家手动出牌(偎牌)
  2232. if(this.everyDongState[chairId] == 1 || wpwjsfwpkc) this.isCanOut = false;
  2233. for (let i = 0; i < this.ccount; ++i) {
  2234. let weidata = {////这种一定要声明在for循环里面
  2235. chairId: String(chairId),
  2236. isCanOut: this.isCanOut,//是否允许玩家手动出牌
  2237. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2238. card: String(card),
  2239. type: res.type,
  2240. everyDongState: this.everyDongState,
  2241. }
  2242. if(i == chairId){
  2243. weidata.cards = this.handCards[chairId];
  2244. weidata.hxInfos = this.handHXInfos[chairId];
  2245. if(this.logic.isXYBCP(this.handCards[i],this.huCards[i])){
  2246. this.hutipdata[i] = this.logic.hutip2(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////偎牌调用胡牌提示
  2247. }
  2248. else {
  2249. this.hutipdata[i] = this.logic.hutip(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////偎牌调用胡牌提示
  2250. }
  2251. weidata.hutipdata = this.hutipdata[i];
  2252. }
  2253. else{
  2254. this.logic.updateSYPS(i,[card],this.handCards[i],this.huCards,this.outCards,this.hutipdata[i]);
  2255. weidata.hutipdata = this.hutipdata[i];
  2256. }
  2257. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.PAOHUZI_WEI, data: weidata });
  2258. }
  2259. this.moOrChu = 3;
  2260. let weidatapg = {////偎的旁观数据
  2261. chairId: String(chairId),
  2262. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2263. everyDongState: this.everyDongState,
  2264. card: String(card),
  2265. type: res.type,
  2266. }
  2267. weidatapg.hutipdata = {
  2268. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  2269. };
  2270. yield this.lookMsgAsync('paohuzi_event', { type: M.PAOHUZI_WEI, data: weidatapg });////TL++
  2271. ////20200831增加胡牌提示的时候把下面这句换成了上面那一段
  2272. let pjhfsplist = {
  2273. shouPai:this.logic.deepCloneTL(this.handCards),
  2274. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2275. handHXInfos:this.logic.deepCloneTL(this.handHXInfos),
  2276. everyDongState: this.logic.deepCloneTL(this.everyDongState),
  2277. lastCount:String(this.logic.leaveCount()),
  2278. outCards:this.logic.deepCloneTL(this.outCards),
  2279. opData:{ chairId: String(chairId), card: String(card),type: res.type, }
  2280. }
  2281. this.setPaijuHuiFangData(M.PAOHUZI_WEI,pjhfsplist);/////TL++ 牌局回放 push偎操作数据
  2282. if(this.everysfdycpdt[chairId]){
  2283. //下面是处理起手时非庄家的提
  2284. let qsCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  2285. let qstres = this.logic.anGangAnalyze(qsCards);
  2286. if(qstres.length > 0){
  2287. this.masks[chairId] |= 8;
  2288. //庄家打牌之后轮到闲家摸牌,在闲家摸牌之前先提掉该玩家手上所有的提
  2289. return yield this.gangCardAsync(chairId,qstres[0].card,2);
  2290. }
  2291. //处理起手时非庄家的提结束
  2292. }
  2293. this.sfwhkhqypkc = false;//偎牌玩家是否偎后可胡且有牌可出
  2294. if(this.everyDongState[chairId] != 1){
  2295. let huRes = this.logic.huAnalyze(chairId,this.handCards[chairId], card, this.huCards[chairId],true,false);
  2296. // console.error("ssccAAA胡牌分析 huRes",huRes);
  2297. if (huRes) {
  2298. this.huRes[chairId] = huRes;
  2299. this.masks[chairId] |= 16;
  2300. if(this.logic.getSFWPKC2(this.handCards[chairId],this.handHXInfos[chairId])){
  2301. // 偎牌之后可胡情况下若无牌可出则自动胡牌,
  2302. yield this.autoSysOperate(600,chairId,"hu",card);
  2303. }
  2304. else{
  2305. this.sfwhkhqypkc = true;
  2306. }
  2307. }
  2308. }
  2309. let gwjsfjz = this.logic.isXYBCP(this.handCards[chairId],this.huCards[chairId]);//该玩家是否需要进子
  2310. if(gwjsfjz || this.everyDongState[chairId] == 1){//2个提的时候需要进子不出牌
  2311. let oldCurr = this.currentId;
  2312. let nextId = (this.currentId + 1) % this.ccount;
  2313. this.currentId = nextId;
  2314. // console.warn("????????----???111偎牌 ",chairId);
  2315. // return this.touchCardAsync(this.currentId).then(() => ({ code: C.OK }));//////2个提的时候不用出牌给下家摸牌
  2316. return this.yanchiBaKuai(oldCurr,this.currentId,true).then(() => ({ code: C.OK }));
  2317. }
  2318. if(this.sfwhkhqypkc){
  2319. //偎牌之后可胡情况下若有牌可出则发此消息询问用户是过是胡;
  2320. this.masks[chairId] |= 64;
  2321. // console.warn("????????----???222偎牌 ",chairId);
  2322. yield this.pushMsgAsync(chairId, 'paohuzi_event', { type: M.PAOHUZI_WEIAFTER, data: {mask: String(this.masks[chairId])} });
  2323. }
  2324. return { code: C.OK };
  2325. });
  2326. // 碰牌
  2327. proto.pengCardAsync = cor(function* (chairId, card) {
  2328. let str3 = "table 碰牌id:%s "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +" ,card "+card;
  2329. logger.warn(str3);////cssj
  2330. // console.warn("碰牌============== ",card , this.moOrChu,this.moCard,this.outCard,this.currentId);
  2331. // 参数校验
  2332. if(this.moOrChu == 2){//2表示出
  2333. if (card != this.outCard || this.currentId == chairId) {
  2334. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  2335. }
  2336. }
  2337. if(this.moOrChu == 1){//1表示摸
  2338. if (card != this.moCard || this.currentId == chairId) {
  2339. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  2340. }
  2341. }
  2342. // 权限校验
  2343. if (!(this.masks[chairId] & 4)) {
  2344. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  2345. }
  2346. if (this.masks[chairId] & 16) this.logic.isGuoHuList[chairId][0] = true;
  2347. // 他人可胡杠
  2348. var cHuGang = _.findIndex(this.masks, (m) => (((m & 16) || (m & 8)) && !(m & 4)));
  2349. // console.warn("碰牌按钮被点击了 他人可胡杠",cHuGang,this.masks);
  2350. if (cHuGang == -1) {
  2351. let res = this.logic.peng(chairId,this.handCards[chairId], card);
  2352. if (!res) {
  2353. return { code: C.FAILD, msg: C.TABLE_PENG_ERROR };
  2354. }
  2355. /////TL++7月17日,这整个if的内容 和else的判断
  2356. let winner = this.winner;
  2357. if (winner.chs.length > 0) {
  2358. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  2359. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  2360. // console.warn("提前结算AAA");
  2361. yield this.concludeGameAsync(MODE.NORMAL);
  2362. }
  2363. else{
  2364. // 记录碰牌
  2365. res.origin = this.outerId;
  2366. // this.outCards[this.outerId].pop();
  2367. this.huCards[chairId].push(res);
  2368. this.everyCPHX[chairId] = this.logic.getCPHX(this.huCards[chairId]);
  2369. let scspRes = this.logic.removes2(this.handCards[chairId], [card, card]);//删除手牌结果
  2370. this.handCards[chairId] = _.cloneDeep(scspRes.handCards);
  2371. this.handHXInfos[chairId] = _.cloneDeep(scspRes.handHXInfos);
  2372. // 清空权限
  2373. this._eatType = 0;
  2374. this._bi1Type = 0;
  2375. this._bi2Type = 0;
  2376. this.gangType = 0;
  2377. this.gangCard = 0;
  2378. _.fill(this.masks, 0);
  2379. // 用户顺序
  2380. this.currentId = chairId;
  2381. this.isCanOut = true;//是否允许玩家手动出牌(碰牌)
  2382. for (let i = 0; i < this.ccount; ++i) {
  2383. let pengdata = {////这种一定要声明在for循环里面
  2384. chairId: String(chairId),
  2385. isCanOut: this.isCanOut,//是否允许玩家手动出牌
  2386. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2387. card: String(card),
  2388. isGuoHuList: this.logic.isGuoHuList[i]
  2389. }
  2390. if(i == chairId){
  2391. pengdata.cards = this.handCards[chairId];
  2392. pengdata.hxInfos = this.handHXInfos[chairId];
  2393. if(this.logic.isXYBCP(this.handCards[i],this.huCards[i])){
  2394. this.hutipdata[i] = this.logic.hutip2(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////碰牌调用胡牌提示
  2395. }
  2396. else {
  2397. this.hutipdata[i] = this.logic.hutip(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////碰牌调用胡牌提示
  2398. }
  2399. pengdata.hutipdata = this.hutipdata[i];
  2400. }
  2401. else{
  2402. this.logic.updateSYPS(i,[card],this.handCards[i],this.huCards,this.outCards,this.hutipdata[i]);
  2403. pengdata.hutipdata = this.hutipdata[i];
  2404. }
  2405. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.PENG, data: pengdata });
  2406. }
  2407. this.moOrChu = 3;
  2408. let pengdatapg = {////碰的旁观数据
  2409. chairId: String(chairId),
  2410. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2411. card: String(card)
  2412. }
  2413. pengdatapg.hutipdata = {
  2414. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  2415. };
  2416. yield this.lookMsgAsync('paohuzi_event', { type: M.PENG, data: pengdatapg });////TL++
  2417. ////20200831增加胡牌提示的时候把下面这句换成了上面那一段
  2418. // yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.PENG, data: { chairId: String(chairId), card: String(card) } });
  2419. let pjhfsplist = {
  2420. shouPai:this.logic.deepCloneTL(this.handCards),
  2421. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2422. handHXInfos:this.logic.deepCloneTL(this.handHXInfos),
  2423. lastCount:String(this.logic.leaveCount()),
  2424. outCards:this.logic.deepCloneTL(this.outCards),
  2425. isGuoHuList: this.logic.deepCloneTL(this.logic.isGuoHuList),
  2426. opData:{ chairId: String(chairId), card: String(card) }
  2427. }
  2428. this.setPaijuHuiFangData(M.PENG,pjhfsplist);/////TL++ 牌局回放 push碰操作数据
  2429. if(this.everysfdycpdt[chairId]){
  2430. //下面是处理起手时非庄家的提
  2431. let qsCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  2432. let qstres = this.logic.anGangAnalyze(qsCards);
  2433. if(qstres.length > 0){
  2434. this.masks[chairId] |= 8;
  2435. //庄家打牌之后轮到闲家摸牌,在闲家摸牌之前先提掉该玩家手上所有的提
  2436. return yield this.gangCardAsync(chairId,qstres[0].card,2);
  2437. }
  2438. //处理起手时非庄家的提结束
  2439. }
  2440. let gwjsfjz = this.logic.isXYBCP(this.handCards[chairId],this.huCards[chairId]);//该玩家是否需要进子
  2441. if(gwjsfjz){//2个提的时候需要进子不出牌
  2442. let oldCurr = this.currentId;
  2443. let nextId = (this.currentId + 1) % this.ccount;
  2444. this.currentId = nextId;
  2445. // return this.touchCardAsync(this.currentId).then(() => ({ code: C.OK }));//////2个提的时候不用出牌给下家摸牌
  2446. return this.yanchiBaKuai(oldCurr,this.currentId,true).then(() => ({ code: C.OK }));
  2447. }
  2448. }
  2449. } else {
  2450. // 置于等待
  2451. this.masks[chairId] = 5;
  2452. // 查找等待 TL++下面这一段,为了解决A打出一张牌之后B可吃胡C可碰情况下 C先点碰B点吃会死掉的问题 这是原始代码的重大天然Bug
  2453. let cGang = -1
  2454. let cPeng = -1;
  2455. let _cChi = -1;
  2456. // console.warn("这里是啥情况啊",this.masks);
  2457. for (let i = 0; i < this.masks.length; ++i) {
  2458. // if (i == this.currentId || i == chairId) continue;///////TL++zsyl 这种写法会导致拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  2459. if (i == chairId) continue;//////TL++,为了解决拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  2460. if (this.masks[i] == 9) {
  2461. cGang = i;
  2462. continue;
  2463. }
  2464. if (this.masks[i] == 5) {
  2465. cPeng = i;
  2466. continue;
  2467. }
  2468. if (this.masks[i] == 3) {
  2469. _cChi = i;
  2470. continue;
  2471. }
  2472. }
  2473. // console.warn("ppppppppppp444 ",chairId,cGang,cPeng,_cChi);
  2474. // console.warn("2222情况啊",cGang, this.gangType,this.gangCard);
  2475. // 杠
  2476. if (cGang != -1 && this.gangType > 0 && this.gangCard > 0) {
  2477. return this.gangCardAsync(cGang, this.gangCard, this.gangType).then(() => ({ code: C.OK }));
  2478. }
  2479. }
  2480. // let str4 = "table 碰牌id:%s"+this.id + ",uid"+chairId+","+ this.state +" card "+card;
  2481. // logger.info(str4);////cssj
  2482. return { code: C.OK };
  2483. });
  2484. // 吃牌,1-@**左吃, 2-*@*中吃, 3-@**右吃
  2485. proto.eatCardAsync = cor(function* (chairId, card, type, bi1Type, bi2Type) {
  2486. let str3 = "table 吃牌id:%s "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks +",card "+card+",type "+type+",bi1Type "+bi1Type+",bi2Type "+bi2Type;
  2487. logger.warn(str3);////cssj
  2488. // 参数校验
  2489. if (!type && (type < 1 || type > 6)) {
  2490. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  2491. }
  2492. if (this.moOrChu == 2 && card != this.outCard) {
  2493. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  2494. }
  2495. // 权限校验
  2496. if (!(this.masks[chairId] & 2)) {
  2497. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  2498. }
  2499. let chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  2500. if (this.masks[chairId] & 2) {
  2501. let mpwjdxj = (this.moChair + 1) % this.ccount;//摸牌玩家的下家
  2502. if(this.moOrChu == 1 && mpwjdxj == chairId) chiBiArr = this.chiBiArrxj;
  2503. else chiBiArr = this.chiBiArr; //吃牌时吃比数据
  2504. }
  2505. if(!this.logic.checkChiData(type,chiBiArr.cdpsszs,bi1Type,bi2Type)){
  2506. // console.warn("da0ppppppppoooooooooooooo");
  2507. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  2508. }
  2509. if (this.masks[chairId] & 16) this.logic.isGuoHuList[chairId][0] = true;
  2510. // if(this.logic.isGuoHuList[chairId][0]) this.logic.isGuoHuList[chairId][0] = false;/////TL++,吃牌设置过胡玩家的是否点击过胡为false;
  2511. // 他人可胡杠碰
  2512. // 这是麻将的写法,因为麻将里能吃的人只有1个,下面这样判断的目的是排除吃牌者之外的人有没有碰杠胡
  2513. // var cHuGangPeng = _.findIndex(this.masks, (m) => (((m & 16) || (m & 8) || (m & 4)) && !(m & 2)));
  2514. //上面这行不适用吃同时存在,为了解决摸牌者和摸牌者的下家都能吃摸牌者摸到的牌(摸牌者优先)问题把上面这行改为下面这段
  2515. var cHuGangPeng = -1;//除操作吃之外可碰杠胡的玩家
  2516. var qtkcwj = -1;//除操作吃之外可吃的玩家
  2517. for (let i = 0; i < this.masks.length; ++i) {
  2518. if(i == chairId) continue;
  2519. let maskItem = this.masks[i];
  2520. if((maskItem & 16) || (maskItem & 8) || (maskItem & 4)) cHuGangPeng = i;
  2521. if ((maskItem & 2)) qtkcwj = i;
  2522. }
  2523. if (cHuGangPeng == -1 && qtkcwj != -1) {
  2524. //至此是除操作吃牌顽疾之外其他玩家没有可以碰杠胡,且有人可吃
  2525. if(this.moOrChu == 1 && this.moChair == qtkcwj){
  2526. //只有在摸牌阶段才会可以2个人同时吃,且摸牌者优先
  2527. cHuGangPeng = qtkcwj;
  2528. }
  2529. }
  2530. if (cHuGangPeng == -1) {
  2531. let res = this.logic.chi(this.handCards[chairId], card, type, chiBiArr.cdpsszs, bi1Type, bi2Type, this.outerId, chairId);
  2532. if (res.length == 0) {
  2533. return { code: C.FAILD, msg: C.TABLE_CARD_ERROR };
  2534. }
  2535. /////TL++7月17日,这整个if的内容 和else的判断
  2536. let winner = this.winner;
  2537. // console.warn("222他人可胡杠碰",winner.chs.length);
  2538. if (winner.chs.length > 0) {
  2539. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  2540. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  2541. // console.warn("提前结算aaa");
  2542. yield this.concludeGameAsync(MODE.NORMAL);
  2543. }
  2544. else{
  2545. // 记录吃牌
  2546. // this.outCards[this.outerId].pop();
  2547. for (var i = 0; i < res.length; i++) {
  2548. this.huCards[chairId].push(res[i]);
  2549. }
  2550. this.everyCPHX[chairId] = this.logic.getCPHX(this.huCards[chairId]);
  2551. // if (type == 1) {
  2552. // this.logic.remove(this.handCards[chairId], [card + 1, card + 2]);
  2553. // } else if (type == 2) {
  2554. // this.logic.remove(this.handCards[chairId], [card - 1, card + 1]);
  2555. // } else {
  2556. // this.logic.remove(this.handCards[chairId], [card - 2, card - 1]);
  2557. // }
  2558. let needRemoves = this.logic.getChiAllNeedRemoves(card,type, chiBiArr.cdpsszs, bi1Type, bi2Type);
  2559. let scspRes = this.logic.removes2(this.handCards[chairId], needRemoves);//删除手牌结果
  2560. this.handCards[chairId] = _.cloneDeep(scspRes.handCards);
  2561. this.handHXInfos[chairId] = _.cloneDeep(scspRes.handHXInfos);
  2562. // 清空权限
  2563. this._eatType = 0;
  2564. this._bi1Type = 0;
  2565. this._bi2Type = 0;
  2566. this.gangType = 0;
  2567. this.gangCard = 0;
  2568. _.fill(this.masks, 0);
  2569. // 用户顺序
  2570. this.currentId = chairId;
  2571. this.isCanOut = true;//是否允许玩家手动出牌(吃牌)
  2572. // 发送通知
  2573. for (let i = 0; i < this.ccount; ++i) {
  2574. let chidata = {
  2575. chairId: String(chairId),
  2576. isCanOut: this.isCanOut,//是否允许玩家手动出牌
  2577. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2578. type: String(type),
  2579. bi1Type: String(bi1Type),
  2580. bi2Type: String(bi2Type),
  2581. card: String(card)
  2582. }
  2583. if(i == chairId){
  2584. chidata.cards = this.handCards[chairId];
  2585. chidata.hxInfos = this.handHXInfos[chairId];
  2586. if(this.logic.isXYBCP(this.handCards[i],this.huCards[i])){
  2587. this.hutipdata[i] = this.logic.hutip2(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////吃牌调用胡牌提示
  2588. }
  2589. else {
  2590. this.hutipdata[i] = this.logic.hutip(i,this.handCards[i],this.huCards[i],this.huCards,this.outCards);////吃牌调用胡牌提示
  2591. }
  2592. chidata.hutipdata = this.hutipdata[i];
  2593. }
  2594. else{
  2595. this.logic.updateSYPS(i,needRemoves,this.handCards[i],this.huCards,this.outCards,this.hutipdata[i]);
  2596. chidata.hutipdata = this.hutipdata[i];
  2597. }
  2598. yield this.pushMsgAsync(i, 'paohuzi_event', { type: M.CHI, data: chidata });
  2599. }
  2600. // console.warn("MMMMMMMMMMMMMM666 ",this.huCards[chairId]);
  2601. this.moOrChu = 3;
  2602. this.chiBiArr = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //吃牌时吃比数据
  2603. this.chiBiArrxj = {cdpsszs:-1,chi:[],bi1:[],bi2:[]}; //摸牌者下家吃摸牌者摸的牌时吃比数据
  2604. let chidatapg = { ////TL++吃牌旁观数据
  2605. chairId: String(chairId),
  2606. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2607. type: String(type),
  2608. bi1Type: String(bi1Type),
  2609. bi2Type: String(bi2Type),
  2610. card: String(card),
  2611. isGuoHuList: this.logic.isGuoHuList[chairId]
  2612. }
  2613. chidatapg.hutipdata = {
  2614. kehuData:[]/////对象数组,分别表示打哪张可胡哪几张数据
  2615. };
  2616. yield this.lookMsgAsync('paohuzi_event', { type: M.CHI, data: chidatapg });////TL++吃牌旁观消息
  2617. ////20200901为了增加胡牌提示把下面这一段换成了上面那一段
  2618. // yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.CHI, data: { chairId: String(chairId), type: String(type), card: String(card) } });
  2619. let pjhfsplist = {
  2620. shouPai:this.logic.deepCloneTL(this.handCards),
  2621. everyCPHX: this.everyCPHX,//每个玩家的吃碰胡息
  2622. handHXInfos:this.logic.deepCloneTL(this.handHXInfos),
  2623. lastCount:String(this.logic.leaveCount()),
  2624. outCards:this.logic.deepCloneTL(this.outCards),
  2625. isGuoHuList: this.logic.deepCloneTL(this.logic.isGuoHuList),
  2626. opData:{chairId: String(chairId), type: String(type),bi1Type: String(bi1Type),
  2627. bi2Type: String(bi2Type), card: String(card)}
  2628. }
  2629. this.setPaijuHuiFangData(M.CHI,pjhfsplist);/////TL++ 牌局回放 push吃操作数据
  2630. if(this.everysfdycpdt[chairId]){
  2631. //下面是处理起手时非庄家的提
  2632. let qsCards = this.logic.arr2ToArr1(this.handCards[chairId],true);
  2633. let qstres = this.logic.anGangAnalyze(qsCards);
  2634. if(qstres.length > 0){
  2635. this.masks[chairId] |= 8;
  2636. //庄家打牌之后轮到闲家摸牌,在闲家摸牌之前先提掉该玩家手上所有的提
  2637. return yield this.gangCardAsync(chairId,qstres[0].card,2);
  2638. }
  2639. //处理起手时非庄家的提结束
  2640. }
  2641. let gwjsfjz = this.logic.isXYBCP(this.handCards[chairId],this.huCards[chairId]);//该玩家是否需要进子
  2642. if(gwjsfjz){//2个提的时候需要进子不出牌
  2643. let oldCurr = this.currentId;
  2644. let nextId = (this.currentId + 1) % this.ccount;
  2645. this.currentId = nextId;
  2646. // return this.touchCardAsync(this.currentId).then(() => ({ code: C.OK }));//////2个提的时候不用出牌给下家摸牌
  2647. return this.yanchiBaKuai(oldCurr,this.currentId,true).then(() => ({ code: C.OK }));
  2648. }
  2649. }
  2650. } else {
  2651. // 置于等待
  2652. let old_eatType = this._eatType;
  2653. let old_bi1Type = this._bi1Type;
  2654. let old_bi2Type = this._bi2Type;
  2655. let ddcwj = _.findIndex(this.masks, (m, i) => (m == 3));//等待吃的玩家
  2656. this.masks[chairId] = 3;
  2657. this._eatType = type;
  2658. this._bi1Type = bi1Type;
  2659. this._bi2Type = bi2Type;
  2660. // console.warn("----------================111 ",chairId,ddcwj,this.moChair,this.masks);
  2661. //增加下面这段是为了解决A摸203时AB都可吃C可碰或跑或胡时A点吃之后B点吃C点过之后A玩家持牌错误的bug
  2662. if(this.moOrChu == 1 && ddcwj != -1){
  2663. if(this.moChair == chairId && ddcwj != this.moChair){
  2664. //至此是有非摸牌者等待吃摸牌者摸到的牌,把摸牌时非摸牌者等待吃去掉
  2665. this.masks[ddcwj] = 0;
  2666. }
  2667. if(this.moChair != chairId && ddcwj == this.moChair){
  2668. //至此是有摸牌者等待吃自己摸到的牌,把摸牌时非摸牌者等待吃去掉
  2669. this.masks[chairId] = 0;
  2670. this._eatType = old_eatType;
  2671. this._bi1Type = old_bi1Type;
  2672. this._bi2Type = old_bi2Type;
  2673. }
  2674. }
  2675. // console.warn("----------================222 ",this._eatType,this._bi1Type,this.masks[ddcwj],this.masks);
  2676. // 查找等待 TL++下面这一段,为了解决A打出一张牌之后B可吃胡C可碰情况下 C先点碰B点吃会死掉的问题 这是原始代码的重大天然Bug
  2677. let cGang = -1
  2678. let cPeng = -1;
  2679. let _cChi = -1;
  2680. // console.warn("这里是啥情况啊",this.masks);
  2681. for (let i = 0; i < this.masks.length; ++i) {
  2682. // if (i == this.currentId || i == chairId) continue;///////TL++zsyl 这种写法会导致拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  2683. // if (i == chairId) continue;//////TL++,为了解决拉杠胡的玩家点击过胡之后被拉杠胡的玩家杠不出来的问题
  2684. if (this.masks[i] == 9) {
  2685. cGang = i;
  2686. continue;
  2687. }
  2688. if (this.masks[i] == 5) {
  2689. cPeng = i;
  2690. continue;
  2691. }
  2692. if (this.masks[i] == 3) {
  2693. _cChi = i;
  2694. continue;
  2695. }
  2696. }
  2697. // console.warn("2222情况啊",cGang, this.gangType,this.gangCard);
  2698. // 杠碰吃
  2699. if (cGang != -1 && this.gangType > 0 && this.gangCard > 0) {
  2700. return this.gangCardAsync(cGang, this.gangCard, this.gangType).then(() => ({ code: C.OK }));
  2701. } else if (cPeng != -1) {
  2702. if(this.moOrChu == 1){
  2703. return this.pengCardAsync(cPeng, this.liangZi).then(() => ({ code: C.OK }));
  2704. }
  2705. return this.pengCardAsync(cPeng, this.outCard).then(() => ({ code: C.OK }));
  2706. } else if (_cChi != -1 && this._eatType > 0 && cHuGangPeng == -1) {
  2707. //cHuGangPeng == -1是为了解决A摸203时AB都可吃C可碰或跑或胡时AB点碰之后陷入死循环的bug
  2708. if(this.moOrChu == 1){
  2709. return this.eatCardAsync(_cChi, this.liangZi, this._eatType,this._bi1Type,this._bi2Type).then(() => ({ code: C.OK }));
  2710. }
  2711. return this.eatCardAsync(_cChi, this.outCard, this._eatType,this._bi1Type,this._bi2Type).then(() => ({ code: C.OK }));
  2712. }
  2713. }
  2714. // let str4 = "table 吃牌id:"+this.id + ",uid"+chairId+","+ this.state +",card "+card;
  2715. // logger.info(str4);////cssj
  2716. return { code: C.OK };
  2717. });
  2718. //发生打子(八块)消息,因为有吃碰偎提跑之后是八块的话则不出牌而是给下家摸牌
  2719. proto.yanchiBaKuai = cor(function* (bkchairId,mochairId,isbk) {
  2720. let moycsj = 1000;
  2721. if(isbk) moycsj = 2100;
  2722. if(!this.bakuaiTimer && isbk){
  2723. this.bakuaiTimer = this.app.timer.setTimeout(() => this.sendBaKuai(bkchairId), 1000);
  2724. }
  2725. if(!this.ycMoTimer){
  2726. this.ycMoTimer = this.app.timer.setTimeout(() => this.yanchiTouch(mochairId), moycsj);
  2727. }
  2728. });
  2729. //发生打子(八块)消息,因为有吃碰偎提跑之后是八块的话则不出牌而是给下家摸牌
  2730. proto.sendBaKuai = cor(function* (chairId,isbk) {
  2731. if(this.bakuaiTimer){
  2732. clearTimeout(this.bakuaiTimer);
  2733. this.bakuaiTimer = null;
  2734. }
  2735. return yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.SEED, data: { chairId: String(chairId)} });
  2736. });
  2737. //延迟执行摸牌函数,用于前端有时间播放”八块”的动画和音效
  2738. proto.yanchiTouch = cor(function* (chairId) {
  2739. if(this.ycMoTimer){
  2740. clearTimeout(this.ycMoTimer);
  2741. this.ycMoTimer = null;
  2742. }
  2743. return yield this.touchCardAsync(chairId);
  2744. });
  2745. // 操作是否自动出牌
  2746. proto.autoOutCardAsync = cor(function* (chairId) {
  2747. // console.warn("操作是否自动出牌 "+chairId);
  2748. // if(this.everyIsAutoOut[chairId]) this.everyIsAutoOut[chairId] = 0;
  2749. // else this.everyIsAutoOut[chairId] = 1;
  2750. // return { code: C.OK,isAutoOut:this.everyIsAutoOut[chairId]};
  2751. })
  2752. // 胡牌 处理前端
  2753. proto.succCardAsync = cor(function* (chairId) {
  2754. let str3 = "table 胡牌:%s "+this.id + " ,uid "+chairId+" ,this.masks "+ this.masks;
  2755. logger.warn(str3);////cssj
  2756. // 权限校验
  2757. if (!(this.masks[chairId] & 16)) {
  2758. return { code: C.FAILD, msg: C.TABLE_MASK_ERROR };
  2759. }
  2760. // 删除权限
  2761. this.masks[chairId] = 0;
  2762. // 是否自摸
  2763. let winner = this.winner;
  2764. // var isMoHu = (this.currentId == chairId);
  2765. var isMoHu = (this.moChair == chairId);
  2766. // console.warn(" 胡牌 处理前端 chairId, currentId, outerId ",chairId,this.currentId,this.outerId);
  2767. // console.warn(" 胡牌 处理前端111 ",isMoHu,winner,this.winner);
  2768. if (isMoHu) {
  2769. winner.chs[0] = chairId;
  2770. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  2771. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push摸胡牌数据
  2772. // console.warn("提前结算444");
  2773. yield this.concludeGameAsync(MODE.NORMAL);
  2774. } else {
  2775. // 抢杠胡
  2776. if (this.isGangHu) {
  2777. winner.lead = this.currentId;
  2778. // 抢杠牌
  2779. if (this.gangType > 0 && this.gangCard > 0) {
  2780. this.logic.remove(this.handCards[this.currentId], this.gangCard);
  2781. this.masks[this.currentId] = 0;
  2782. this.gangType = 0; this.gangCard = 0;
  2783. }
  2784. } else {
  2785. // 点炮
  2786. // console.warn("outerId ",this.outerId,"moOrChu ",this.moOrChu,"moChair ",this.moChair,"currentId ",this.currentId);
  2787. winner.lead = this.outerId;
  2788. if(this.logic.isFPJD() || this.moOrChu == 1){
  2789. winner.lead = this.currentId;
  2790. }
  2791. }
  2792. // 胡牌者
  2793. if (winner.chs.length <= 0) winner.chs[0] = chairId;
  2794. else {
  2795. /////有多个人点击胡牌的时候,按照打牌顺序找出距离出牌人最近的人设置为这次的赢家
  2796. let dist = (winner.chs[0] - winner.lead + this.ccount) % this.ccount;
  2797. if ((chairId - winner.lead + this.ccount) % this.ccount < dist) winner.chs[0] = chairId;
  2798. }
  2799. // 他人可胡
  2800. let __cHu = _.findIndex(this.masks, (m, i) => ((m & 16)))
  2801. // console.warn("22局部变量改变全局变量",winner ,this.winner);
  2802. // console.warn("点击胡按钮",__cHu,this.masks);
  2803. if (__cHu == -1) {
  2804. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.HU, data: { lead: String(winner.lead), chairIds: winner.chs } });
  2805. this.setPaijuHuiFangData(M.HU,{ lead: String(winner.lead), chairIds: winner.chs });/////TL++ 牌局回放 push吃胡牌数据
  2806. // console.warn("提前结算555");
  2807. yield this.concludeGameAsync(MODE.NORMAL);
  2808. }
  2809. }
  2810. return { code: C.OK };
  2811. });
  2812. // 结算游戏
  2813. proto.concludeGameAsync = cor(function* (mode) {
  2814. /////增加下面这几行是为了保证每一把只执行一次结算方法
  2815. if(this.isYJJSGL){
  2816. // let strk = "table 结算游戏 id:了保证每一把只执行一次结算方法 "+this.id +"结算模式"+mode
  2817. // logger.info(strk);////cssj
  2818. return;
  2819. }
  2820. this.isYJJSGL = true;
  2821. this.isYJKSGL = false;/////是否已经执行过开始函数了
  2822. this.everyIsAutoOut = _.fill(Array(this.ccount), 0);
  2823. // console.warn("结算函数",mode);
  2824. let str1 = "table 结算游戏 id: "+this.id +" 结算模式 "+mode
  2825. logger.warn(str1);////cssj
  2826. //ts--end
  2827. // 结算数据
  2828. var winner = this.winner;
  2829. var data = { mode: String(mode),yjchair:-1, lead: String(winner.lead) };
  2830. var wins = this.logic.fillDeep(Array(this.ccount), {
  2831. win: 0,//总输赢
  2832. isPoChan: 0,
  2833. shiJiKouFen: 0,
  2834. cardfen: 0,
  2835. });
  2836. data.banker = this.chBanker;/////TL++
  2837. let isMZJYM = false;//是否满足无红中加一码
  2838. // console.warn("结算游戏 huRes ",JSON.stringify(this.huRes));
  2839. data.hxInfos = {}
  2840. //ts++胡的人
  2841. let hu=-1;
  2842. if (winner.chs.length >0 && winner.chs[0] >= 0 && winner.chs[0] <= 2)
  2843. {
  2844. hu=winner.chs[0];
  2845. if(this.paoHuQK[0] == hu && this.paoHuQK[1] && this.paoHuQK[2] > 0){
  2846. let kpIndex = -1;
  2847. for (let i = 0; i < this.huCards[hu].length; ++i) {
  2848. if(this.huCards[hu][i].card != this.paoHuQK[2]) continue;
  2849. let stylelx = this.huCards[hu][i].style;
  2850. if (stylelx == Logic.STYLE.PENG || stylelx == Logic.STYLE.WEI) {
  2851. kpIndex = i;
  2852. break;
  2853. }
  2854. }
  2855. if(kpIndex > -1){
  2856. this.huCards[hu][kpIndex].style = Logic.STYLE.ZMGANG;
  2857. this.huCards[hu][kpIndex].cards.push(this.paoHuQK[2]);
  2858. }
  2859. }
  2860. data.hxInfos = this.logic.getWinerHXInfo(this.huRes[hu],this.huCards[hu]);
  2861. }
  2862. // console.warn("???????????????/ ",hu,JSON.stringify(this.huRes));
  2863. // 1 [null,{"zdhx":20,"card":108,"cards":[[201,201]],"hxInfos":{"styles":[0],"hxTypes":[0],"hxValues":[0]}}]
  2864. data.hutype = [];
  2865. data.allFan = 0;
  2866. let typeInfo = {hutype:[],allFan:0}
  2867. if(hu > -1){
  2868. data.yjchair = hu;
  2869. typeInfo = this.logic.isGetCardTypeTL(hu,this.huRes[hu].cards,this.huCards[hu],[],winner.lead == -1,this.huRes[hu].card)
  2870. data.hutype = typeInfo.hutype;
  2871. data.allFan = typeInfo.allFan;
  2872. }
  2873. data.lastCards = this.logic.getSYPaiDui();//剩余牌堆
  2874. let yjgs = 0;//赢家个数
  2875. // 计算输赢
  2876. for (let i = 0; i < wins.length; ++i) {
  2877. // 自摸
  2878. let isMoHu = winner.lead == -1;
  2879. let zdhx = 0;//最大胡息
  2880. let allTun = 0;//总的囤数
  2881. if(this.huRes[i] && this.huRes[i].zdhx){
  2882. zdhx = this.huRes[i].zdhx;
  2883. if(zdhx >= this.logic.khMinHX){
  2884. allTun = this.cell + this.tunshuValue;
  2885. if(isMoHu) allTun += 1;
  2886. allTun += Math.floor((zdhx - this.logic.khMinHX) / 3)
  2887. }
  2888. }
  2889. wins[i].zdhx = zdhx;
  2890. wins[i].allTun = allTun;
  2891. // 胡牌者
  2892. if (winner.chs.indexOf(i) != -1) {
  2893. yjgs++;
  2894. let sy = allTun * typeInfo.allFan;
  2895. if(sy > this.fengDingValue && this.fengDingValue > 0) sy = this.fengDingValue;
  2896. let yjdzt = this.everyDongState[i];//本局玩家的钻洞状态
  2897. if(sy > 0 && yjdzt == 1 || yjdzt == 2){
  2898. sy = 0;//钻洞玩家赢了不得分然后出洞
  2899. this.everyDongState[i] = 3;
  2900. }
  2901. wins.forEach((w, c) => {
  2902. if (c != i) {
  2903. w.win -= sy;
  2904. wins[i].win += sy;
  2905. w.cardfen -= sy;
  2906. wins[i].cardfen += sy;
  2907. }
  2908. });
  2909. wins[i].lucky = 1;
  2910. }
  2911. if(hu == -1) data.hxInfos = this.logic.deepCloneTL(this.handHXInfos[i]);
  2912. // 手牌
  2913. let cards = { card: 0, groups: [], hands: []};
  2914. if (wins[i].lucky) {
  2915. cards.card = this.huRes[i].card;
  2916. }
  2917. for (let huCard of this.huCards[i]) {
  2918. cards.groups.push({ style: huCard.style, type: huCard.type, card: huCard.card });
  2919. }
  2920. // console.warn("----------------------------------?????????????? ",i,this.handCards[i],this.huRes[i].cards);
  2921. cards.hands = this.handCards[i];
  2922. if(hu == i && this.huRes[i] && this.huRes[i].cards){
  2923. cards.hands = this.huRes[i].cards;
  2924. }
  2925. wins[i].cards = cards;
  2926. }
  2927. // let str3 = "table 333结算函数---id:"+this.id +",结算模式"+mode
  2928. // logger.info(str3);////cssj
  2929. //////TL++
  2930. let shiJiKouFen = [];
  2931. if(this.playerAllCount == 2) shiJiKouFen = [wins[0].win,wins[1].win];
  2932. else if(this.playerAllCount == 3) shiJiKouFen = [wins[0].win,wins[1].win,wins[2].win];
  2933. else if(this.playerAllCount == 4) shiJiKouFen = [wins[0].win,wins[1].win,wins[2].win,wins[3].win];
  2934. for (let i = 0; i < this.ccount; ++i) {
  2935. wins[i].shiJiKouFen = shiJiKouFen[i];
  2936. }
  2937. //console.warn("实际扣分XXX",shiJiKouFen,wins[0].win,wins[1].win,wins[2].win,wins[3].win)
  2938. // 胜负情况
  2939. data.wins = wins;
  2940. data.everyDongState = _.cloneDeep(this.everyDongState);
  2941. let bjsy = [];//本局每个人的输赢
  2942. for (let i = 0; i < this.ccount; ++i) {
  2943. // bjsy[i] = wins[i].win;
  2944. let zhx = 0;//总胡息
  2945. let cdts = 0;//充的囤数
  2946. let iszm = 0;//是否自摸
  2947. let zts = 0;//总囤数
  2948. if(data.yjchair == i){
  2949. zhx = wins[i].zdhx;
  2950. cdts = this.tunshuValue;
  2951. if(data.lead == -1) iszm = 1;
  2952. zts = wins[i].allTun;
  2953. }
  2954. let zhanjiItem = {
  2955. zf: wins[i].win,
  2956. zhx: zhx,
  2957. cdts: cdts,
  2958. iszm: iszm,
  2959. zts: zts,
  2960. }
  2961. bjsy[i] = zhanjiItem;
  2962. }
  2963. this.sszjDataList[this.sszjDataList.length] = bjsy;
  2964. this.over += 1;// 局数+1
  2965. //ts++
  2966. let sszjScore = [];//ts++实时本局成绩
  2967. let sszjAllScore = [];//ts++实时总成绩
  2968. // 记录分数
  2969. for (let i = 0; i < this.ccount; ++i) {
  2970. let user = this.users[i];
  2971. if (user)
  2972. {
  2973. sszjScore[i] = shiJiKouFen[i];
  2974. this.score.writeScore(user.id,shiJiKouFen[i], 1);//设置分数
  2975. sszjAllScore[i] = this.score.getScore(user.id);
  2976. // if(this.gameKindTL == 2) sszjAllScore[i] -=200;
  2977. if(this.over == 1)
  2978. {
  2979. this.score.writeCost(user.id,this.cost, 0); //ts++设置消耗
  2980. }
  2981. }
  2982. }
  2983. let endmode=ENDMODE.PLAYING;
  2984. if(this.isGameOver())
  2985. {
  2986. this.isGameOk=true;
  2987. endmode=ENDMODE.NORMALEND;//局数完成--正常结束
  2988. }
  2989. data.isover = this.isGameOk;
  2990. data.nowTime = Date.now();
  2991. // let str4 = "table 444结算函数---id:%s"+this.id +"结算模式"+mode
  2992. // logger.info(str4);////cssj
  2993. //ts++实时战绩
  2994. //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});
  2995. this.sszjs.push({_id: String(this.over),sszjScore:sszjScore,sszjAllScore:sszjAllScore,banker:this.chBanker,hu:hu,pao:winner.lead});
  2996. //处理点灯规则的当前剩余灯数
  2997. let otherstr = ""+this.other;
  2998. if(this.gameKindTL == 1 || this.gameKindTL == 2) {
  2999. if(hu == -1) {
  3000. this.logic.dengshuValue++;//流局则灯数+1
  3001. if(this.logic.dengshuValue > 1 && parseInt(otherstr[1]) != 1) this.logic.dengshuValue = 1;//没勾选点灯规则的话灯数不累加
  3002. }
  3003. else if(hu != this.chBanker && this.logic.dengshuValue > 0) this.logic.dengshuValue--;//闲家赢了则灯数不变
  3004. }
  3005. // 切换庄家,谁赢谁做庄,荒庄之后庄家不变
  3006. if(yjgs == 1){
  3007. //只有一个人赢了,谁赢谁做庄
  3008. this.chBanker = winner.chs[0];
  3009. }
  3010. else{
  3011. if(hu == -1) {
  3012. //流局之后 没有黄规则的时候(土跑胡)流局之后切换庄家为庄家的下一家
  3013. if(this.gameKindTL == 3) this.chBanker = (this.chBanker + 1) % this.ccount;
  3014. }
  3015. }
  3016. /////TL++,10月9号,为了解决冲刺时前端的玩家分数偶尔会显示负数的bug
  3017. data.playNowScore = [];
  3018. for (let i = 0; i < this.ccount; ++i) {
  3019. let user = this.users[i];
  3020. if (user)
  3021. {
  3022. data.playNowScore[i] = this.score.getScore(user.id);
  3023. }
  3024. }
  3025. this.setPaijuHuiFangData(M.CONCLUDE,data);/////TL++ 牌局回放 push结算数据
  3026. /////TL++,用于记录玩家牌局回放的json文件名
  3027. this.pjhffileName[this.pjhffileName.length] = this.PJHF.getjsonFileName(this.over,this.recordid,this.ctime);
  3028. // 重置本局
  3029. this.resetRound();
  3030. // 结算通知
  3031. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.CONCLUDE, data: data });
  3032. this.PJHF.writePJHFJson({"pjhfDataList":this.PaijuHuiFang},this.over,this.id)
  3033. this.logic.isZHYZ = false; /////TL++,是否最后一张
  3034. // yield this.pushMsgAsync(-1, 'paohuzi_event', { type: 100, data: {"pjhfDataList":this.PaijuHuiFang}});//////最终发送给前端的牌局回放
  3035. // let str6 = "table end 结算函数-id:"+this.id +"结算模式"+mode
  3036. // logger.info(str6);////cssj
  3037. yield this.endResultAsync(endmode);
  3038. });
  3039. // 发送聊天
  3040. proto.sendMsgAsync = cor(function* (chairId, msg) {
  3041. // console.error("sscc发送聊天+++++++++++++++++++++++++++++++++",chairId,msg)
  3042. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.CHAT, data: { chairId: String(chairId), msg: msg } });
  3043. return { code: C.OK };
  3044. });
  3045. // 收费聊天 礼物收费
  3046. proto.vsendMsgAsync = cor(function* (schairId, dchairId, msg) {
  3047. if (schairId == dchairId || !this.users[dchairId]) {
  3048. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  3049. }
  3050. let user = this.users[schairId];
  3051. if (!user) {
  3052. return { code: C.FAILD, msg: C.TABLE_NOT_USER };
  3053. }
  3054. let lwcost = this.LWKF[msg.type];//////TL++礼物扣费
  3055. if(lwcost > 0){
  3056. var player = yield this.app.models.Player.findByIdAsync(user.id, 'diamond');
  3057. if(player)
  3058. {
  3059. if (((player.diamond) || 0) < lwcost) {
  3060. return { code: C.FAILD, msg: C.GAME_DIAMOND_LOW };
  3061. }
  3062. let dSource=player.diamond;
  3063. let dNow=player.diamond-lwcost;
  3064. player.diamond -= lwcost;
  3065. yield player.saveAsync();
  3066. // 钻石记录
  3067. var diamondrecord = new this.app.models.DiamondRecord({
  3068. _id: uuid.v1(),
  3069. playerId: user.id,
  3070. dType: 5,//礼物
  3071. dSource: dSource,
  3072. dSwap: -lwcost,
  3073. dNow: dNow,
  3074. tableId: this.recordid
  3075. });
  3076. yield diamondrecord.saveAsync();
  3077. //ts++设置消耗
  3078. // this.score.writeCost(user.id,0, lwcost);
  3079. }
  3080. }
  3081. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.FEE_CHAT, data: { cost: String(lwcost),schairId: String(schairId), dchairId: String(dchairId), msg: msg } });
  3082. return { code: C.OK };
  3083. });
  3084. //ts++写分 endtype = { 正常: 0,局数完成: 1, 房主解散: 2, 申请解散: 3 ,超时解散: 4 };
  3085. proto.writeResultAsync = cor(function* (endmode) {
  3086. logger.warn("牌局写入-------------- " + this.id );
  3087. // console.warn("ts++---------牌局写入writeResultAsync",this.id);
  3088. let gameCost=0;//游戏消耗
  3089. let giftCost = 0;////道具消耗
  3090. this.etime = Date.now();
  3091. let users = [];
  3092. let localUsers = [];
  3093. var scorers = this.score.getUsers();
  3094. if (scorers.length > 0)
  3095. {
  3096. var scorersSort = _.sortBy(scorers, (i) => i.chairId);
  3097. for (let scorer of scorersSort) {
  3098. gameCost+=this.cost;
  3099. giftCost+=scorer.giftCost;
  3100. let userscore=scorer.score;
  3101. // if(this.gameKindTL == 2) userscore -= 200;
  3102. 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});
  3103. //, gameCost: scorer.gameCost,giftCost: scorer.giftCost,diamond: scorer.diamond
  3104. localUsers.push({_id: scorer.playerId,userId: scorer.userId, name: scorer.name, gameCost: scorer.gameCost,giftCost: scorer.giftCost,});
  3105. }
  3106. }
  3107. // if(this.isGameOk)////以前是解散的不算返利
  3108. if(this.over > 0)////改成只要玩家扣钻了就有返利
  3109. {
  3110. // this.agentRebate=gameCost;//parseInt(gameCost*0.5);
  3111. this.agentRebate=gameCost+giftCost;////礼物也算消耗进行返利
  3112. // console.warn("代理返利+++++",this.agentRebate);
  3113. }
  3114. else
  3115. {
  3116. this.agentRebate=0;
  3117. }
  3118. //console.warn("实时战绩",this.sszjs);//ts++
  3119. this.PJHF.getTSjsonFileName(100,this.recordid,this.ctime);/////TL++,用于记录玩家牌局回放的json文件名
  3120. // console.error("000HHHHHHHHHHHHHHHHHHHHHH",this.pjhffileName.length,this.pjhffileName);
  3121. let datats = {
  3122. _id: this.recordid,//记录
  3123. gameId: this.gameId,
  3124. tableNo: this.id,
  3125. ownerId: this.ownerId,
  3126. agentId: this.agentId,
  3127. type: this.type,
  3128. kind: this.gameKindTL,//游戏类型 = 1代表全名堂 = 2代表大小子 = 3表示土跑胡
  3129. other: this.other,//////TL++2人3人的游戏规则
  3130. playerCount: this.playerAllCount,//游戏人数
  3131. round: this.round,//
  3132. over: this.over,//游戏局数
  3133. ctime: this.ctime,//创建时间
  3134. stime: this.stime,//开始时间
  3135. time: this.etime,//结束时间
  3136. endMode: endmode,//结束类型
  3137. gameCost: gameCost,//游戏消耗
  3138. giftCost: giftCost,//礼物消耗
  3139. agentRebate: parseInt(this.agentRebate),//代理返利
  3140. sszjFile: this.logic.deepCloneTL(this.pjhffileName),
  3141. sszj: this.logic.deepCloneTL(this.sszjs),
  3142. users: users
  3143. }
  3144. this.PJHF.writeTSJson(datats,100,this.id);////在开始第一局的时候将桌子信息写入本地的json文件
  3145. var fhmjtable = new this.app.models.FHMJTables({
  3146. _id: this.recordid,//记录
  3147. gameId: this.gameId,
  3148. tableNo: this.id,
  3149. ownerId: this.ownerId,
  3150. agentId: this.agentId,
  3151. type: this.type,
  3152. kind: this.gameKindTL,//游戏类型 = 1代表全名堂 = 2代表大小子 = 3表示土跑胡
  3153. other: this.other,//////TL++2人3人的游戏规则
  3154. playerCount: this.playerAllCount,//游戏人数
  3155. round: this.round,//
  3156. over: this.over,//游戏局数
  3157. ctime: this.ctime,//创建时间
  3158. stime: this.stime,//开始时间
  3159. time: this.etime,//结束时间
  3160. endMode: endmode,//结束类型
  3161. gameCost: gameCost,//游戏消耗
  3162. giftCost: giftCost,//礼物消耗
  3163. agentRebate: parseInt(this.agentRebate),//代理返利
  3164. sszjFile: this.pjhffileName,
  3165. sszj: this.sszjs,
  3166. users: users
  3167. });
  3168. // console.warn("fhmjtable new",fhmjtable);
  3169. yield fhmjtable.saveAsync();
  3170. //下面是记录返利相关的
  3171. if(this.agentId && this.agentRebate>0){
  3172. yield this.lsetReabte.writeReabteInfo(this.agentId,this.etime,this.agentRebate,gameCost,giftCost,this.recordid,localUsers,this.gameId);
  3173. // yield this.lsetReabte.writePlayerCountInfo(this.agentId,this.etime,users,this.cost,this.isGameOk,this.gameId);
  3174. }
  3175. //下面是记录邀请新人按比例送钻这个活动的数据
  3176. if(!this.lconfigCommon) {
  3177. // console.warn("邀请新人送钻石活动 this.lconfigCommon 不存在 "+this.etime);
  3178. this.lconfigCommon = new configCommon(this.app);
  3179. }
  3180. yield this.lconfigCommon.yxActivityAsync(scorers,this.etime);
  3181. // logger.info("战绩写入fhmjtable.saveAsync()--------------",this.id);
  3182. });
  3183. // 结束信息 var endtype = { 局数完成: 1, 主动解散: 2, 断线解散: 3 ,超时解散: 4 };
  3184. proto.endResultAsync = cor(function* (endmode) {
  3185. // console.warn("ts++---------记录信息",this.id);
  3186. let str6 = "table 结束信息--id: "+this.id +" ,结算模式 "+endmode;
  3187. logger.warn(str6);////cssj
  3188. if(endmode>ENDMODE.PLAYING)//ts++关闭
  3189. {
  3190. let nowTime = Date.now();
  3191. if(this.state<STATE.END)//ts++防止重复写入
  3192. {
  3193. this.state = STATE.END;
  3194. if (this.endTimer) {
  3195. clearTimeout(this.endTimer);
  3196. this.endTimer = null;
  3197. }
  3198. if (this.overTimer) {
  3199. clearTimeout(this.overTimer);
  3200. this.overTimer = null;
  3201. }
  3202. // console.warn("ts++---------局数完成",this.over);
  3203. if(this.over>0)
  3204. {
  3205. var scorers = this.score.getUsers();
  3206. if (scorers.length > 0) {
  3207. let data = {
  3208. _id: this.recordid,
  3209. gameId: this.gameId,
  3210. tableNo: this.id,
  3211. ownerId: this.ownerId,
  3212. type:String(this.type),
  3213. kind: String(this.gameKindTL),
  3214. over: String(this.over),
  3215. round: String(this.round),
  3216. time: String(nowTime),
  3217. ctime: String(this.ctime),
  3218. keep: String(nowTime - this.stime),
  3219. other: this.other,
  3220. playerCount:this.playerAllCount,
  3221. agentId: this.agentId
  3222. };
  3223. let collects = [];
  3224. for (let scorer of scorers) {
  3225. let userscore=scorer.score;
  3226. // if(this.gameKindTL == 2) userscore -= 200;//TL++,因为总的结算界面的每个玩家的分数范围为-200 ~ 600
  3227. collects.push({ chairId:scorer.chairId,name: scorer.name, sex: scorer.sex, headurl: scorer.headurl, score: userscore });
  3228. }
  3229. data.users = _.sortBy(collects, (i) => -i.score);
  3230. //data.sszjFile=this.pjhffileName;
  3231. data.sszj=this.sszjs;
  3232. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.TOTAL_CONCLUDE, data: data });////汇总结算
  3233. }
  3234. //console.warn("ts++---------牌局写入");
  3235. yield this.writeResultAsync(endmode);
  3236. }
  3237. //console.warn("ts---------牌局结束");
  3238. for (let user of this.users) {
  3239. if (user) {
  3240. if (user.isOffline())
  3241. {
  3242. user.state = User.STATE.FREE;
  3243. user.state2 = User.STATE.FREE;
  3244. this.leaveUsers.push(user.id);
  3245. ///yield this.game.leaveTableAsync(user.id);
  3246. }
  3247. else
  3248. {
  3249. user.state = User.STATE.FREE;
  3250. user.state2 = User.STATE.FREE;
  3251. }
  3252. }
  3253. }
  3254. }
  3255. if(endmode==ENDMODE.SYSTEMEND)
  3256. {
  3257. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.TABLE_JIESAN });
  3258. }
  3259. if(this.leaveUsers.length>0)
  3260. {
  3261. this.app.timer.setTimeout(() => this.leaveUserTimeAsync(), 100);
  3262. }
  3263. // var gametable = yield this.app.models.GameTable.findByIdAsync(this.recordid, '_id tableNo agentId endMode');
  3264. // if(gametable){
  3265. // gametable.endMode = 1;
  3266. // yield gametable.saveAsync();
  3267. // }
  3268. this.game.deleteTable(this.id);//ts++删除房间
  3269. // let str5 = "table 结束信息22 关闭-id:"+this.id +"结算模式"+endmode;
  3270. // logger.info(str5);////cssj
  3271. }
  3272. else//普通结束
  3273. {
  3274. // let str5 = "table 结束信息 普通结束---id:"+this.id +"结算模式"+endmode
  3275. // logger.info(str5);////cssj
  3276. this.state = STATE.FREE2;
  3277. for (let user of this.users) {
  3278. if (user) user.state2 = User.STATE.FREE;
  3279. }
  3280. }
  3281. let str7 = "table end 结束信息---id:%s "+this.id +" 结算模式 "+endmode;
  3282. logger.warn(str7);////cssj
  3283. });
  3284. //ts++离开用户退出定时器
  3285. proto.leaveUserTimeAsync = cor(function* () {
  3286. // console.warn("离开用户退出定时器,离开用户数==%d",this.leaveUsers.length);////cssj
  3287. if(this.leaveUsers.length>0)
  3288. {
  3289. let userid = this.leaveUsers[0];
  3290. this.leaveUsers.splice(0, 1);
  3291. let str7 = "table end 离开用户退出定时器---id:%s "+this.id +" userid "+userid;
  3292. logger.warn(str7);////cssj
  3293. yield this.game.leaveTableAsync(userid);
  3294. }
  3295. if(this.leaveUsers.length>0)
  3296. {
  3297. this.app.timer.setTimeout(() => this.leaveUserTimeAsync(), 100);
  3298. }
  3299. });
  3300. // TL++,得到玩家位置
  3301. proto.sendLocationAsync = cor(function* (user,msg) {
  3302. /////设置玩家的经纬度
  3303. user.longitude = msg.longitude; // 经度,浮点数,范围为180 ~ -180。
  3304. user.latitude = msg.latitude; // 纬度,浮点数,范围为90 ~ -90
  3305. let tempData = {
  3306. userId: user.userId,
  3307. account: user.account,
  3308. longitude: msg.longitude,
  3309. latitude: msg.latitude
  3310. }
  3311. //////向其他玩家广播该玩家位置
  3312. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.COAST_PLAYERLOCATION, data: tempData });
  3313. return { code: C.OK, data: tempData };
  3314. });
  3315. // 玩家信息
  3316. proto.roleInfoAsync = cor(function* (chairId) {
  3317. // console.log("玩家信息玩家信息玩家信息");
  3318. var user = this.users[chairId];
  3319. if (!user) {
  3320. return { code: C.FAILD, msg: C.GAME_PARAM_ERROR };
  3321. }
  3322. var data = { userId: '0', ttCount: '0', winCount: '0', noCount: '0', runCount: '0' };
  3323. data.userId =user.userId;
  3324. return { code: C.OK, data: data };
  3325. });
  3326. //ts++请求结束定时器
  3327. proto.overTimeAsync = cor(function* (endmode) {
  3328. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.TABLE_JIESAN });
  3329. let str6 = "table 请求结束定时器---id: "+this.id +" ,endmode: "+endmode
  3330. logger.warn(str6);////cssj
  3331. yield this.endResultAsync(endmode);//ts++ 房主解散 写分
  3332. });
  3333. // 请求结束
  3334. proto.overTableAsync = cor(function* (user) {
  3335. // console.warn("ts+++++请求结束",user.chairId);
  3336. let str3 = "table 请求结束.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  3337. logger.warn(str3);////cssj
  3338. if(this.state == STATE.END)
  3339. {
  3340. this.leaveAsync(user);
  3341. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  3342. }
  3343. if(this.reqJieSan.indexOf(2) != -1) return;/////有发起人的时候
  3344. // console.warn("2222请求结束请求结束请求结束",this.reqJieSan);
  3345. //解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  3346. //jieSanType =1:游戏开始前房主申请解散 =2:游戏开始前非房主玩家退出房间 =3:游戏过程中玩家申请解散 =4游戏过程中是房主但没参与游戏退出房间 =5其他
  3347. if(this.gameNeverStart) {//游戏是否从未开始过,用于解散房间判断
  3348. if(user.userId == this.ownerUid){
  3349. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.TABLE_JIESAN });
  3350. // let str5 = "table 房主解散-id:"+this.id+ ",uid"+user.userId;
  3351. // logger.info(str5);////cssj
  3352. yield this.endResultAsync(ENDMODE.OWNEREND);//ts++ 房主解散 写分
  3353. return { code: C.OK, data:{jieSanType: 1}};
  3354. }
  3355. else{
  3356. this.leaveAsync(user);
  3357. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  3358. }
  3359. }
  3360. else
  3361. {
  3362. let chairId=user.chairId;
  3363. if(chairId >= 0 && chairId < 4 )
  3364. {
  3365. if(this.overFlag==0)//发起
  3366. {
  3367. this.overFlag = 1;
  3368. this.reqJieSan[0]=-1;
  3369. this.reqJieSan[1]=-1;
  3370. this.reqJieSan[2]=-1;
  3371. this.reqJieSan[3]=-1;
  3372. this.reqJieSan[chairId]=2;
  3373. let jsdata = [];//ts++实时本局成绩
  3374. jsdata[0] = this.reqJieSan[0];
  3375. jsdata[1] = this.reqJieSan[1];
  3376. jsdata[2] = this.reqJieSan[2];
  3377. jsdata[3] = this.reqJieSan[3];
  3378. this.JSFJTime = 60;//////解散倒计时60秒
  3379. this.SQJSTime = Date.now() + this.JSFJTime*1000;
  3380. if (!this.overTimer) this.overTimer = this.app.timer.setTimeout(() => this.overTimeAsync(ENDMODE.REGEND),this.JSFJTime*1000);//解散倒计时60秒
  3381. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.REQUEST_END, data: { chairId: String(chairId),time: this.JSFJTime,jsdata:jsdata}});
  3382. return { code: C.OK, data:{jieSanType: 3}};
  3383. }
  3384. else//同意
  3385. {
  3386. return this.agreeOverAsync(chairId);
  3387. }
  3388. }
  3389. else
  3390. {
  3391. return { code: C.FAILD, msg: C.TABLE_ALREADY_SQJS };
  3392. }
  3393. }
  3394. return { code: C.OK, data:{jieSanType: 5}};
  3395. });
  3396. // 拒绝结束
  3397. proto.refuseOverAsync = cor(function* (user) {
  3398. let str3 = "table 拒绝结束.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  3399. logger.warn(str3);////cssj
  3400. if(this.state == STATE.END)
  3401. {
  3402. this.leaveAsync(user);
  3403. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  3404. }
  3405. if(this.overFlag == 0) //ts++已经拒绝了
  3406. {
  3407. return { code: C.OK };
  3408. }
  3409. this.overFlag = 0;
  3410. let chairId=user.chairId;
  3411. // console.error("ts++----------拒绝结束",chairId);
  3412. this.reqJieSan[chairId]=0;//解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  3413. let jsdata = [];//ts++实时本局成绩
  3414. jsdata[0] = this.reqJieSan[0];
  3415. jsdata[1] = this.reqJieSan[1];
  3416. jsdata[2] = this.reqJieSan[2];
  3417. jsdata[3] = this.reqJieSan[3];
  3418. if (this.overTimer) {
  3419. clearTimeout(this.overTimer);
  3420. this.overTimer = null;
  3421. }
  3422. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.REFUSE_END, data: { chairId: String(chairId),time: 0,jsdata:jsdata} });
  3423. //this.reqJieSan = [[-1,-1],[-1,-1],[-1,-1],[-1,-1]];/////解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  3424. this.reqJieSan[0]=-1;
  3425. this.reqJieSan[1]=-1;
  3426. this.reqJieSan[2]=-1;
  3427. this.reqJieSan[3]=-1;
  3428. return { code: C.OK };
  3429. });
  3430. // 同意结束
  3431. proto.agreeOverAsync = cor(function* (user) {
  3432. let str3 = "table 同意结束.......id: "+ this.id + " user.chairId: " + user.chairId + " user.name: " + user.name ;
  3433. logger.warn(str3);////cssj
  3434. if(this.state == STATE.END)
  3435. {
  3436. this.leaveAsync(user);
  3437. return { code: C.OK, data:{jieSanType: 2}};//离开房间
  3438. }
  3439. if(this.overFlag == 0) //ts++已经拒绝了
  3440. {
  3441. return { code: C.OK };
  3442. }
  3443. let chairId=user.chairId;
  3444. // console.error("ts++----------同意结束",chairId);
  3445. this.reqJieSan[chairId] = 1;/////解散桌子数据,前面为chirid后面为情况-1:未操作 0:拒绝 1:同意 2为解散发起
  3446. let jsdata = [];//ts++实时本局成绩
  3447. jsdata[0] = this.reqJieSan[0];
  3448. jsdata[1] = this.reqJieSan[1];
  3449. jsdata[2] = this.reqJieSan[2];
  3450. jsdata[3] = this.reqJieSan[3];
  3451. this.JSFJTime = Math.floor((this.SQJSTime - Date.now())/1000);
  3452. if(this.JSFJTime >= 25)this.JSFJTime -= 20;//////解散房间倒计时60秒
  3453. else this.JSFJTime = 10;
  3454. this.SQJSTime = Date.now() + this.JSFJTime*1000;
  3455. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.AGREE_END, data: { chairId: String(chairId),time: this.JSFJTime,jsdata:jsdata} });
  3456. let jsFlag = 0;
  3457. for (let i = 0; i < 4; ++i)
  3458. {
  3459. if(this.reqJieSan[i] >=1 )
  3460. {
  3461. jsFlag+=1;
  3462. }
  3463. }
  3464. if(jsFlag>=this.ccount || this.JSFJTime<=0)
  3465. {
  3466. if(this.backStartTimer)
  3467. {
  3468. clearTimeout(this.backStartTimer);
  3469. this.backStartTimer = null;
  3470. }
  3471. yield this.pushMsgAsync(-1, 'paohuzi_event', { type: M.TABLE_JIESAN });
  3472. // let str4 = "table 全部同意结束-id:%s"+this.id + ",uid"+user.userId+",state"+ this.state;
  3473. // logger.info(str4);////cssj
  3474. yield this.endResultAsync(ENDMODE.REGEND);//ts++ 结束
  3475. }
  3476. else
  3477. {
  3478. if (this.overTimer) {
  3479. clearTimeout(this.overTimer);
  3480. this.overTimer = null;
  3481. }
  3482. if (!this.overTimer) this.overTimer = this.app.timer.setTimeout(() => this.overTimeAsync(ENDMODE.REGEND),this.JSFJTime*1000);//解散倒计时60秒
  3483. }
  3484. // let str3 = "table end 同意结束-id:"+this.id + ",uid"+user.userId+",state"+ this.state;
  3485. // logger.info(str3);////cssj
  3486. return { code: C.OK, data: { chairId: String(chairId),time: this.JSFJTime, jieSanType: 1 }};
  3487. });
  3488. //////TL++,设置记录游戏过程中的记录数据
  3489. proto.setPaijuHuiFangData = function (_operateKind,_data){
  3490. let data = this.logic.deepCloneTL(_data);
  3491. data.operateKind = _operateKind;
  3492. this.PaijuHuiFang[this.PaijuHuiFang.length] = data;
  3493. };
  3494. // 得到玩家位置
  3495. proto.getLocationAsync = cor(function* () {
  3496. let location = [];
  3497. // 桌上玩家
  3498. for (let i = 0; i < this.users.length; ++i) {
  3499. let user = this.users[i];
  3500. if (user) {
  3501. location.push({
  3502. chairId: user.chairId,
  3503. longitude: user.longitude,
  3504. latitude: user.latitude,
  3505. headurl: user.headurl,
  3506. name: user.name
  3507. });
  3508. }
  3509. }
  3510. // console.warn("ts+++++玩家位置",location);
  3511. return { code: C.OK, data: location };
  3512. });