21点游戏规则更新

This commit is contained in:
2025-10-31 15:57:26 +08:00
parent 9e16774d2f
commit b07b044035

View File

@@ -767,7 +767,9 @@ class CasinoGame(BaseGame):
if action in ['open', '开启', '开始']:
return await self._open_blackjack(sub_args, chat_id, user_id)
elif action in ['bet', '下注', '']:
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)
@@ -791,23 +793,19 @@ class CasinoGame(BaseGame):
try:
parts = args.split()
if len(parts) < 2:
return "❌ 参数格式错误!\n\n正确格式:`.赌场 21点 open <最小下注> <最大下注> [黑杰克倍数]`\n\n示例:`.赌场 21点 open 10 100 1.5`"
return "❌ 参数格式错误!\n\n正确格式:`.赌场 21点 open <注> <黑杰克倍数>`\n\n示例:`.赌场 21点 open 50 1.5`"
try:
min_bet = int(parts[0])
max_bet = int(parts[1])
blackjack_multiplier = float(parts[2]) if len(parts) > 2 else 1.5
base_bet = int(parts[0])
blackjack_multiplier = float(parts[1])
except ValueError:
return "❌ 参数必须是数字!"
if min_bet <= 0 or max_bet <= 0:
return "下注金额必须大于0"
if base_bet <= 0:
return "底注必须大于0"
if min_bet > max_bet:
return "最小下注不能大于最大下注"
if max_bet > 10000:
return "❌ 最大下注不能超过10000分"
if base_bet > 10000:
return "底注不能超过10000分"
if blackjack_multiplier <= 0:
return "❌ 黑杰克倍数必须大于0"
@@ -820,8 +818,8 @@ class CasinoGame(BaseGame):
chat_id=chat_id,
game_type='21点',
banker_id=user_id,
min_bet=min_bet,
max_bet=max_bet,
min_bet=base_bet, # 底注作为最小下注
max_bet=base_bet * 10, # 最大下注设为底注的10倍
multiplier=1.0, # 21点标准赔率1:1
house_fee=0.05,
current_phase='betting',
@@ -831,12 +829,11 @@ class CasinoGame(BaseGame):
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"**最小下注**{min_bet}\n\n"
text += f"**最大下注**{max_bet}\n\n"
text += f"**注**{base_bet}\n\n"
text += f"**黑杰克倍数**{blackjack_multiplier}\n\n"
text += f"**抽水率**5%\n\n"
text += "---\n\n"
text += "💡 提示:玩家下注后,庄家使用 `.赌场 21点 deal` 发牌"
text += f"💡 提示:玩家使用 `.赌场 21点 join` 加入游戏(需要至少{base_bet}分积分)"
return text
@@ -844,47 +841,49 @@ class CasinoGame(BaseGame):
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:
"""玩家下注21点"""
async def _join_blackjack(self, chat_id: int, user_id: int) -> str:
"""玩家加入21点游戏"""
try:
try:
amount = int(args.strip())
except ValueError:
return "❌ 下注金额必须是数字!\n\n正确格式:`.赌场 21点 bet <金额>`"
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏,请等待庄家开启游戏。"
if session['current_phase'] != 'betting':
return "❌ 当前不是下注阶段,无法下注"
return "❌ 当前不是加入阶段,游戏已开始"
if amount < session['min_bet']:
return f"❌ 下注金额太小!最小下注:{session['min_bet']}"
# 检查是否已经加入
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']}"
if amount > session['max_bet']:
return f"❌ 下注金额太大!最大下注:{session['max_bet']}"
base_bet = session['min_bet']
# 检查积分是否足够底注
user_points = self.db.get_user_points(user_id)
if user_points['points'] < amount:
return f"❌ 积分不足!需要 {amount} 分,当前可用 {user_points['points']}"
if user_points['points'] < base_bet:
return f"❌ 积分不足!需要至少 {base_bet}才能加入,当前可用 {user_points['points']}"
if not self.db.consume_points(user_id, amount, 'casino_bet', "21点游戏下注"):
# 扣除底注
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=amount,
amount=base_bet,
multiplier=1.0, # 标准赔率1:1
hand_status='playing'
)
updated_points = self.db.get_user_points(user_id)
text = f"## 🎲 下注成功\n\n"
text += f"**下注金额**{amount}\n\n"
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 += "💡 等待庄家发牌..."
@@ -892,8 +891,74 @@ class CasinoGame(BaseGame):
return text
except Exception as e:
logger.error(f"21点下注失败: {e}", exc_info=True)
return f"下注失败: {str(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"""
@@ -930,17 +995,28 @@ class CasinoGame(BaseGame):
session_id = session['id']
# 为庄家发两张牌
banker_cards = [self._draw_card(), self._draw_card()]
banker_points = self._calculate_points(banker_cards)
banker_status = 'blackjack' if self._check_blackjack(banker_cards) else 'playing'
# 标准发牌顺序:
# 1. 先给每个玩家发一张牌
# 2. 再给庄家发一张明牌
# 3. 再给每个玩家发第二张牌
# 4. 最后给庄家发第二张暗牌
self.db.create_blackjack_hand(session_id, 0, banker_cards, banker_status)
# 为每个下注的玩家发两张牌
player_hands = {}
player_first_cards = {}
# 第一轮:给每个玩家发一张牌
for bet in bets:
player_cards = [self._draw_card(), self._draw_card()]
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'
@@ -951,6 +1027,15 @@ class CasinoGame(BaseGame):
'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("""
@@ -959,9 +1044,9 @@ class CasinoGame(BaseGame):
WHERE id = ?
""", (session_id,))
# 构建发牌结果
# 构建发牌结果(庄家只显示明牌)
text = f"## 🎰 发牌完成\n\n"
text += f"**庄家手牌**{self._format_cards(banker_cards)} ({banker_points}点)\n\n"
text += f"**庄家手牌**{self._format_cards([banker_first_card])} ? (隐藏一张暗牌)\n\n"
if banker_status == 'blackjack':
text += "**庄家黑杰克!**\n\n"
@@ -976,7 +1061,7 @@ class CasinoGame(BaseGame):
text += "\n"
text += "\n---\n\n"
text += "💡 玩家可以使用 `.赌场 21点 hit` 要牌`.赌场 21点 stand` 停牌"
text += "💡 玩家可以使用 `.赌场 21点 hit` 要牌`.赌场 21点 stand` 停牌或 `.赌场 21点 bet <金额>` 加注"
return text
@@ -1051,6 +1136,30 @@ class CasinoGame(BaseGame):
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['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 += "💡 可以继续要牌或停牌"
@@ -1088,11 +1197,37 @@ class CasinoGame(BaseGame):
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['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"
text += "---\n\n"
text += "💡 已停牌,等待其他玩家操作或庄家结算"
# 如果所有玩家都已完成,自动结算
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
@@ -1118,13 +1253,20 @@ class CasinoGame(BaseGame):
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_points = self._calculate_points(banker_hand['cards'])
text += f"**庄家手牌**{self._format_cards(banker_hand['cards'])} ({banker_points}点)"
if banker_hand['status'] == 'blackjack':
text += " **黑杰克!**"
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"
@@ -1293,28 +1435,39 @@ class CasinoGame(BaseGame):
"""获取21点游戏帮助信息"""
return """## 🎰 21点游戏帮助
### 游戏流程
1. **庄家开启**`.赌场 21点 open <底注> <黑杰克倍数>`
- 示例:`.赌场 21点 open 50 1.5`
2. **玩家加入**`.赌场 21点 join`(需要至少底注的积分)
3. **庄家发牌**`.赌场 21点 deal`
4. **玩家操作**:要牌、停牌或加注
5. **自动结算**:所有玩家停牌后自动结算
### 庄家命令
- `.赌场 21点 open <最小> <最大> [黑杰克倍数]` - 开启游戏
- 示例:`.赌场 21点 open 10 100 1.5`
- `.赌场 21点 deal` - 发牌(所有玩家下注后)
- `.赌场 21点 settle` - 结算游戏自动要牌到17点以上后结算)
- `.赌场 21点 open <底注> <黑杰克倍数>` - 开启游戏
- 示例:`.赌场 21点 open 50 1.5`
- `.赌场 21点 deal` - 发牌(玩家加入后)
- `.赌场 21点 settle` - 手动结算(可选,会自动结算)
- `.赌场 21点 cancel` - 放弃游戏(返还所有下注)
### 玩家命令
- `.赌场 21点 bet <金额>` - 下注
- `.赌场 21点 join` - 加入游戏(扣除底注,需要至少底注的积分)
- `.赌场 21点 bet <金额>` - 加注(游戏中,不低于底注)
- 示例:`.赌场 21点 bet 50`
- `.赌场 21点 hit` - 要牌
- `.赌场 21点 stand` - 停牌
- `.赌场 21点 stand` - 停牌(所有玩家停牌后自动结算)
### 通用命令
- `.赌场 21点 status` - 查看当前状态
### 游戏规则
- 目标手牌点数尽可能接近21点但不能超过
- 黑杰克A+10/J/Q/K赢得1.5倍(默认)
- 玩家点数>庄家点数且未爆牌赢得1:1
- 平局:返还下注
- 爆牌:失去下注
- 庄家自动要牌到17点以上
- 系统抽水5%"""
- **目标**手牌点数尽可能接近21点但不能超过
- **发牌**:标准发牌顺序,庄家隐藏一张暗牌
- **黑杰克**A+10/J/Q/K赢得设定倍数默认1.5倍)
- **玩家点数>庄家点数且未爆牌**赢得1:1
- **平局**:返还下注
- **爆牌**:失去下注
- **庄家规则**自动要牌到17点以上
- **自动结算**:所有玩家停牌后,最后一名玩家停牌时立即结算
- **系统抽水**5%"""