175 lines
6.6 KiB
Python
175 lines
6.6 KiB
Python
"""
|
||
阴阳师抽卡插件 - 抽卡核心逻辑模块
|
||
|
||
实现抽卡核心算法,包括:
|
||
- 多稀有度抽卡(R/SR/SSR/SP)
|
||
- 子池支持
|
||
- 保底机制
|
||
- 成就检查
|
||
"""
|
||
|
||
import random
|
||
from typing import Dict, Tuple, List, Optional, Any
|
||
import os
|
||
from pathlib import Path
|
||
|
||
from .config import Config
|
||
from .data_manager import DataManager
|
||
|
||
config = Config()
|
||
data_manager = DataManager()
|
||
|
||
class GachaSystem:
|
||
"""抽卡系统核心类,管理抽卡逻辑和数据"""
|
||
def __init__(self):
|
||
self.data_manager = data_manager
|
||
|
||
async def draw(self, user_id: str) -> Dict[str, Any]:
|
||
"""执行一次抽卡"""
|
||
# 检查抽卡限制
|
||
if not await self.data_manager.check_daily_limit(user_id):
|
||
draws_left = await self.data_manager.get_draws_left(user_id)
|
||
return {
|
||
"success": False,
|
||
"message": f"您今日的抽卡次数已用完,每日限制{config.DAILY_LIMIT}次,明天再来吧!"
|
||
}
|
||
|
||
# 抽取稀有度(传递用户ID)
|
||
rarity = self._draw_rarity(user_id)
|
||
|
||
# 从该稀有度中抽取式神
|
||
await self.data_manager.ensure_shikigami_data()
|
||
shikigami_data = self.data_manager.shikigami_data.get(rarity, [])
|
||
if not shikigami_data:
|
||
return {
|
||
"success": False,
|
||
"message": f"系统错误:{rarity}稀有度下没有可用式神"
|
||
}
|
||
|
||
# 随机选择式神
|
||
shikigami = random.choice(shikigami_data)
|
||
|
||
# xapi 只负责写入抽卡数据;奖励副作用仍由 nonebot handler 编排。
|
||
record_result = await self.data_manager.record_draw_result(user_id, rarity, shikigami)
|
||
if not record_result.get("success"):
|
||
return {
|
||
"success": False,
|
||
"message": record_result.get("message", "抽卡记录写入失败")
|
||
}
|
||
|
||
return {
|
||
"success": True,
|
||
"rarity": record_result.get("rarity", rarity),
|
||
"name": record_result.get("name", shikigami["name"]),
|
||
"image_url": record_result.get("image_url") or record_result.get("image_path") or shikigami["image_url"],
|
||
"draws_left": record_result.get("draws_left", 0),
|
||
"unlocked_achievements": record_result.get("unlocked_achievements", [])
|
||
}
|
||
|
||
def _draw_rarity(self, user_id: str = None) -> str:
|
||
"""按概率抽取稀有度"""
|
||
# 检查是否是特殊概率用户
|
||
if user_id and user_id in config.SPECIAL_PROBABILITY_USERS:
|
||
# 100%概率抽到SSR或SP,随机选择
|
||
return random.choice(["SSR", "SP"])
|
||
|
||
# 普通用户的概率逻辑
|
||
r = random.random() * 100 # 0-100的随机数
|
||
|
||
cumulative = 0
|
||
for rarity, prob in config.RARITY_PROBABILITY.items():
|
||
cumulative += prob
|
||
if r < cumulative:
|
||
return rarity
|
||
|
||
# 默认返回R,理论上不会执行到这里
|
||
return "R"
|
||
|
||
async def get_user_stats(self, user_id: str) -> Dict:
|
||
"""获取用户抽卡统计"""
|
||
return await self.data_manager.get_user_stats(user_id)
|
||
|
||
def get_probability_text(self) -> str:
|
||
"""获取概率展示文本"""
|
||
probs = config.RARITY_PROBABILITY
|
||
return f"--- 系统概率 ---\nR: {probs['R']}% | SR: {probs['SR']}% | SSR: {probs['SSR']}% | SP: {probs['SP']}%"
|
||
|
||
async def get_rank_list(self) -> List[Tuple[str, Dict[str, int]]]:
|
||
"""获取抽卡排行榜数据"""
|
||
items = await self.data_manager.get_rank(limit=10)
|
||
return [(item["user_id"], item) for item in items]
|
||
|
||
async def get_daily_stats(self) -> Dict:
|
||
"""获取今日抽卡统计"""
|
||
return await self.data_manager.get_daily_stats()
|
||
|
||
async def triple_draw(self, user_id: str) -> Dict:
|
||
"""执行三连抽"""
|
||
# 检查是否有足够的抽卡次数
|
||
draws_left = await self.data_manager.get_draws_left(user_id)
|
||
if draws_left < 3:
|
||
return {
|
||
"success": False,
|
||
"message": f"抽卡次数不足,您今日还剩{draws_left}次抽卡机会,三连抽需要3次机会"
|
||
}
|
||
|
||
results = []
|
||
await self.data_manager.ensure_shikigami_data()
|
||
|
||
# 执行三次本地概率抽取,统一提交 xapi 三连写入端点。
|
||
for i in range(3):
|
||
# 抽取稀有度(传递用户ID)
|
||
rarity = self._draw_rarity(user_id)
|
||
|
||
# 从该稀有度中抽取式神
|
||
shikigami_data = self.data_manager.shikigami_data.get(rarity, [])
|
||
if not shikigami_data:
|
||
return {
|
||
"success": False,
|
||
"message": f"系统错误:{rarity}稀有度下没有可用式神"
|
||
}
|
||
|
||
# 随机选择式神
|
||
shikigami = random.choice(shikigami_data)
|
||
|
||
results.append({
|
||
"id": shikigami["id"],
|
||
"rarity": rarity,
|
||
"name": shikigami["name"],
|
||
"image_url": shikigami["image_url"]
|
||
})
|
||
|
||
record_result = await self.data_manager.record_triple_draw_result(user_id, results)
|
||
if not record_result.get("success"):
|
||
return {
|
||
"success": False,
|
||
"message": record_result.get("message", "三连抽记录写入失败")
|
||
}
|
||
|
||
return {
|
||
"success": True,
|
||
"results": record_result.get("results", results),
|
||
"draws_left": record_result.get("draws_left", 0),
|
||
"unlocked_achievements": record_result.get("unlocked_achievements", [])
|
||
}
|
||
|
||
async def get_user_achievements(self, user_id: str) -> Dict:
|
||
"""获取用户成就信息"""
|
||
achievement_data = await self.data_manager.get_user_achievements(user_id)
|
||
|
||
if not achievement_data["unlocked"] and all(v == 0 for v in achievement_data["progress"].values()):
|
||
return {
|
||
"success": False,
|
||
"message": "您还没有任何成就进度哦!快去抽卡吧!"
|
||
}
|
||
|
||
return {
|
||
"success": True,
|
||
"achievements": achievement_data["unlocked"],
|
||
"progress": achievement_data["progress"]
|
||
}
|
||
|
||
async def get_daily_detailed_records(self, date: Optional[str] = None) -> Dict:
|
||
"""获取每日详细抽卡记录"""
|
||
return await self.data_manager.get_daily_records(date)
|