import { CardRecordTableInfo, CardTableInfo } from '../../../../GameCard/Logic/Table/CardTable'; import { CardTable, CardCreateTableDataModel } from "../../../../GameCard/Logic/Table/CardTable"; import { CardServer } from "../../../../GameCard/Logic/CardServer"; import * as _ from "underscore"; import { ETexasAction, ETexasSeatState, TexasSeat } from "./TexasSeat"; import { PlayerInfo } from "../../../../GameCard/Logic/Table/CardSeat"; import { ns_card } from '../../../../GameCard/Config/_ini_'; import { TexasMatch } from '../Match/TexasMatch'; import { EErrorCode } from '../../Config/_error_'; import { ECardType, GTexasTool } from '../TexasTool'; import { TexasClientWebSocket } from '../../Net/TexasClientWebSocket'; import { ns_texas } from '../../Config/_ini_'; import { EMatchState, MatchPlayer } from '../../../../Common/Service/MatchInstanceService'; import { GLog } from 'cgserver'; import { TexasConfig } from '../../Config/TexasConfig'; class TexasResultPotItem { pot=0 wins:{[user_id:number]:number}={} } class TexasResult { pots:TexasResultPotItem[]=[] } export class TexasCreateTableDataModel extends CardCreateTableDataModel { //盲注表id blind_id=1 } export class TexasRecordTableInfo extends CardRecordTableInfo { match_id=0 blind_id=0 blind_index=0 dealer_index=0 small_blind_index=0 big_blind_index=0 small_blind=0 big_blind=0 cards:number[]=[] tr:TexasResult=null } export class TexasTableInfo extends CardTableInfo { dealer_index = 0 //发牌位 small_blind_index = 0 //小盲位 big_blind_index = 0 //大盲位 small_blind=0 big_blind=0 cards: number[] = []; //公共牌 blind_index: number = 0; //当前盲注等级 pot: number = 0; //底池 //上次的dt值,方便加注使用(加注妖大于等于dtbet) dtbet=0 curmaxbet=0//当前下注的最大量 turn_user_id=-1 match_insid="" //盲注 blind_deadline=-1 } /* 游戏逻辑 */ export class TexasTable extends CardTable { protected _pot = 0 protected _dtbet = 0 protected _curmaxbet = 0 protected _cards:number[] = [] get cards() { return this._cards } protected _turn_user_id = 0 protected _blind_index = 1 protected _big_blind = 0 protected _small_blind = 0 protected _ante = 0 protected _dealer_index = 0 protected _small_blind_index = 0 protected _big_blind_index = 0 get ctdm() { return this._ctdm } protected _match:TexasMatch=null get match() { return this._match } set match(value:TexasMatch) { this._match=value } constructor(table_id:number,game:CardServer) { super(table_id,game) } protected _create_seat(playerinfo:PlayerInfo) { let seat = new TexasSeat(playerinfo,this) return seat } init(ctdm:TexasCreateTableDataModel) { super.init(ctdm) this._is_record_coin_every_battle=false } protected _allcards: number[] = [] protected _first_seat_index=0//开始是大盲,后面为加注的那个 protected _next_blind_index=1 protected _clear() { super._clear() this._pot = 0 this._dtbet = 0 this._curmaxbet = 0 this._cards = [] this._turn_user_id = 0 } //比赛通知开始 onMatchBegin() { GLog.info(`table(${this._id}) match begin...player:${this.user_num}...audience:${this.audience_id_list.length}`,true) //之后就自动开了 this._ctdm.auto_start=true this.onStart() } //暂停游戏,休息几分钟 onPause() { this._timer.pause() } //游戏结束,接着玩 onResume() { this._timer.resume() } //升级盲注 onUpgrateBlind(blindindex:number) { this._next_blind_index = blindindex this.broadcast("upgradeblind_bc",this._id,blindindex,this._match.getBlindItem(this._next_blind_index)) if(this._state==ns_card.ETableState.Waiting) { this._blind_index=blindindex this._tryIdle() return } if(this._state==ns_texas.ETexasTableState.Idle) { this._state=ns_texas.ETexasTableState.Waiting //之前的prepare还在 this.onResume() this._tryTriggerPrepare() return } return } onEnter(playerinfo:MatchPlayer) { let ret = super.onEnter(playerinfo) if(!ret) { playerinfo.table_id=this._id } return ret } async onStart() { this._timer.clear() this._state=ns_texas.ETexasTableState.Waiting let ret = await super.onStart() if(ret) { return ret } this._first_seat_index=-1 this._turn_user_id=-1 this._match.onTableOneStart(this) this._timer.setTimeout(this._beginBet.bind(this),1000) } protected _tryIdle() { if(this._state==ns_texas.ETexasTableState.Playing ||this._state==ns_texas.ETexasTableState.WaintingCombine) { return } let bi = this._match.getBlindItem(this._blind_index) if(bi.ante+bi.small_blind+bi.big_blind>0) { return } this._state = ns_texas.ETexasTableState.Idle this.onPause() this.broadcast("idle_bc",this._id,this._match.deadline) } protected _onStartProcess() { super._onStartProcess() this._cards=[] this._begin_time=Date.now() this._blind_index=this._next_blind_index let bcfg = this._match.getBlindItem(this._blind_index) this._big_blind=bcfg.big_blind this._small_blind=bcfg.small_blind this._ante=bcfg.ante let dealer_index = 0 //计算下一个dealer位 for (let i = 1; i < this._seats.length; i++) { let di = (this._dealer_index + i) % this._seats.length let seat = this._seats[di] if(!seat) { continue } dealer_index = di break } this._dealer_index=dealer_index //计算小盲位 let small_blind_index = 0 for (let i = 1; i < this._seats.length; i++) { let sbi = (this._dealer_index + i) % this._seats.length let seat = this._seats[sbi] if(!seat) { continue } small_blind_index = sbi break } //计算大盲位 let big_blind_index = 0 for (let i = 1; i < this._seats.length; i++) { let sbi = (small_blind_index + i) % this._seats.length let seat = this._seats[sbi] if(!seat) { continue } big_blind_index = sbi break } this._dealer_index = dealer_index this._small_blind_index = small_blind_index this._big_blind_index = big_blind_index this._state=ns_card.ETableState.Playing for (let index in this._seats) { let seat = this._seats[index] as TexasSeat if(!seat) { continue } let ante = seat.onBet(bcfg.ante,ETexasAction.None,true) this._pot += ante } let small_seat = this._seats[this._small_blind_index] as TexasSeat let bet = small_seat.onBet(bcfg.small_blind,ETexasAction.None) this._pot += bet let big_seat = this._seats[this._big_blind_index] as TexasSeat bet = big_seat.onBet(bcfg.big_blind,ETexasAction.None); this._pot += bet //初始化 //和4取余分别为黑桃,方块,梅花,红桃 // let cards = []; for (let i = 0; i < 52; i++) { cards.push(i + 1); } this._curmaxbet=bcfg.big_blind this._dtbet=bcfg.big_blind this._first_seat_index=-1 this._turn_user_id=-1 //洗牌 cards=_.shuffle(cards) //发牌 for (let index in this._seats) { let seat = this._seats[index] as TexasSeat if(!seat) { continue } seat.cards = cards.splice(0, 2) seat.cards.sort((a, b) => b - a) let cd0 = GTexasTool.getCardDetail(seat.cards[0]) let cd1 = GTexasTool.getCardDetail(seat.cards[1]) if(cd0.cd==cd1.cd) { seat.cardtype=ECardType.OnePair } else { seat.cardtype=ECardType.High } } this._allcards = cards } protected _beginBet() { //玩的人,包括allin的人数 let leftnum = 0 //playing let playing_num=0 for (let i = 0; i < this._seats.length; i++) { let seat = this._seats[i] if(!seat) { continue } if(seat.state!=ETexasSeatState.Playing&&seat.state!=ETexasSeatState.AllIn) { continue } if(seat.state==ETexasSeatState.Playing) { playing_num++ } ++leftnum } if(leftnum<=1) { //直接结束 this._timer.setTimeout(this._onEnd.bind(this),1000) return } //如果全allin了,_turn_user_id和first_seat_index是-1,照完了也找不到一个该出牌的人 if(playing_num==0) { this._onBetEnd() return } //如果新的一轮了,但是只剩一个了, if(this._turn_user_id<0&&playing_num==1) { this._onBetEnd() return } let turn_seat = this._getSeatByUserId(this._turn_user_id) as TexasSeat let cur_index=-1 if(turn_seat) { //查找当前下一个 cur_index=turn_seat.index } else if(this._cards.length<=0) { //从大盲下一个开始 cur_index=this._big_blind_index this._first_seat_index=this._big_blind_index } else { //从小盲开始 cur_index=this._small_blind_index-1 } for (let i = 1; i <= this._seats.length; i++) { let index = (cur_index + i) % this._seats.length let seat = this._seats[index] if(!seat) { continue } if(seat.index==this._first_seat_index) { this._onBetEnd() return } if(seat.state!=ETexasSeatState.Playing) { continue } this._turn_user_id=seat.id break } turn_seat = this._getSeatByUserId(this._turn_user_id) as TexasSeat if(this._first_seat_index<0) { this._first_seat_index=turn_seat.index } let cfg = this._server.cfg as TexasConfig this._timer.setTimeout(this._onBetTimeout.bind(this),cfg.wait_bet_timeout) this.broadcast("beginbet_bc", { table_id:this._id, first_seat:this._first_seat_index, turn_user_id:this._turn_user_id, curmaxbet:this._curmaxbet, dtbet:this._dtbet, curbet:turn_seat.bet, curpoint:turn_seat.playerInfo.point, timeout:this._timer.deadline }) if(turn_seat.auto) { setTimeout(()=> { let errcode = this.onBet(turn_seat.id,-1) if(!errcode) { turn_seat.auto=true } },1000) } } protected _onBetTimeout() { //让他弃牌 let seat = this._getSeatByUserId(this._turn_user_id) this.onBet(seat.id,-1) seat.auto=true } onBet(user_id:number,bet:number) { if(this._state!=ns_texas.ETexasTableState.Playing) { return EErrorCode.Action_Failed } //没有轮到你 if(user_id!=this._turn_user_id) { return EErrorCode.Not_Your_Turn } let seat = this._getSeatByUserId(user_id) as TexasSeat if(!seat) { return EErrorCode.No_Seat_By_User_Id } //金币异常不能下注 if(seat.point=this._curmaxbet) { return EErrorCode.Wrong_ActionType } } seat.auto=false let action = ETexasAction.None if(bet<0) { seat.state=ETexasSeatState.Fold action=ETexasAction.Fold seat.onBet(0,action) } else { let pretotalbet = bet+seat.bet //allin了,无论如何都是合法的 if(bet==seat.point) { action=ETexasAction.Allin } else if(pretotalbet==this._curmaxbet) { if(this._curmaxbet==0) { action=ETexasAction.Check } else { action=ETexasAction.Call } } else if(pretotalbet>=this._curmaxbet+this._dtbet) { action=ETexasAction.Raise } if(action!=ETexasAction.None)//加注 { bet = seat.onBet(bet,action) } else { return EErrorCode.Wrong_Bet_Value } let totalbet = seat.bet if(totalbet>this._curmaxbet) { this._dtbet=totalbet-this._curmaxbet this._curmaxbet=totalbet this._first_seat_index=seat.index } this._pot+=bet } this.broadcast("bet_bc", { table_id:this._id, user_id:user_id, bet:bet, action:action, curmaxbet:this._curmaxbet, dtbet:this._dtbet }) this._timer.clear() this._beginBet() return null } //一圈下注结束 protected _onBetEnd() { for (let index in this._seats) { let seat = this._seats[index] as TexasSeat if(!seat) { continue } if(seat.state==ETexasSeatState.Waiting ||seat.state==ETexasSeatState.Fold ||seat.state==ETexasSeatState.AllIn) { continue } seat.action = ETexasAction.None } this._curmaxbet=0 let bcfg = this._match.getBlindItem(this._blind_index) this._dtbet=bcfg.big_blind this._first_seat_index=-1 this._turn_user_id=-1 //检查是否需要发牌 if(this._cards.length<5) { let cards = null if(this._cards.length==0) { cards = this._allcards.splice(0,3) this._cards=cards } else { cards = this._allcards.splice(0,1) this._cards.push(cards[0]) } let user_id_list = this.bc_user_id_list for(let i=0;isuper._onBattleRecord() brd.match_id=this._match?.matchId||0 brd.blind_id=(this._ctdm as TexasCreateTableDataModel).blind_id brd.blind_index=this._blind_index brd.dealer_index=this._dealer_index brd.small_blind_index=this._small_blind_index brd.big_blind_index=this._big_blind_index brd.small_blind=this._small_blind brd.big_blind=this._big_blind brd.cards=this._cards.concat() brd.tr=tr return brd } /** * 处理结果 */ protected _processResult() { this._state = ns_card.ETableState.Waiting //先计算没有fold的玩家 let playing_seats=new Array() for(let i=0;i}>() //从小到大 playing_seats.sort((a,b)=> { return a.totalBet-b.totalBet }) //最多只有n-1个池子,随便把各自的牌型算了 let allleft:{[user_id:number]:number}={} let allinbets:number[]=[] let cardresults:{[seat_index:number]:any}={} for(let i=0;i0&&seat.state==ETexasSeatState.AllIn) { allinbets.push(seat.totalBet) } } allinbets.sort((a,b)=> { return a-b }) let pre=0 for(let i=0;i=bet) { allleft[key]-=bet pot.bet+=bet let user_id = parseInt(key) pot.indexes.push({user_id:user_id,rs:cardresults[user_id]}) } else if(allleft[key]>0) { pot.bet+=allleft[key] allleft[key]=0 } } if(pot.bet>0) { pots.push(pot) } } //allin之外的池子 let leftchip =0 for(let key in allleft) { leftchip+=allleft[key] } if(leftchip>0) { let pot= { bet:leftchip, indexes:[] } for(let key in allleft) { if(allleft[key]<=0) { continue } let user_id = parseInt(key) let seat = this._getSeatByUserId(user_id) if(seat.state!=ETexasSeatState.Fold) { pot.indexes.push({user_id:user_id,rs:cardresults[user_id]}) } } //最后一个池子理论上必须有一个没有弃牌的玩家,但是可能意外导致那么就取钱最多的几个人 //容错处理,理论上不应该到这里 if(pot.indexes.length<=0) { GLog.error({special:this.getInfo()}) for(let key in allleft) { if(allleft[key]<=0) { continue } let user_id = parseInt(key) pot.indexes.push({user_id:user_id,rs:cardresults[user_id],bet:allleft[key]}) } pot.indexes.sort((a,b)=> { return b.bet-a.bet }) let i=1 for(;i=2) { for(let i=0;i { let ret = GTexasTool.compare(i0.rs,i1.rs) let pre = this._getSeatByUserId(i0.user_id) as TexasSeat pre.showcards=true pre.cardtype=i0.rs.type let seat = this._getSeatByUserId(i1.user_id) as TexasSeat seat.showcards=true seat.cardtype=i1.rs.type return -ret }) let seat = this._getSeatByUserId(pot.indexes[0].user_id) as TexasSeat let maxseats = [seat] for(let j=1;j