Files
WPSBot/games/alchemy.py
2025-11-10 15:17:53 +08:00

207 lines
7.5 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 random
import time
import logging
from datetime import datetime
from games.base import BaseGame
from utils.parser import CommandParser
from core.database import get_db
from typing import *
logger = logging.getLogger(__name__)
class AlchemyGame(BaseGame):
"""炼金系统游戏"""
def __init__(self):
"""初始化游戏"""
super().__init__()
self.db = get_db()
# 奖品池配置 - 确保数学期望等于消耗积分
self.prize_pool: List[Tuple[int, str, float, str]] = [
# (权重, 类型, 倍率, 描述)
(500, "penalty", 0, "炼金失败"),
(160, "penalty", -1, "炼金爆炸"),
(110, "points", 0.1, "少量积分"),
(390, "points", 0.5, "少量积分"),
(500, "points", 1, "等值积分"),
(390, "points", 2, "丰厚积分"),
(136, "points", 5, "丰厚积分"),
(9, "points", 10, "🌟 巨额积分"),
(1, "points", 100, "💎 传说积分"),
]
self.total_weight: int = 0
for weight,_,_,_ in self.prize_pool:
self.total_weight += weight
async def handle(self, command: str, chat_id: int, user_id: int) -> str:
"""处理炼金相关指令
Args:
command: 指令,如 ".alchemy", ".alchemy 10", ".alchemy stats"
chat_id: 会话ID
user_id: 用户ID
Returns:
回复消息
"""
try:
# 提取参数
_, args = CommandParser.extract_command_args(command)
args = args.strip().lower()
# 炼金说明
if args in ['help', '帮助', 'info']:
return self._get_alchemy_help()
# 默认:炼金抽奖
else:
# 解析消耗积分数量
cost_points = 10 # 默认消耗10积分
if args.isdigit():
cost_points = int(args)
return self._perform_alchemy(user_id, cost_points)
except Exception as e:
logger.error(f"处理炼金指令错误: {e}", exc_info=True)
return f"❌ 处理指令出错: {str(e)}"
def _perform_alchemy(self, user_id: int, cost_points: int) -> str:
"""执行炼金抽奖
Args:
user_id: 用户ID
cost_points: 消耗积分
Returns:
抽奖结果消息
"""
# 检查用户是否正在冒险中
state = self.db.get_game_state(0, user_id, 'adventure')
if state:
try:
state_data = state['state_data']
start_time = state_data.get('start_time', 0)
cost_time = state_data.get('cost_time', 1)
current_time = int(time.time())
end_time = start_time + cost_time * 60
remaining_seconds = end_time - current_time
# 如果冒险已完成,提示用户先回收奖励,不允许炼金
if remaining_seconds <= 0:
return f"❌ 你有待回收的冒险奖励!\n\n💡 请先使用 `.adventure` 回收冒险奖励后再进行炼金。"
else:
# 冒险未完成,返回错误提示
remaining_minutes = remaining_seconds // 60
remaining_secs = remaining_seconds % 60
if remaining_minutes > 0:
wait_msg = f"{remaining_minutes}{remaining_secs}"
else:
wait_msg = f"{remaining_secs}"
return f"❌ 冒险进行中,无法进行炼金!\n\n还需等待 **{wait_msg}** 才能完成冒险。\n\n💡 提示:冒险期间无法进行炼金,请先完成冒险!"
except Exception as e:
# 状态数据异常,删除损坏状态,允许继续
logger.error(f"冒险状态数据异常: {e}", exc_info=True)
self.db.delete_game_state(0, user_id, 'adventure')
# 检查用户积分是否足够
user_points = self.db.get_user_points(user_id)
if user_points['points'] < cost_points:
return f"❌ 积分不足!需要 {cost_points} 积分,当前可用 {user_points['points']} 积分"
# 选择奖品池
prize_pool = self.prize_pool
# 执行抽奖
reward = self._draw_prize(prize_pool)
reward_points = int(reward['value']*cost_points)
# 消费积分
if not self.db.consume_points(user_id, cost_points, "alchemy", f"炼金抽奖消耗"):
return "❌ 积分消费失败,请稍后重试"
# 处理奖励
if reward['type'] == 'points' and reward['value'] > 0:
# 获得积分奖励
self.db.add_points(user_id, reward_points, "alchemy", f"炼金奖励")
elif reward['type'] == 'penalty' and reward['value'] < 0:
# 负面奖励(扣分)
penalty_points = abs(reward_points)
self.db.consume_points(user_id, penalty_points, "alchemy", f"炼金失败")
# 炼金系统已简化,不再记录历史
# 获取更新后的积分信息
updated_points = self.db.get_user_points(user_id)
# 格式化输出
text = f"## ⚗️ 炼金结果\n\n"
text += f"**消耗积分**{cost_points}\n\n"
if reward['type'] == 'points':
text += f"**{reward['description']}**: 获得{reward_points} 积分\n\n"
elif reward['type'] == 'penalty':
text += f"**{reward['description']}**: 损失 {abs(reward_points)} 积分\n\n"
text += f"**当前积分**{updated_points['points']}\n\n"
text += "---\n\n"
text += "💡 提示:炼金有风险,投资需谨慎!"
return text
def _draw_prize(self, prize_pool: list) -> dict:
"""从奖品池中抽取奖品
Args:
prize_pool: 奖品池
Returns:
奖品信息
"""
# 生成随机数
rand = random.random()*self.total_weight
cumulative_prob = 0.0
for weight, reward_type, reward_value, description in prize_pool:
cumulative_prob += weight
if rand <= cumulative_prob:
return {
'type': reward_type,
'value': reward_value,
'description': description
}
# 兜底返回第一个奖品
return {
'type': prize_pool[0][1],
'value': prize_pool[0][2],
'description': prize_pool[0][3]
}
def _get_alchemy_help(self) -> str:
"""获取炼金帮助信息
Returns:
帮助信息消息
"""
text = f"## ⚗️ 炼金系统\n\n"
text += f"### 基础用法\n"
text += f"- `.alchemy` - 消耗10积分进行炼金\n"
text += f"- `.alchemy cost` - 消耗cost积分进行炼金, 最少1积分\n"
text += f"### 其他功能\n"
text += f"- `.alchemy help` - 查看帮助\n\n"
return text
def get_help(self) -> str:
"""获取帮助信息"""
return self._get_alchemy_help()