Files
DanDingNoneBot/danding_bot/plugins/onmyoji_gacha/gacha.py

175 lines
6.6 KiB
Python
Raw 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.

"""
阴阳师抽卡插件 - 抽卡核心逻辑模块
实现抽卡核心算法,包括:
- 多稀有度抽卡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)