2025-10-28 13:00:35 +08:00
|
|
|
|
"""运势占卜游戏"""
|
|
|
|
|
|
import json
|
|
|
|
|
|
import random
|
|
|
|
|
|
import logging
|
|
|
|
|
|
import hashlib
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
from games.base import BaseGame
|
|
|
|
|
|
from utils.parser import CommandParser
|
2025-10-29 11:32:43 +08:00
|
|
|
|
from games.points import PointsGame
|
2025-10-28 13:00:35 +08:00
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FortuneGame(BaseGame):
|
|
|
|
|
|
"""运势占卜游戏"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
"""初始化游戏"""
|
|
|
|
|
|
super().__init__()
|
|
|
|
|
|
self._fortunes = None
|
|
|
|
|
|
self._tarot = None
|
2025-10-29 11:32:43 +08:00
|
|
|
|
self.points_game = PointsGame()
|
2025-10-28 13:00:35 +08:00
|
|
|
|
|
|
|
|
|
|
def _load_data(self):
|
|
|
|
|
|
"""懒加载运势数据"""
|
|
|
|
|
|
if self._fortunes is None:
|
|
|
|
|
|
try:
|
|
|
|
|
|
data_file = Path(__file__).parent.parent / "data" / "fortunes.json"
|
|
|
|
|
|
with open(data_file, 'r', encoding='utf-8') as f:
|
|
|
|
|
|
data = json.load(f)
|
|
|
|
|
|
self._fortunes = data.get('fortunes', [])
|
|
|
|
|
|
self._tarot = data.get('tarot', [])
|
|
|
|
|
|
logger.info("运势数据加载完成")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"加载运势数据失败: {e}")
|
|
|
|
|
|
self._fortunes = []
|
|
|
|
|
|
self._tarot = []
|
|
|
|
|
|
|
|
|
|
|
|
async def handle(self, command: str, chat_id: int, user_id: int) -> str:
|
|
|
|
|
|
"""处理运势占卜指令
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
command: 指令,如 ".fortune" 或 ".fortune tarot"
|
|
|
|
|
|
chat_id: 会话ID
|
|
|
|
|
|
user_id: 用户ID
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
回复消息
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 加载数据
|
|
|
|
|
|
self._load_data()
|
|
|
|
|
|
|
|
|
|
|
|
# 提取参数
|
|
|
|
|
|
_, args = CommandParser.extract_command_args(command)
|
|
|
|
|
|
args = args.strip().lower()
|
|
|
|
|
|
|
|
|
|
|
|
# 塔罗牌
|
|
|
|
|
|
if args in ['tarot', '塔罗', '塔罗牌']:
|
|
|
|
|
|
return self._get_tarot(user_id)
|
|
|
|
|
|
|
|
|
|
|
|
# 默认:今日运势
|
|
|
|
|
|
return self._get_daily_fortune(user_id)
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"处理运势占卜指令错误: {e}", exc_info=True)
|
|
|
|
|
|
return f"❌ 处理指令出错: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
def _get_daily_fortune(self, user_id: int) -> str:
|
|
|
|
|
|
"""获取今日运势
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
user_id: 用户ID
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
运势信息
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not self._fortunes:
|
|
|
|
|
|
return "❌ 运势数据加载失败"
|
|
|
|
|
|
|
|
|
|
|
|
# 基于日期和用户ID生成seed
|
|
|
|
|
|
# 同一用户同一天结果相同
|
|
|
|
|
|
today = datetime.now().strftime('%Y-%m-%d')
|
|
|
|
|
|
seed_str = f"{user_id}_{today}"
|
|
|
|
|
|
seed = int(hashlib.md5(seed_str.encode()).hexdigest(), 16) % (10 ** 8)
|
|
|
|
|
|
|
|
|
|
|
|
# 使用seed选择运势
|
|
|
|
|
|
random.seed(seed)
|
|
|
|
|
|
fortune = random.choice(self._fortunes)
|
|
|
|
|
|
|
|
|
|
|
|
# 生成幸运数字和幸运颜色(同样基于seed)
|
|
|
|
|
|
lucky_number = random.randint(1, 99)
|
|
|
|
|
|
lucky_colors = ["红色", "蓝色", "绿色", "黄色", "紫色", "粉色", "橙色"]
|
|
|
|
|
|
lucky_color = random.choice(lucky_colors)
|
|
|
|
|
|
|
|
|
|
|
|
# 重置随机seed
|
|
|
|
|
|
random.seed()
|
|
|
|
|
|
|
2025-10-29 11:32:43 +08:00
|
|
|
|
# 尝试获得积分奖励(30%概率)
|
|
|
|
|
|
points_earned = 0
|
|
|
|
|
|
if random.random() < 0.3: # 30%概率获得积分
|
|
|
|
|
|
points_earned = self.points_game.add_fortune_points(user_id)
|
|
|
|
|
|
|
2025-10-28 13:00:35 +08:00
|
|
|
|
# 格式化输出
|
|
|
|
|
|
text = f"## 🔮 今日运势\n\n"
|
|
|
|
|
|
text += f"**日期**:{today}\n\n"
|
|
|
|
|
|
text += f"**运势**:{fortune['emoji']} <font color='{fortune['color']}'>{fortune['level']}</font>\n\n"
|
|
|
|
|
|
text += f"**运势解读**:{fortune['description']}\n\n"
|
|
|
|
|
|
text += f"**建议**:{fortune['advice']}\n\n"
|
|
|
|
|
|
text += f"**幸运数字**:{lucky_number}\n\n"
|
|
|
|
|
|
text += f"**幸运颜色**:{lucky_color}\n\n"
|
2025-10-29 11:32:43 +08:00
|
|
|
|
|
|
|
|
|
|
# 添加积分奖励信息
|
|
|
|
|
|
if points_earned > 0:
|
|
|
|
|
|
text += f"**🎁 积分奖励**:+{points_earned} 分\n\n"
|
|
|
|
|
|
|
2025-10-28 13:00:35 +08:00
|
|
|
|
text += "---\n\n"
|
2025-10-29 11:32:43 +08:00
|
|
|
|
text += "💡 提示:运势仅供娱乐参考,查看运势有机会获得积分奖励~"
|
2025-10-28 13:00:35 +08:00
|
|
|
|
|
|
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
|
|
def _get_tarot(self, user_id: int) -> str:
|
|
|
|
|
|
"""抽塔罗牌
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
user_id: 用户ID
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
塔罗牌信息
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not self._tarot:
|
|
|
|
|
|
return "❌ 塔罗牌数据加载失败"
|
|
|
|
|
|
|
|
|
|
|
|
# 基于时间和用户ID生成seed(分钟级别变化)
|
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
|
seed_str = f"{user_id}_{now.strftime('%Y-%m-%d-%H-%M')}"
|
|
|
|
|
|
seed = int(hashlib.md5(seed_str.encode()).hexdigest(), 16) % (10 ** 8)
|
|
|
|
|
|
|
|
|
|
|
|
# 使用seed选择塔罗牌
|
|
|
|
|
|
random.seed(seed)
|
|
|
|
|
|
card = random.choice(self._tarot)
|
|
|
|
|
|
|
|
|
|
|
|
# 重置随机seed
|
|
|
|
|
|
random.seed()
|
|
|
|
|
|
|
|
|
|
|
|
# 格式化输出
|
|
|
|
|
|
text = f"## 🃏 塔罗占卜\n\n"
|
|
|
|
|
|
text += f"**牌面**:{card['emoji']} {card['name']}\n\n"
|
|
|
|
|
|
text += f"**含义**:{card['meaning']}\n\n"
|
|
|
|
|
|
text += f"**建议**:{card['advice']}\n\n"
|
|
|
|
|
|
text += "---\n\n"
|
|
|
|
|
|
text += "💡 提示:塔罗牌指引方向,最终决定权在你手中~"
|
|
|
|
|
|
|
|
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
|
|
def get_help(self) -> str:
|
|
|
|
|
|
"""获取帮助信息"""
|
|
|
|
|
|
return """## 🔮 运势占卜
|
|
|
|
|
|
|
|
|
|
|
|
### 基础用法
|
|
|
|
|
|
- `.fortune` - 查看今日运势
|
|
|
|
|
|
- `.运势` - 查看今日运势
|
|
|
|
|
|
- `.fortune tarot` - 抽塔罗牌
|
|
|
|
|
|
|
|
|
|
|
|
### 说明
|
|
|
|
|
|
- 同一天查询,运势结果相同
|
|
|
|
|
|
- 塔罗牌每分钟变化一次
|
|
|
|
|
|
- 仅供娱乐参考
|
|
|
|
|
|
|
|
|
|
|
|
### 示例
|
|
|
|
|
|
```
|
|
|
|
|
|
.fortune
|
|
|
|
|
|
.运势
|
|
|
|
|
|
.fortune tarot
|
|
|
|
|
|
```
|
|
|
|
|
|
"""
|
|
|
|
|
|
|