Files
WPSBot/games/casino.py

1474 lines
61 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""赌场游戏模块"""
import logging
import random
from typing import List
from games.base import BaseGame
from utils.parser import CommandParser
from core.database import get_db
logger = logging.getLogger(__name__)
class CasinoGame(BaseGame):
"""赌场游戏"""
def __init__(self):
"""初始化游戏"""
super().__init__()
self.db = get_db()
async def handle(self, command: str, chat_id: int, user_id: int) -> str:
"""处理赌场指令
Args:
command: 完整指令
chat_id: 会话ID
user_id: 用户ID
Returns:
回复消息
"""
try:
# 提取参数
_, args = CommandParser.extract_command_args(command)
args = args.strip().lower()
# 没有参数,显示帮助
if not args:
return self.get_help()
# 解析第一个参数为游戏类型
parts = args.split(maxsplit=1)
game_type = parts[0]
sub_args = parts[1] if len(parts) > 1 else ""
# 根据游戏类型分发
if game_type == '大小':
return await self._handle_bigsmall(sub_args, chat_id, user_id)
elif game_type == '轮盘':
return await self._handle_roulette(sub_args, chat_id, user_id)
elif game_type in ['21点', 'blackjack', '21']:
return await self._handle_blackjack(sub_args, chat_id, user_id)
elif game_type in ['help', '帮助']:
return self.get_help()
else:
return f"❌ 暂不支持的游戏类型: {game_type}\n\n支持的类型大小、轮盘、21点"
except Exception as e:
logger.error(f"处理赌场指令错误: {e}", exc_info=True)
return f"❌ 处理指令出错: {str(e)}"
async def _handle_bigsmall(self, args: str, chat_id: int, user_id: int) -> str:
"""处理大小游戏
Args:
args: 子命令和参数
chat_id: 会话ID
user_id: 用户ID
Returns:
回复消息
"""
if not args:
return self._get_bigsmall_help()
# 解析子命令
parts = args.split(maxsplit=1)
action = parts[0].lower()
sub_args = parts[1] if len(parts) > 1 else ""
if action in ['open', '开启', '开始']:
return await self._open_bigsmall(sub_args, chat_id, user_id)
elif action in ['bet', '下注', '']:
return await self._bet_bigsmall(sub_args, chat_id, user_id)
elif action in ['status', '状态', '查看']:
return await self._status_bigsmall(chat_id)
elif action in ['settle', '结算', '开奖']:
return await self._settle_bigsmall(sub_args, chat_id, user_id)
elif action in ['cancel', '放弃', '关闭']:
return await self._cancel_bigsmall(chat_id, user_id)
elif action in ['help', '帮助']:
return self._get_bigsmall_help()
else:
return f"❌ 未知命令: {action}\n\n{self._get_bigsmall_help()}"
async def _open_bigsmall(self, args: str, chat_id: int, user_id: int) -> str:
"""庄家开启大小游戏
Args:
args: 参数字符串 "<最小下注> <最大下注> <赔率>"
chat_id: 会话ID
user_id: 用户ID
Returns:
回复消息
"""
try:
# 解析参数
parts = args.split()
if len(parts) != 3:
return "❌ 参数格式错误!\n\n正确格式:`.赌场 大小 open <最小下注> <最大下注> <赔率>`\n\n示例:`.赌场 大小 open 10 100 2.0`"
try:
min_bet = int(parts[0])
max_bet = int(parts[1])
multiplier = float(parts[2])
except ValueError:
return "❌ 参数必须是数字!"
# 参数验证
if min_bet <= 0 or max_bet <= 0:
return "❌ 下注金额必须大于0"
if min_bet > max_bet:
return "❌ 最小下注不能大于最大下注!"
if multiplier <= 0:
return "❌ 赔率必须大于0"
if max_bet > 10000:
return "❌ 最大下注不能超过10000分"
# 检查是否已有活跃游戏(单场限制)
existing = self.db.get_any_active_casino_session(chat_id)
if existing:
return f"⚠️ 当前已有进行中的游戏({existing['game_type']}),请先结算后再开启新游戏。"
# 创建游戏会话
session_id = self.db.create_casino_session(
chat_id=chat_id,
game_type='大小',
banker_id=user_id,
min_bet=min_bet,
max_bet=max_bet,
multiplier=multiplier,
house_fee=0.05 # 固定5%抽水
)
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 大小游戏已开启\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**最小下注**{min_bet}\n\n"
text += f"**最大下注**{max_bet}\n\n"
text += f"**赔率**{multiplier}\n\n"
text += f"**抽水率**5%\n\n"
text += "---\n\n"
text += "💡 提示:玩家可以使用 `.赌场 大小 bet <大/小> <金额>` 进行下注"
return text
except Exception as e:
logger.error(f"开启游戏失败: {e}", exc_info=True)
return f"❌ 开启游戏失败: {str(e)}"
async def _bet_bigsmall(self, args: str, chat_id: int, user_id: int) -> str:
"""玩家下注
Args:
args: 参数字符串 "<大/小> <下注金额>"
chat_id: 会话ID
user_id: 用户ID
Returns:
回复消息
"""
try:
# 解析参数
parts = args.split()
if len(parts) != 2:
return "❌ 参数格式错误!\n\n正确格式:`.赌场 大小 bet <大/小> <下注金额>`\n\n示例:`.赌场 大小 bet 大 50`"
bet_type = parts[0]
try:
amount = int(parts[1])
except ValueError:
return "❌ 下注金额必须是数字!"
# 验证下注类型
if bet_type not in ['', '']:
return f"❌ 下注类型错误!只支持'''',您输入的是:{bet_type}"
# 检查是否有活跃的会话
session = self.db.get_active_casino_session(chat_id, '大小')
if not session:
return "❌ 当前没有进行中的游戏,请等待庄家开启游戏。"
# 验证下注金额
if amount < session['min_bet']:
return f"❌ 下注金额太小!最小下注:{session['min_bet']}"
if amount > session['max_bet']:
return f"❌ 下注金额太大!最大下注:{session['max_bet']}"
# 检查用户积分
user_points = self.db.get_user_points(user_id)
if user_points['points'] < amount:
return f"❌ 积分不足!需要 {amount} 分,当前可用 {user_points['points']}"
# 扣除积分
if not self.db.consume_points(user_id, amount, 'casino_bet', f"大小游戏下注{bet_type}"):
return "❌ 扣除积分失败!"
# 记录下注
bet_id = self.db.create_casino_bet(
chat_id=chat_id,
game_type='大小',
user_id=user_id,
bet_type=bet_type,
amount=amount,
multiplier=session['multiplier']
)
# 获取更新后的积分
updated_points = self.db.get_user_points(user_id)
text = f"## 🎲 下注成功\n\n"
text += f"**下注类型**{bet_type}\n\n"
text += f"**下注金额**{amount}\n\n"
text += f"**赔率**{session['multiplier']}\n\n"
text += f"**剩余积分**{updated_points['points']}\n\n"
text += "---\n\n"
text += "💡 等待庄家结算结果..."
return text
except Exception as e:
logger.error(f"下注失败: {e}", exc_info=True)
return f"❌ 下注失败: {str(e)}"
async def _status_bigsmall(self, chat_id: int) -> str:
"""查看当前游戏状态
Args:
chat_id: 会话ID
Returns:
状态消息
"""
session = self.db.get_active_casino_session(chat_id, '大小')
if not session:
return "❌ 当前没有进行中的大小游戏"
# 获取所有待结算下注
bets = self.db.get_pending_bets(chat_id, '大小')
# 统计下注情况
bet_big = sum(b['amount'] for b in bets if b['bet_type'] == '')
bet_small = sum(b['amount'] for b in bets if b['bet_type'] == '')
banker_display_name = self.db.get_user_display_name(session['banker_id'])
text = f"## 🎰 大小游戏状态\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**最小下注**{session['min_bet']}\n\n"
text += f"**最大下注**{session['max_bet']}\n\n"
text += f"**赔率**{session['multiplier']}\n\n"
text += "---\n\n"
text += f"**当前下注统计**\n"
text += f"- 压大:{bet_big} 分({len([b for b in bets if b['bet_type'] == ''])}注)\n"
text += f"- 压小:{bet_small} 分({len([b for b in bets if b['bet_type'] == ''])}注)\n"
text += f"- 总下注:{len(bets)}\n\n"
text += "---\n\n"
text += "💡 庄家可以使用 `.赌场 大小 settle` 结算"
return text
async def _settle_bigsmall(self, args: str, chat_id: int, user_id: int) -> str:
"""庄家结算游戏(系统随机生成结果)
Args:
args: 无参数
chat_id: 会话ID
user_id: 用户ID
Returns:
结算结果消息
"""
try:
# 不需要参数,系统自动随机生成结果
# 使用系统随机数决定大小50%概率)
result = '' if random.random() > 0.5 else ''
# 结算
settlement = self.db.settle_casino_bets(chat_id, '大小', result, user_id)
# 构建结算报告
text = f"## 🎰 大小游戏结算\n\n"
text += f"**结算结果**:🎲 {result}\n\n"
text += "---\n\n"
text += f"**赢家**{len(settlement['winners'])}\n"
text += f"**输家**{len(settlement['losers'])}\n\n"
# 显示赢家详情
if settlement['winners']:
text += "**赢家明细**\n"
for winner in settlement['winners']:
winner_display_name = self.db.get_user_display_name(winner['user_id'])
text += f"- {winner_display_name}: 下注{winner['amount']}分,赢得{winner['win_amount']}\n"
text += "\n"
# 显示输家详情
if settlement['losers']:
text += "**输家明细**\n"
for loser in settlement['losers']:
loser_display_name = self.db.get_user_display_name(loser['user_id'])
text += f"- {loser_display_name}: 下注{loser['amount']}\n"
text += "\n"
text += "---\n\n"
text += "✅ 游戏已结束,欢迎再次游戏!"
return text
except ValueError as e:
return f"{str(e)}"
except Exception as e:
logger.error(f"结算失败: {e}", exc_info=True)
return f"❌ 结算失败: {str(e)}"
async def _cancel_bigsmall(self, chat_id: int, user_id: int) -> str:
"""庄家放弃本轮游戏
Args:
chat_id: 会话ID
user_id: 用户ID
Returns:
放弃结果消息
"""
try:
# 检查是否有活跃的会话
session = self.db.get_active_casino_session(chat_id, '大小')
if not session:
return "❌ 当前没有进行中的游戏"
# 验证是否为庄家
if session['banker_id'] != user_id:
return "❌ 只有庄家可以放弃游戏"
# 获取所有待结算下注
bets = self.db.get_pending_bets(chat_id, '大小')
# 返还所有下注的积分
return_amount = 0
for bet in bets:
# 返还积分
self.db.add_points(bet['user_id'], bet['amount'], 'casino_cancel',
"庄家放弃游戏,返还下注")
return_amount += bet['amount']
# 关闭会话(不结算,返还积分)
self.db.close_casino_session(chat_id, '大小')
# 标记下注为已取消
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_bets
SET status = 'cancelled'
WHERE chat_id = ? AND game_type = ? AND status = 'pending'
""", (chat_id, '大小'))
# 构建报告
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 游戏已放弃\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**总返还积分**{return_amount}\n\n"
text += f"**返还人数**{len(bets)}\n\n"
text += "---\n\n"
text += "✅ 所有下注已返还,游戏已关闭"
return text
except Exception as e:
logger.error(f"放弃游戏失败: {e}", exc_info=True)
return f"❌ 放弃游戏失败: {str(e)}"
def _get_bigsmall_help(self) -> str:
"""获取大小游戏帮助信息"""
return """## 🎰 大小游戏帮助
### 庄家命令
- `.赌场 大小 open <最小> <最大> <赔率>` - 开启游戏
- 示例:`.赌场 大小 open 10 100 2.0`
- `.赌场 大小 settle` - 结算游戏(系统随机生成结果)
- `.赌场 大小 cancel` - 放弃游戏(返还所有下注)
### 玩家命令
- `.赌场 大小 bet <大/小> <金额>` - 下注
- 示例:`.赌场 大小 bet 大 50`
- 示例:`.赌场 大小 bet 小 30`
### 通用命令
- `.赌场 大小 status` - 查看当前状态
### 游戏规则
- 玩家下注后积分立即扣除
- 结算后根据结果发放奖励
- 庄家放弃游戏时,所有下注全额返还
- 系统抽水5%
- 赔率由庄家设置
"""
def get_help(self) -> str:
"""获取帮助信息"""
text = "# 🎰 赌场游戏帮助\n\n"
text += self._get_bigsmall_help() + "\n\n"
text += self._get_roulette_help() + "\n\n"
text += self._get_blackjack_help()
return text
# ===== 轮盘游戏 =====
async def _handle_roulette(self, args: str, chat_id: int, user_id: int) -> str:
"""处理轮盘游戏
Args:
args: 子命令和参数
chat_id: 会话ID
user_id: 用户ID
Returns:
回复消息
"""
if not args:
return self._get_roulette_help()
parts = args.split(maxsplit=1)
action = parts[0].lower()
sub_args = parts[1] if len(parts) > 1 else ""
if action in ['open', '开启', '开始']:
return await self._open_roulette(sub_args, chat_id, user_id)
elif action in ['bet', '下注', '']:
return await self._bet_roulette(sub_args, chat_id, user_id)
elif action in ['status', '状态', '查看']:
return await self._status_roulette(chat_id)
elif action in ['settle', '结算', '开奖']:
return await self._settle_roulette(chat_id, user_id)
elif action in ['cancel', '放弃', '关闭']:
return await self._cancel_roulette(chat_id, user_id)
elif action in ['help', '帮助']:
return self._get_roulette_help()
else:
return f"❌ 未知命令: {action}\n\n{self._get_roulette_help()}"
async def _open_roulette(self, args: str, chat_id: int, user_id: int) -> str:
"""庄家开启轮盘游戏"""
try:
parts = args.split()
if len(parts) != 2:
return "❌ 参数格式错误!\n\n正确格式:`.赌场 轮盘 open <最小下注> <最大下注>`\n\n示例:`.赌场 轮盘 open 10 100`"
try:
min_bet = int(parts[0])
max_bet = int(parts[1])
except ValueError:
return "❌ 参数必须是数字!"
if min_bet <= 0 or max_bet <= 0:
return "❌ 下注金额必须大于0"
if min_bet > max_bet:
return "❌ 最小下注不能大于最大下注!"
if max_bet > 10000:
return "❌ 最大下注不能超过10000分"
existing = self.db.get_any_active_casino_session(chat_id)
if existing:
return f"⚠️ 当前已有进行中的游戏({existing['game_type']}),请先结算后再开启新游戏。"
session_id = self.db.create_casino_session(
chat_id=chat_id,
game_type='轮盘',
banker_id=user_id,
min_bet=min_bet,
max_bet=max_bet,
multiplier=1.0, # 轮盘赔率根据下注类型自动计算
house_fee=0.05
)
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 轮盘游戏已开启\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**最小下注**{min_bet}\n\n"
text += f"**最大下注**{max_bet}\n\n"
text += f"**抽水率**5%\n\n"
text += "**赔率**\n"
text += "- 数字35倍\n"
text += "- 颜色/奇偶/大小2倍\n"
text += "- 区间3倍\n\n"
text += "---\n\n"
text += "💡 提示:玩家可以使用 `.赌场 轮盘 bet <类型> <选项> <金额>` 进行下注"
return text
except Exception as e:
logger.error(f"开启轮盘游戏失败: {e}", exc_info=True)
return f"❌ 开启游戏失败: {str(e)}"
async def _bet_roulette(self, args: str, chat_id: int, user_id: int) -> str:
"""玩家下注轮盘"""
try:
parts = args.split()
if len(parts) < 2:
return "❌ 参数格式错误!\n\n正确格式:`.赌场 轮盘 bet <类型> <选项> <金额>`\n\n示例:`.赌场 轮盘 bet 数字 17 100`"
bet_category = parts[0]
if len(parts) == 2:
# 颜色/奇偶/大小/区间下注bet <类型> <金额>
bet_value = bet_category
bet_category_map = {
'红色': '颜色', '黑色': '颜色', '绿色': '颜色',
'奇数': '奇偶', '偶数': '奇偶',
'': '大小', '': '大小',
'1-12': '区间', '13-24': '区间', '25-36': '区间'
}
bet_category = bet_category_map.get(bet_value)
if not bet_category:
return f"❌ 未知的下注类型: {bet_value}"
try:
amount = int(parts[1])
except ValueError:
return "❌ 下注金额必须是数字!"
bet_number = None
elif len(parts) == 3:
# 数字下注bet 数字 <数字> <金额>
if bet_category != '数字':
return "❌ 数字下注格式:`.赌场 轮盘 bet 数字 <0-36> <金额>`"
try:
bet_number = int(parts[1])
amount = int(parts[2])
except ValueError:
return "❌ 数字和金额必须是数字!"
if bet_number < 0 or bet_number > 36:
return "❌ 数字必须在0-36之间"
bet_value = None
else:
return "❌ 参数格式错误!"
session = self.db.get_active_casino_session(chat_id, '轮盘')
if not session:
return "❌ 当前没有进行中的游戏,请等待庄家开启游戏。"
if amount < session['min_bet']:
return f"❌ 下注金额太小!最小下注:{session['min_bet']}"
if amount > session['max_bet']:
return f"❌ 下注金额太大!最大下注:{session['max_bet']}"
user_points = self.db.get_user_points(user_id)
if user_points['points'] < amount:
return f"❌ 积分不足!需要 {amount} 分,当前可用 {user_points['points']}"
# 根据下注类型计算赔率
if bet_category == '数字':
multiplier = 36.0 # 35:1赔率返回36倍包含本金
elif bet_category in ['颜色', '奇偶', '大小']:
multiplier = 2.0
elif bet_category == '区间':
multiplier = 3.0
else:
return f"❌ 未知的下注类别: {bet_category}"
if not self.db.consume_points(user_id, amount, 'casino_bet', f"轮盘游戏下注{bet_category}"):
return "❌ 扣除积分失败!"
bet_id = self.db.create_casino_bet(
chat_id=chat_id,
game_type='轮盘',
user_id=user_id,
bet_type='轮盘',
amount=amount,
multiplier=multiplier,
bet_category=bet_category,
bet_number=bet_number,
bet_value=bet_value
)
updated_points = self.db.get_user_points(user_id)
text = f"## 🎲 下注成功\n\n"
text += f"**下注类型**{bet_category}"
if bet_number is not None:
text += f" - {bet_number}"
elif bet_value:
text += f" - {bet_value}"
text += f"\n\n**下注金额**{amount}\n\n"
text += f"**赔率**{multiplier}\n\n"
text += f"**剩余积分**{updated_points['points']}\n\n"
text += "---\n\n"
text += "💡 等待庄家结算结果..."
return text
except Exception as e:
logger.error(f"轮盘下注失败: {e}", exc_info=True)
return f"❌ 下注失败: {str(e)}"
async def _status_roulette(self, chat_id: int) -> str:
"""查看轮盘游戏状态"""
session = self.db.get_active_casino_session(chat_id, '轮盘')
if not session:
return "❌ 当前没有进行中的轮盘游戏"
bets = self.db.get_pending_bets(chat_id, '轮盘')
# 统计下注情况
bet_stats = {}
for bet in bets:
category = bet.get('bet_category', '未知')
value = bet.get('bet_value') or str(bet.get('bet_number', ''))
key = f"{category}-{value}"
if key not in bet_stats:
bet_stats[key] = {'amount': 0, 'count': 0}
bet_stats[key]['amount'] += bet['amount']
bet_stats[key]['count'] += 1
banker_display_name = self.db.get_user_display_name(session['banker_id'])
text = f"## 🎰 轮盘游戏状态\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**最小下注**{session['min_bet']}\n\n"
text += f"**最大下注**{session['max_bet']}\n\n"
text += "---\n\n"
text += f"**当前下注统计**\n"
for key, stat in bet_stats.items():
parts = key.split('-', 1)
text += f"- {parts[0]}{' - ' + parts[1] if len(parts) > 1 else ''}{stat['amount']} 分({stat['count']}注)\n"
text += f"\n**总下注**{len(bets)}\n\n"
text += "---\n\n"
text += "💡 庄家可以使用 `.赌场 轮盘 settle` 结算"
return text
async def _settle_roulette(self, chat_id: int, user_id: int) -> str:
"""庄家结算轮盘游戏(系统随机生成结果)"""
try:
# 系统随机生成0-36的数字
result_number = random.randint(0, 36)
# 结算
settlement = self.db.settle_casino_bets(
chat_id, '轮盘', str(result_number), user_id,
result_number=result_number
)
# 构建结算报告
text = f"## 🎰 轮盘游戏结算\n\n"
text += f"**结算结果**:🎲 **{result_number}**\n\n"
text += "---\n\n"
text += f"**赢家**{len(settlement['winners'])}\n"
text += f"**输家**{len(settlement['losers'])}\n\n"
if settlement['winners']:
text += "**赢家明细**\n"
for winner in settlement['winners']:
winner_display_name = self.db.get_user_display_name(winner['user_id'])
text += f"- {winner_display_name}: 下注{winner['amount']}分,赢得{winner['win_amount']}\n"
text += "\n"
if settlement['losers']:
text += "**输家明细**\n"
for loser in settlement['losers']:
loser_display_name = self.db.get_user_display_name(loser['user_id'])
text += f"- {loser_display_name}: 下注{loser['amount']}\n"
text += "\n"
text += "---\n\n"
text += "✅ 游戏已结束,欢迎再次游戏!"
return text
except ValueError as e:
return f"{str(e)}"
except Exception as e:
logger.error(f"轮盘结算失败: {e}", exc_info=True)
return f"❌ 结算失败: {str(e)}"
async def _cancel_roulette(self, chat_id: int, user_id: int) -> str:
"""庄家放弃轮盘游戏"""
try:
session = self.db.get_active_casino_session(chat_id, '轮盘')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以放弃游戏"
bets = self.db.get_pending_bets(chat_id, '轮盘')
return_amount = 0
for bet in bets:
self.db.add_points(bet['user_id'], bet['amount'], 'casino_cancel',
"庄家放弃游戏,返还下注")
return_amount += bet['amount']
self.db.close_casino_session(chat_id, '轮盘')
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_bets
SET status = 'cancelled'
WHERE chat_id = ? AND game_type = ? AND status = 'pending'
""", (chat_id, '轮盘'))
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 游戏已放弃\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**总返还积分**{return_amount}\n\n"
text += f"**返还人数**{len(bets)}\n\n"
text += "---\n\n"
text += "✅ 所有下注已返还,游戏已关闭"
return text
except Exception as e:
logger.error(f"放弃轮盘游戏失败: {e}", exc_info=True)
return f"❌ 放弃游戏失败: {str(e)}"
def _get_roulette_help(self) -> str:
"""获取轮盘游戏帮助信息"""
return """## 🎰 轮盘游戏帮助
### 庄家命令
- `.赌场 轮盘 open <最小> <最大>` - 开启游戏
- 示例:`.赌场 轮盘 open 10 100`
- `.赌场 轮盘 settle` - 结算游戏系统随机生成0-36
- `.赌场 轮盘 cancel` - 放弃游戏(返还所有下注)
### 玩家命令
- `.赌场 轮盘 bet <类型> <选项> <金额>` - 下注
- 数字:`.赌场 轮盘 bet 数字 17 100` 押数字17100分35倍赔率
- 颜色:`.赌场 轮盘 bet 红色 50` 押红色50分2倍赔率
- 奇偶:`.赌场 轮盘 bet 奇数 30` 押奇数30分2倍赔率
- 大小:`.赌场 轮盘 bet 大 40` 押大19-3640分2倍赔率
- 区间:`.赌场 轮盘 bet 1-12 60` 押1-1260分3倍赔率
### 通用命令
- `.赌场 轮盘 status` - 查看当前状态
### 游戏规则
- 数字0-360为绿色其他数字为红色或黑色
- 数字下注35倍赔率
- 颜色/奇偶/大小2倍赔率
- 区间1-12/13-24/25-363倍赔率
- 系统抽水5%"""
# ===== 21点游戏 =====
async def _handle_blackjack(self, args: str, chat_id: int, user_id: int) -> str:
"""处理21点游戏"""
if not args:
return self._get_blackjack_help()
parts = args.split(maxsplit=1)
action = parts[0].lower()
sub_args = parts[1] if len(parts) > 1 else ""
if action in ['open', '开启', '开始']:
return await self._open_blackjack(sub_args, chat_id, user_id)
elif action in ['join', '加入']:
return await self._join_blackjack(chat_id, user_id)
elif action in ['bet', '下注', '', '加注']:
return await self._bet_blackjack(sub_args, chat_id, user_id)
elif action in ['deal', '发牌']:
return await self._deal_blackjack(chat_id, user_id)
elif action in ['hit', '要牌']:
return await self._hit_blackjack(chat_id, user_id)
elif action in ['stand', '停牌']:
return await self._stand_blackjack(chat_id, user_id)
elif action in ['status', '状态', '查看']:
return await self._status_blackjack(chat_id)
elif action in ['settle', '结算']:
return await self._settle_blackjack(chat_id, user_id)
elif action in ['cancel', '放弃', '关闭']:
return await self._cancel_blackjack(chat_id, user_id)
elif action in ['help', '帮助']:
return self._get_blackjack_help()
else:
return f"❌ 未知命令: {action}\n\n{self._get_blackjack_help()}"
async def _open_blackjack(self, args: str, chat_id: int, user_id: int) -> str:
"""庄家开启21点游戏"""
try:
parts = args.split()
if len(parts) < 2:
return "❌ 参数格式错误!\n\n正确格式:`.赌场 21点 open <底注> <黑杰克倍数>`\n\n示例:`.赌场 21点 open 50 1.5`"
try:
base_bet = int(parts[0])
blackjack_multiplier = float(parts[1])
except ValueError:
return "❌ 参数必须是数字!"
if base_bet <= 0:
return "❌ 底注必须大于0"
if base_bet > 10000:
return "❌ 底注不能超过10000分"
if blackjack_multiplier <= 0:
return "❌ 黑杰克倍数必须大于0"
existing = self.db.get_any_active_casino_session(chat_id)
if existing:
return f"⚠️ 当前已有进行中的游戏({existing['game_type']}),请先结算后再开启新游戏。"
session_id = self.db.create_casino_session(
chat_id=chat_id,
game_type='21点',
banker_id=user_id,
min_bet=base_bet, # 底注作为最小下注
max_bet=base_bet * 10, # 最大下注设为底注的10倍
multiplier=1.0, # 21点标准赔率1:1
house_fee=0.05,
current_phase='betting',
blackjack_multiplier=blackjack_multiplier
)
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 21点游戏已开启\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**底注**{base_bet}\n\n"
text += f"**黑杰克倍数**{blackjack_multiplier}\n\n"
text += f"**抽水率**5%\n\n"
text += "---\n\n"
text += f"💡 提示:玩家使用 `.赌场 21点 join` 加入游戏(需要至少{base_bet}分积分)"
return text
except Exception as e:
logger.error(f"开启21点游戏失败: {e}", exc_info=True)
return f"❌ 开启游戏失败: {str(e)}"
async def _join_blackjack(self, chat_id: int, user_id: int) -> str:
"""玩家加入21点游戏"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏,请等待庄家开启游戏。"
if session['current_phase'] != 'betting':
return "❌ 当前不是加入阶段,游戏已开始。"
# 检查是否已经加入
bets = self.db.get_pending_bets(chat_id, '21点')
existing_bet = next((b for b in bets if b['user_id'] == user_id), None)
if existing_bet:
return f"❌ 您已经加入游戏,当前下注:{existing_bet['amount']}"
base_bet = session['min_bet']
# 检查积分是否足够底注
user_points = self.db.get_user_points(user_id)
if user_points['points'] < base_bet:
return f"❌ 积分不足!需要至少 {base_bet} 分才能加入,当前可用 {user_points['points']}"
# 扣除底注
if not self.db.consume_points(user_id, base_bet, 'casino_bet', "21点游戏加入底注"):
return "❌ 扣除积分失败!"
# 创建下注记录(使用底注)
bet_id = self.db.create_casino_bet(
chat_id=chat_id,
game_type='21点',
user_id=user_id,
bet_type='标准',
amount=base_bet,
multiplier=1.0, # 标准赔率1:1
hand_status='playing'
)
updated_points = self.db.get_user_points(user_id)
player_name = self.db.get_user_display_name(user_id)
text = f"## 🎲 加入成功\n\n"
text += f"**玩家**{player_name}\n\n"
text += f"**底注**{base_bet}\n\n"
text += f"**剩余积分**{updated_points['points']}\n\n"
text += "---\n\n"
text += "💡 等待庄家发牌..."
return text
except Exception as e:
logger.error(f"21点加入失败: {e}", exc_info=True)
return f"❌ 加入失败: {str(e)}"
async def _bet_blackjack(self, args: str, chat_id: int, user_id: int) -> str:
"""玩家加注(游戏中加注)"""
try:
try:
amount = int(args.strip())
except ValueError:
return "❌ 加注金额必须是数字!\n\n正确格式:`.赌场 21点 bet <加注金额>`\n\n加注金额必须不低于底注"
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏。"
if session['current_phase'] != 'playing':
return "❌ 当前不是游戏阶段,无法加注。"
base_bet = session['min_bet']
if amount < base_bet:
return f"❌ 加注金额太小!必须不低于底注:{base_bet}"
# 检查玩家是否有下注
bets = self.db.get_pending_bets(chat_id, '21点')
user_bet = next((b for b in bets if b['user_id'] == user_id), None)
if not user_bet:
return "❌ 您没有加入游戏,无法加注"
# 检查玩家手牌状态
session_id = session['id']
hand = self.db.get_blackjack_hand(session_id, user_id)
if not hand or hand['hand_status'] != 'playing':
return f"❌ 当前手牌状态不允许加注(状态:{hand['hand_status'] if hand else '未找到'}"
# 检查积分是否足够
user_points = self.db.get_user_points(user_id)
if user_points['points'] < amount:
return f"❌ 积分不足!需要 {amount} 分,当前可用 {user_points['points']}"
# 扣除加注金额
if not self.db.consume_points(user_id, amount, 'casino_bet', "21点游戏加注"):
return "❌ 扣除积分失败!"
# 更新下注金额
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_bets
SET amount = amount + ?
WHERE id = ?
""", (amount, user_bet['id']))
updated_points = self.db.get_user_points(user_id)
player_name = self.db.get_user_display_name(user_id)
new_total = user_bet['amount'] + amount
text = f"## 🎲 加注成功\n\n"
text += f"**玩家**{player_name}\n\n"
text += f"**加注金额**{amount}\n\n"
text += f"**总下注**{new_total} 分(原底注 {user_bet['amount']} + 加注 {amount}\n\n"
text += f"**剩余积分**{updated_points['points']}\n\n"
text += "---\n\n"
text += "💡 可以继续要牌或停牌"
return text
except Exception as e:
logger.error(f"21点加注失败: {e}", exc_info=True)
return f"❌ 加注失败: {str(e)}"
def _draw_card(self) -> int:
"""抽取一张牌1-13其中1=A11=J12=Q13=K"""
return random.randint(1, 13)
def _calculate_points(self, cards: List[int]) -> int:
"""计算21点手牌点数复用数据库方法逻辑"""
return self.db._calculate_blackjack_points(cards)
def _check_blackjack(self, cards: List[int]) -> bool:
"""检查是否为黑杰克A+10/J/Q/K"""
if len(cards) != 2:
return False
has_ace = 1 in cards
has_ten = any(card >= 11 for card in cards) or 10 in cards
return has_ace and has_ten
async def _deal_blackjack(self, chat_id: int, user_id: int) -> str:
"""庄家发初始牌"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以发牌"
if session['current_phase'] != 'betting':
return "❌ 当前阶段不是下注阶段,无法发牌"
bets = self.db.get_pending_bets(chat_id, '21点')
if not bets:
return "❌ 还没有玩家下注,无法发牌"
session_id = session['id']
# 标准发牌顺序:
# 1. 先给每个玩家发一张牌
# 2. 再给庄家发一张明牌
# 3. 再给每个玩家发第二张牌
# 4. 最后给庄家发第二张暗牌
player_hands = {}
player_first_cards = {}
# 第一轮:给每个玩家发一张牌
for bet in bets:
first_card = self._draw_card()
player_first_cards[bet['user_id']] = [first_card]
# 给庄家发第一张明牌
banker_first_card = self._draw_card()
banker_cards = [banker_first_card]
# 第二轮:给每个玩家发第二张牌
for bet in bets:
second_card = self._draw_card()
player_cards = player_first_cards[bet['user_id']] + [second_card]
player_points = self._calculate_points(player_cards)
player_status = 'blackjack' if self._check_blackjack(player_cards) else 'playing'
self.db.create_blackjack_hand(session_id, bet['user_id'], player_cards, player_status)
player_hands[bet['user_id']] = {
'cards': player_cards,
'points': player_points,
'status': player_status
}
# 给庄家发第二张暗牌
banker_second_card = self._draw_card()
banker_cards.append(banker_second_card)
banker_points = self._calculate_points(banker_cards)
banker_status = 'blackjack' if self._check_blackjack(banker_cards) else 'playing'
# 存储庄家完整手牌(包含暗牌)
self.db.create_blackjack_hand(session_id, 0, banker_cards, banker_status)
# 更新session阶段
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_sessions
SET current_phase = 'playing'
WHERE id = ?
""", (session_id,))
# 构建发牌结果(庄家只显示明牌)
text = f"## 🎰 发牌完成\n\n"
text += f"**庄家手牌**{self._format_cards([banker_first_card])} ? (隐藏一张暗牌)\n\n"
if banker_status == 'blackjack':
text += "**庄家黑杰克!**\n\n"
text += "---\n\n"
text += "**玩家手牌**\n"
for user_id, hand in player_hands.items():
player_name = self.db.get_user_display_name(user_id)
text += f"- {player_name}{self._format_cards(hand['cards'])} ({hand['points']}点)"
if hand['status'] == 'blackjack':
text += " **黑杰克!**"
text += "\n"
text += "\n---\n\n"
text += "💡 玩家可以使用 `.赌场 21点 hit` 要牌、`.赌场 21点 stand` 停牌或 `.赌场 21点 bet <金额>` 加注"
return text
except Exception as e:
logger.error(f"21点发牌失败: {e}", exc_info=True)
return f"❌ 发牌失败: {str(e)}"
def _format_cards(self, cards: List[int]) -> str:
"""格式化手牌显示"""
card_names = {
1: 'A',
11: 'J',
12: 'Q',
13: 'K'
}
formatted = []
for card in cards:
if card in card_names:
formatted.append(card_names[card])
else:
formatted.append(str(card))
return ' '.join(formatted)
async def _hit_blackjack(self, chat_id: int, user_id: int) -> str:
"""玩家要牌"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['current_phase'] != 'playing':
return "❌ 当前不是游戏阶段,无法要牌"
# 检查玩家是否有下注
bets = self.db.get_pending_bets(chat_id, '21点')
user_bet = next((b for b in bets if b['user_id'] == user_id), None)
if not user_bet:
return "❌ 您没有下注,无法要牌"
# 获取玩家手牌
session_id = session['id']
hand = self.db.get_blackjack_hand(session_id, user_id)
if not hand:
return "❌ 未找到手牌信息"
if hand['hand_status'] != 'playing':
return f"❌ 当前手牌状态为:{hand['hand_status']},无法要牌"
# 抽一张新牌
new_card = self._draw_card()
cards = hand['hand_data'] + [new_card]
points = self._calculate_points(cards)
# 判断状态
if points > 21:
status = 'busted'
elif points == 21:
status = 'stood'
else:
status = 'playing'
# 更新手牌
self.db.update_blackjack_hand(session_id, user_id, cards, status)
player_name = self.db.get_user_display_name(user_id)
text = f"## 🎲 要牌\n\n"
text += f"**玩家**{player_name}\n\n"
text += f"**新手牌**{self._format_cards(cards)} ({points}点)\n\n"
if status == 'busted':
text += "**爆牌!** ❌\n\n"
elif points == 21:
text += "**21点** ✅\n\n"
# 如果爆牌,检查是否所有玩家都已完成
if status == 'busted':
all_hands = self.db.get_all_blackjack_hands(session_id)
bets = self.db.get_pending_bets(chat_id, '21点')
all_players_done = True
for bet in bets:
player_hand = all_hands.get(bet['user_id'])
if player_hand and player_hand['status'] == 'playing':
all_players_done = False
break
if all_players_done:
text += "---\n\n"
text += "✅ 所有玩家已完成操作,自动结算中...\n\n"
# 调用结算方法使用庄家ID
try:
settlement_result = await self._settle_blackjack(chat_id, session['banker_id'])
return settlement_result
except Exception as e:
logger.error(f"自动结算失败: {e}", exc_info=True)
text += f"❌ 自动结算失败: {str(e)}"
return text
text += "---\n\n"
if status == 'playing':
text += "💡 可以继续要牌或停牌"
elif status == 'stood':
text += "💡 21点自动停牌"
else:
text += "💡 已爆牌,等待结算"
return text
except Exception as e:
logger.error(f"21点要牌失败: {e}", exc_info=True)
return f"❌ 要牌失败: {str(e)}"
async def _stand_blackjack(self, chat_id: int, user_id: int) -> str:
"""玩家停牌"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['current_phase'] != 'playing':
return "❌ 当前不是游戏阶段,无法停牌"
session_id = session['id']
hand = self.db.get_blackjack_hand(session_id, user_id)
if not hand:
return "❌ 未找到手牌信息"
if hand['hand_status'] != 'playing':
return f"❌ 当前手牌状态为:{hand['hand_status']},无法停牌"
# 更新状态为停牌
self.db.update_blackjack_hand(session_id, user_id, hand['hand_data'], 'stood')
points = self._calculate_points(hand['hand_data'])
player_name = self.db.get_user_display_name(user_id)
# 检查是否所有玩家都已停牌或爆牌
all_hands = self.db.get_all_blackjack_hands(session_id)
bets = self.db.get_pending_bets(chat_id, '21点')
all_players_done = True
for bet in bets:
player_hand = all_hands.get(bet['user_id'])
if player_hand and player_hand['status'] == 'playing':
all_players_done = False
break
text = f"## 🎲 停牌\n\n"
text += f"**玩家**{player_name}\n\n"
text += f"**最终手牌**{self._format_cards(hand['hand_data'])} ({points}点)\n\n"
# 如果所有玩家都已完成,自动结算
if all_players_done:
text += "---\n\n"
text += "✅ 所有玩家已完成操作,自动结算中...\n\n"
# 调用结算方法使用庄家ID
try:
settlement_result = await self._settle_blackjack(chat_id, session['banker_id'])
return settlement_result
except Exception as e:
logger.error(f"自动结算失败: {e}", exc_info=True)
text += f"❌ 自动结算失败: {str(e)}"
return text
else:
text += "---\n\n"
text += "💡 已停牌,等待其他玩家操作"
return text
except Exception as e:
logger.error(f"21点停牌失败: {e}", exc_info=True)
return f"❌ 停牌失败: {str(e)}"
async def _status_blackjack(self, chat_id: int) -> str:
"""查看21点游戏状态"""
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的21点游戏"
session_id = session['id']
bets = self.db.get_pending_bets(chat_id, '21点')
hands = self.db.get_all_blackjack_hands(session_id)
banker_display_name = self.db.get_user_display_name(session['banker_id'])
text = f"## 🎰 21点游戏状态\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**当前阶段**{session['current_phase']}\n\n"
text += f"**最小下注**{session['min_bet']}\n\n"
text += f"**最大下注**{session['max_bet']}\n\n"
text += f"**黑杰克倍数**{session.get('blackjack_multiplier', 1.5)}\n\n"
# 显示庄家手牌(隐藏暗牌)
banker_hand = hands.get(0)
if banker_hand:
banker_cards = banker_hand['cards']
if session['current_phase'] == 'playing' and len(banker_cards) >= 2:
# 游戏阶段:只显示第一张明牌,隐藏暗牌
visible_card = banker_cards[0]
text += f"**庄家手牌**{self._format_cards([visible_card])} ? (隐藏一张暗牌)"
else:
# 已结算或发牌前:显示完整手牌
banker_points = self._calculate_points(banker_cards)
text += f"**庄家手牌**{self._format_cards(banker_cards)} ({banker_points}点)"
if banker_hand['status'] == 'blackjack':
text += " **黑杰克!**"
text += "\n\n"
text += "---\n\n"
text += f"**玩家下注**{len(bets)}\n\n"
# 显示玩家手牌
if hands:
text += "**玩家手牌**\n"
for user_id, hand in hands.items():
if user_id == 0: # 跳过庄家
continue
player_name = self.db.get_user_display_name(user_id)
player_bet = next((b for b in bets if b['user_id'] == user_id), None)
if player_bet:
points = self._calculate_points(hand['cards'])
text += f"- {player_name}{self._format_cards(hand['cards'])} ({points}点) - 下注{player_bet['amount']}"
if hand['status'] == 'blackjack':
text += " **黑杰克!**"
elif hand['status'] == 'busted':
text += " **爆牌**"
elif hand['status'] == 'stood':
text += " **已停牌**"
text += "\n"
text += "\n"
text += "---\n\n"
if session['current_phase'] == 'betting':
text += "💡 庄家可以使用 `.赌场 21点 deal` 发牌"
elif session['current_phase'] == 'playing':
text += "💡 玩家可以使用 `.赌场 21点 hit` 要牌或 `.赌场 21点 stand` 停牌\n"
text += "💡 庄家可以使用 `.赌场 21点 settle` 结算"
else:
text += "💡 庄家可以使用 `.赌场 21点 settle` 结算"
return text
async def _settle_blackjack(self, chat_id: int, user_id: int) -> str:
"""庄家结算21点游戏"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以结算游戏"
if session['current_phase'] == 'betting':
return "❌ 还未发牌,无法结算"
session_id = session['id']
hands = self.db.get_all_blackjack_hands(session_id)
# 获取庄家手牌
banker_hand = hands.get(0, {})
banker_cards = banker_hand.get('cards', [])
banker_points = self._calculate_points(banker_cards)
banker_status = banker_hand.get('status', 'stood')
# 如果庄家还在playing状态自动要牌到17点以上
while banker_status == 'playing' and banker_points < 17:
new_card = self._draw_card()
banker_cards.append(new_card)
banker_points = self._calculate_points(banker_cards)
if banker_points > 21:
banker_status = 'busted'
elif banker_points >= 17:
banker_status = 'stood'
# 更新庄家手牌
self.db.update_blackjack_hand(session_id, 0, banker_cards, banker_status)
# 更新hands字典
hands[0] = {'cards': banker_cards, 'status': banker_status}
#進行结算
settlement = self.db.settle_casino_bets(
chat_id, '21点', f"庄家{banker_points}", user_id,
hands_dict=hands
)
# 构建结算报告
text = f"## 🎰 21点游戏结算\n\n"
text += f"**庄家最终手牌**{self._format_cards(banker_cards)} ({banker_points}点)\n\n"
if banker_status == 'blackjack':
text += "**庄家黑杰克!**\n\n"
elif banker_status == 'busted':
text += "**庄家爆牌!**\n\n"
text += "---\n\n"
text += f"**赢家**{len(settlement['winners'])}\n"
text += f"**输家**{len(settlement['losers'])}\n\n"
if settlement['winners']:
text += "**赢家明细**\n"
for winner in settlement['winners']:
winner_display_name = self.db.get_user_display_name(winner['user_id'])
player_hand = hands.get(winner['user_id'], {})
player_points = self._calculate_points(player_hand.get('cards', []))
text += f"- {winner_display_name}: {self._format_cards(player_hand.get('cards', []))} ({player_points}点) - 下注{winner['amount']}分,赢得{winner['win_amount']}\n"
text += "\n"
if settlement['losers']:
text += "**输家明细**\n"
for loser in settlement['losers']:
loser_display_name = self.db.get_user_display_name(loser['user_id'])
player_hand = hands.get(loser['user_id'], {})
player_points = self._calculate_points(player_hand.get('cards', []))
text += f"- {loser_display_name}: {self._format_cards(player_hand.get('cards', []))} ({player_points}点) - 下注{loser['amount']}\n"
text += "\n"
text += "---\n\n"
text += "✅ 游戏已结束,欢迎再次游戏!"
return text
except ValueError as e:
return f"{str(e)}"
except Exception as e:
logger.error(f"21点结算失败: {e}", exc_info=True)
return f"❌ 结算失败: {str(e)}"
async def _cancel_blackjack(self, chat_id: int, user_id: int) -> str:
"""庄家放弃21点游戏"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以放弃游戏"
bets = self.db.get_pending_bets(chat_id, '21点')
return_amount = 0
for bet in bets:
self.db.add_points(bet['user_id'], bet['amount'], 'casino_cancel',
"庄家放弃游戏,返还下注")
return_amount += bet['amount']
self.db.close_casino_session(chat_id, '21点')
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_bets
SET status = 'cancelled'
WHERE chat_id = ? AND game_type = ? AND status = 'pending'
""", (chat_id, '21点'))
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 游戏已放弃\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**总返还积分**{return_amount}\n\n"
text += f"**返还人数**{len(bets)}\n\n"
text += "---\n\n"
text += "✅ 所有下注已返还,游戏已关闭"
return text
except Exception as e:
logger.error(f"放弃21点游戏失败: {e}", exc_info=True)
return f"❌ 放弃游戏失败: {str(e)}"
def _get_blackjack_help(self) -> str:
"""获取21点游戏帮助信息"""
return """## 🎰 21点游戏帮助
### 游戏流程
1. **庄家开启**`.赌场 21点 open <底注> <黑杰克倍数>`
- 示例:`.赌场 21点 open 50 1.5`
2. **玩家加入**`.赌场 21点 join`(需要至少底注的积分)
3. **庄家发牌**`.赌场 21点 deal`
4. **玩家操作**:要牌、停牌或加注
5. **自动结算**:所有玩家停牌后自动结算
### 庄家命令
- `.赌场 21点 open <底注> <黑杰克倍数>` - 开启游戏
- 示例:`.赌场 21点 open 50 1.5`
- `.赌场 21点 deal` - 发牌(玩家加入后)
- `.赌场 21点 settle` - 手动结算(可选,会自动结算)
- `.赌场 21点 cancel` - 放弃游戏(返还所有下注)
### 玩家命令
- `.赌场 21点 join` - 加入游戏(扣除底注,需要至少底注的积分)
- `.赌场 21点 bet <金额>` - 加注(游戏中,不低于底注)
- 示例:`.赌场 21点 bet 50`
- `.赌场 21点 hit` - 要牌
- `.赌场 21点 stand` - 停牌(所有玩家停牌后自动结算)
### 通用命令
- `.赌场 21点 status` - 查看当前状态
### 游戏规则
- **目标**手牌点数尽可能接近21点但不能超过
- **发牌**:标准发牌顺序,庄家隐藏一张暗牌
- **黑杰克**A+10/J/Q/K赢得设定倍数默认1.5倍)
- **玩家点数>庄家点数且未爆牌**赢得1:1
- **平局**:返还下注
- **爆牌**:失去下注
- **庄家规则**自动要牌到17点以上
- **自动结算**:所有玩家停牌后,最后一名玩家停牌时立即结算
- **系统抽水**5%"""