import React, { Component } from 'react'
import { View, Text, Image, Input, Button } from '@tarojs/components'
import { connect } from 'react-redux'
import cnames from 'classnames'
import { setBalance } from '@/store/user';
import {
reqGameFullStatus, reqKickOutTable, reqLeaveTable,
reqReadyStart, reqDismissGameTable, reqGameStart,
reqCancelReady, reqBetting, reqAccountBalance
} from '@/api/wsapi'
import { addMsgListen, removeMsgListener } from '@/api/websocket'
import { isEmpty } from '@/utils/validator'
import './table.scss'
import Title from '@/components/title'
import Card from '@/components/card'
import coinIcon from '@/assets/icon/coin-1.svg'
import coin2Icon from '@/assets/icon/coin-2.svg'
import plus1Icon from '@/assets/icon/plus-1.svg'
import sub1Icon from '@/assets/icon/sub-1.svg'
import closeIcon from '@/assets/icon/close-1.svg'
import timeIcon from '@/assets/icon/time-fill.svg'
import clockIcon from '@/assets/icon/clock.svg'
import clockWarnIcon from '@/assets/icon/clock_warn.svg'
import crownIcon from '@/assets/icon/crown.svg'
import crownDarkIcon from '@/assets/icon/crown_dark.svg'
import bigBlindIcon from '@/assets/icon/big_blind.svg'
import smallBlindIcon from '@/assets/icon/small_blind.svg'
import Taro from '@tarojs/taro'
import { showToast, redirectTo } from '@/utils/application'
import { isIn } from '@/utils/collect'
function PlayerStatus(props) {
const { text, color } = props;
return (
{text}
)
}
function cardDot(card, cardBackCode) {
if (!card || !card.suit) {
return cardBackCode;
}
return card['dot'];
}
function cardSuit(card) {
return (card && card.suit) || 'D';
}
// 是否空白牌
function existsCard(card) {
return !!card && !!card.suit;
}
class Table extends Component {
constructor(props) {
super(props)
this.state = {
tableNo: 0,
stage: 0, // 游戏阶段: 1等待玩家准备;2下大盲注;3下小盲注;4发公共牌;5发第四张公共牌,轮流下注;6发第五张公共牌,轮流下注,7比牌结算
chip: 0,
playerId: 0,
masterId: 0,
bigBlindPos: -1,
smallBlindPos: -1,
players: [],
publicCard: [],
otherPlayers: [],
selfIndex: 0,
selfPlayer: {handCard: [], betRole: {}},
betType: 0,
bettingChip: 0,
betConfirmText: '下注',
betSubmitLoading: false,
// winsChip: {}, // {1:14, 2:-14}
playerNoticeLines: [], // {line1: "+6",line2: "跟注",playerId: 1}
playerNotice: null, //{line1: "+108",line2: "加注:12221126",line3: '跟注:6', playerId: 3},
winsChip: {}, //{7: -20, 8: 40, 3: -20},
betSecondLimit: -1,
betSecondInterval: -1,
}
}
componentWillUnmount() {
// 取消监听消息
removeMsgListener('api.ResGameFullStatus');
removeMsgListener('api.ResKickOutTable');
removeMsgListener('api.ResDismissGameTable');
removeMsgListener('api.ResNoticePlayerLine');
removeMsgListener('api.ResCalcWinnerChip');
}
showPlayerNotice() {
if (this.state.playerNotice) {
return;
}
const playerNotice = this.state.playerNoticeLines.shift();
if (!playerNotice) {
return;
}
this.setState({playerNotice}, () => {
// 隔1秒展示下一条
setTimeout(() => {
this.setState({
playerNotice: null
}, this.showPlayerNotice.bind(this));
}, 1500);
});
}
componentDidMount() {
// setTimeout(() => {
// 监听状态变化消息
addMsgListen('api.ResGameFullStatus', this.handleResGameFullStatus); // 牌桌状态变化
// 被房主踢出
addMsgListen('api.ResKickOutTable', res => {
showToast({title: '您被请出牌桌'});
setTimeout(() => redirectTo({url: '/pages/lobby/lobby'}), 800);
});
// 牌桌解散
addMsgListen('api.ResDismissGameTable', res => {
showToast({title: '牌桌已解散'});
setTimeout(() => redirectTo({url: '/pages/lobby/lobby'}), 800);
});
// 操作通知消息 {line1: "+6",line2: "跟注",playerId: 1}
addMsgListen('api.ResNoticePlayerLine', res => {
// 放置消息到通知队列
this.state.playerNoticeLines.push(res);
this.showPlayerNotice.call(this);
});
// 输赢筹码信息
addMsgListen('api.ResCalcWinnerChip', res => {
console.log('winsChip...:', res);
window.winsChip = res;
this.setState({winsChip: res.winsChip});
setTimeout(() => { // 输赢筹码展示一会后消失
if (this.state.winsChip === res.winsChip) {
this.setState({winsChip: {}});
}
}, 10000);
});
// // 扣除大盲注(显示3秒)
// addMsgListen('api.ResBigBlindChip', res => {
// showToast({title: '大盲注:' + res.chip});
// });
// // 扣除小盲注(显示3秒)
// addMsgListen('api.ResSmallBlindChip', res => {
// showToast({title: '小盲注:' + res.chip});
// });
// 查询当前牌桌状态
reqGameFullStatus()
.then(res => {
this.handleResGameFullStatus(res);
})
.catch(err => {
showToast({title: err});
if (err.code === 402) {
setTimeout(() => redirectTo({url: '/pages/lobby/lobby'}), 800);
}
})
// 查询账户余额
reqAccountBalance()
.then(res => {
this.props.setBalance(res.balance)
})
.catch(err => {
console.error('账户余额查询失败:', err)
showToast({title: err})
})
// }, 2000)
}
handleResGameFullStatus = res => {
const players = res.players.map((player, index) => ({player, index}));
const otherPlayers = players.filter(({player}) => player.id !== res.playerId);
const self = players.find(({player}) => player.id === res.playerId);
const {player : bettingPlayer} = players.find(({player}) => isIn(player.status, 4, 6)) || {player: null};
const {index: selfIndex, player: selfPlayer} = self || {player: {handCard: [], betRole: {}}};
// 出牌倒计时处理
let betSecondLimit = -1;
let betSecondInterval = -1;
// console.log('bettingPlayer', bettingPlayer)
if (bettingPlayer && bettingPlayer.betRole) {
const {betTimeLimit: timeLimit, betSecondLimit: secondLimit} = bettingPlayer.betRole;
if (timeLimit) {
const timeSecondLimit = parseInt((timeLimit - Date.now()) / 1000);
betSecondLimit = timeSecondLimit - secondLimit <= 5 ? timeSecondLimit : secondLimit;
clearInterval(this.state.betSecondInterval);
betSecondInterval = setInterval(() => {
if (this.state.betSecondLimit <= 0) {
clearInterval(this.state.betSecondInterval);
return;
}
this.setState({betSecondLimit: this.state.betSecondLimit - 1})
}, 1000);
}
}
this.setState({
playerId: res.playerId,
tableNo: res.tableNo,
stage: res.gameStage,
chip: res.chip || 0,
masterId: res.masterId,
bigBlindPos: res.bigBlindPos,
smallBlindPos: res.smallBlindPos,
players: res.players,
publicCard: res.publicCard,
otherPlayers,
selfIndex,
selfPlayer,
bettingChip: this.state.bettingChip !== 0 ? this.state.bettingChip : selfPlayer.betMin,
betSecondLimit: betSecondLimit !== -1 ? betSecondLimit : this.state.betSecondLimit,
betSecondInterval: betSecondInterval !== -1 ? betSecondInterval : this.state.betSecondInterval,
})
// console.log('res game', res, res.publicCard[0].dot, ifEmpty(res.publicCard[0].dot, -3))
window.publicCard = res.publicCard
}
// 踢人
handleKickoutPlayer(player) {
console.log('kickout', player)
Taro.showModal({
title: '提示',
content: `将玩家[${player.username}]移出牌桌?`,
success: res => {
if (!res.confirm) {
return;
}
reqKickOutTable(player.id)
.then(_ => {
showToast({title: `[${player.username}]已离开牌桌`})
})
.catch(err => {
showToast({title: err})
})
}
});
}
// 退出
handleLeaveTable() {
Taro.showModal({
title: '提示',
content: "是否离开牌桌?",
success: res => {
if (!res.confirm) {
return;
}
reqLeaveTable()
.then(_ => {
redirectTo({url: '/pages/lobby/lobby'})
})
.catch(err => showToast({title: err}))
}
})
}
// 准备开始
handleReadyStart(playerStatus) {
(playerStatus === 2 ? reqCancelReady() : reqReadyStart())
.then(res => {
console.log('ready res:', res);
})
.catch(err => showToast({title: err}));
}
// 解散牌桌
handleResDismissGameTable() {
Taro.showModal({
title: '提示',
content: "是否解散牌桌?",
success: res => {
if (!res.confirm) {
return;
}
reqDismissGameTable()
.then(_ => {
redirectTo({url: '/pages/lobby/lobby'})
})
.catch(err => showToast({title: err}));
}
})
}
// 开始游戏
handleGameStart() {
reqGameStart()
.then(res => {
console.log('game start...', res)
})
.catch(err => showToast({title: err}));
}
// 加注
handleSubPlusBetting(symbol, once) {
const c = this.state.bettingChip || 0;
const {betRole: {betMax}} = this.state.selfPlayer;
if (symbol < 0 && c <= 0) { // 减
return;
} else if (symbol > 0 && betMax >= 0 && c >= betMax) { // 加
return;
}
const chip = c + symbol * once;
this.setState({bettingChip: chip, betType: 2});
}
// 跟注,弃牌...操作按钮
handleBetting(betType) {
// console.log('betType', betType) betOpts
const {betRole: {betMin}} = this.state.selfPlayer;
switch(betType) {
case 1: // 1跟注,2加注(-[0]+),3All-In,4弃牌,5过牌
this.setState({betType: 1, bettingChip: betMin, betConfirmText: '跟注'});
break;
case 4: // 弃牌
this.setState({betType: 4}, this.handleBetConfirm.bind(this));
break;
case 5: // 过牌
this.setState({betType: 5}, this.handleBetConfirm.bind(this));
}
}
handleBetConfirm() {
const {betType, bettingChip} = this.state;
if (betType === 0) {
return showToast({title: '请增加下注筹码或其他操作'});
}
console.log('confirm', betType, bettingChip)
this.setState({bettingChip: 0, betSubmitLoading: true}, () => {
reqBetting(betType, bettingChip || 0)
.then(res => {
console.log('betRes', res);
})
.catch(err => {
showToast({title: err})
})
.finally(() => {
this.setState({betSubmitLoading: false, betConfirmText: '下注'})
})
})
}
handleBettingInput(e) {
// const value = parseInt(e.target.value);
// console.log('input', typeof(value), value, this.state.bettingChip);
// if (typeof(value) !== 'number') {
// this.setState({bettingChip: this.state.bettingChip})
// return;
// }
// if (value < this.state.betMin) {
// this.setState({bettingChip: this.state.betRole.bettingChip})
// return showToast({title: `当前最小下注额${this.state.betRole.betMin}`})
// }
// if (value > this.state.betMax) {
// this.setState({bettingChip: this.state.betRole.bettingChip})
// return showToast({title: `当前最大下注额${this.state.betMax}`})
// }
// console.log('input', value, this.state.betMin, this.state.betRole.betMax);
this.setState({bettingChip: value})
}
render() {
const { username, nickname, avatar, defaultAvatar } = this.props.user; // useSelector(state => state.user);
// const players = [1, 2, 3, 4, 5, 6];
const players = this.state.players.map((player, index) => ({player, index}));
const {
playerId, tableNo,
stage, bigBlindPos, smallBlindPos,
chip, otherPlayers,
selfIndex, selfPlayer,
bettingChip, betConfirmText, betSubmitLoading,
playerNotice: pn, winsChip,
betSecondLimit,
} = this.state;
const {betMin, betMax, betOpts} = selfPlayer.betRole || {};
// console.log('props', this.props);
const playerRows = otherPlayers.reduce((arr, player, idx) => {
const row = parseInt(idx / 2);
let rowArr = arr[row] || [];
rowArr[idx % 2] = player;
arr[row] = rowArr;
return arr;
}, []);
return (
#{tableNo}
)} />
{
playerRows.map((row, i) => (
{
row.map(({index, player}, j) => (
{console.log(p)}).bind(this, player)}>
{
player.status === 2 && Ready
}
{
// 座位编号
!player.id ? null :
player.master
?
#{index+1}
: #{index+1}
}
{
// 大小盲注图标
!player.id ? null : !(isIn(stage, 2,3,4,5) && isIn(index, bigBlindPos, smallBlindPos)) ? null
:
}
{
// 等待读秒,下注金额
!isIn(stage, 2,3,4,5) || !isIn(player.status, 6) ? null :
30 ? clockIcon : clockWarnIcon} />
{betSecondLimit}
{/* {
isIn(player.status, 4, 6)
?
: 99})}>+{player.chip}
} */}
}
{
!pn || pn.playerId !== player.id ? null :
{pn.line1 && {pn.line1}}
{pn.line2 && {pn.line2}}
{pn.line3 && {pn.line3}}
}
{
stage === 7 && typeof(winsChip[player.id]) !== 'number' ? null
:
= 0})}>{winsChip[player.id] >= 0 ? '+' : ''}{winsChip[player.id]}
}
{
// 踢出牌桌close图标
stage === 1 && selfPlayer.master && player.id
?
: null
}
{/* 玩家手牌 */}
{player.id && existsCard(selfPlayer.handCard[0]) ? : null}
{player.id && existsCard(selfPlayer.handCard[1]) ? : null}
{/* 手牌牌型 */}
{
!(player.handType && player.handType.handZh) ? null :
{player.handType.handZh}
}
{/* 头像名称 */}
{!player.id ? null : }
{player.username}
{
// 玩家筹码
!player.id ? null :
{player.chip}
{player.roundBetTotal}
}
))
}
))
}
{
!isIn(stage, 2,3,4,5,7) ? null : this.state.publicCard.map((card, i) => (
))
}
POT
{chip}
{/*
Kelly(#1)进入了游戏
Apollo(#2)进入了游戏
*/}
{
//
selfPlayer.master
?
#{selfIndex+1}
: #{selfIndex+1}
}
{
// 大小盲注图标
!(isIn(stage, 2,3,4,5) && isIn(selfIndex, bigBlindPos, smallBlindPos)) ? null
:
}
{
// 等待读秒,下注金额
{
// TODO All In ...
!isIn(selfPlayer.status, 4, 6)
? null
:
30 ? clockIcon : clockWarnIcon} />
{betSecondLimit}
// : +{selfPlayer.chip}
// , {'filling-chip-l': selfPlayer.chip > 99}
}
}
{existsCard(selfPlayer.handCard[0]) && }
{existsCard(selfPlayer.handCard[1]) && }
{/* 手牌牌型 */}
{
!(selfPlayer.handType && selfPlayer.handType.handZh) ? null :
{selfPlayer.handType.handZh}
}
{
!pn || pn.playerId !== selfPlayer.id ? null :
{pn.line1 && {pn.line1}}
{pn.line2 && {pn.line2}}
{pn.line3 && {pn.line3}}
}
{
stage === 7 && typeof(winsChip[selfPlayer.id]) !== 'number' ? null
:
= 0})}>
{winsChip[selfPlayer.id] >= 0 ? '+' : ''}{winsChip[selfPlayer.id]}
}
{
existsCard(selfPlayer.handCard[0]) && [1, 2, 3, 4, 5].map((_, i) => (
))
}
{selfPlayer.username}
{selfPlayer.chip}
{selfPlayer.roundBetTotal}
{isEmpty(betOpts) ? null :
}
{!isIn(2, betOpts) ? null : }
{!isIn(2, betOpts) ? null : }
{
isIn(stage, 1, 7) ? (
// 是房主: 关闭牌桌, 开始游戏
selfPlayer.master ?
// 是玩家:退出, 准备
:
)
:
{
!isIn(4, betOpts) ?
:
}
{
!isIn(5, betOpts) ?
:
}
{
!isIn(1, betOpts)?
:
}
{
!isIn(3, betOpts)?
:
}
{isEmpty(betOpts) ? null : }
}
)
}
}
const mapStateToProps = state => ({
user: state.user
});
const mapDispatchToProps = dispatch => ({
setBalance: b => dispatch(setBalance(b))
});
export default connect(mapStateToProps, mapDispatchToProps)(Table)