mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 14:22:55 +08:00
222 lines
8.3 KiB
Python
222 lines
8.3 KiB
Python
|
|
import random
|
|||
|
|
from lxml import etree
|
|||
|
|
from typing import List, Tuple
|
|||
|
|
from PIL import ImageDraw
|
|||
|
|
from nonebot.log import logger
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
import ujson as json
|
|||
|
|
except ModuleNotFoundError:
|
|||
|
|
import json
|
|||
|
|
|
|||
|
|
from .base_handle import BaseHandle, BaseData
|
|||
|
|
from ..config import draw_config
|
|||
|
|
from ..util import remove_prohibited_str, cn2py, load_font
|
|||
|
|
from utils.image_utils import BuildImage
|
|||
|
|
|
|||
|
|
|
|||
|
|
class FgoData(BaseData):
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
class FgoChar(FgoData):
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
class FgoCard(FgoData):
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
class FgoHandle(BaseHandle[FgoData]):
|
|||
|
|
def __init__(self):
|
|||
|
|
super().__init__("fgo", "命运-冠位指定")
|
|||
|
|
self.data_files.append("fgo_card.json")
|
|||
|
|
self.max_star = 5
|
|||
|
|
self.config = draw_config.fgo
|
|||
|
|
self.ALL_CHAR: List[FgoChar] = []
|
|||
|
|
self.ALL_CARD: List[FgoCard] = []
|
|||
|
|
|
|||
|
|
def get_card(self, mode: int = 1) -> FgoData:
|
|||
|
|
if mode == 1:
|
|||
|
|
star = self.get_star(
|
|||
|
|
[8, 7, 6, 5, 4, 3],
|
|||
|
|
[
|
|||
|
|
self.config.FGO_SERVANT_FIVE_P,
|
|||
|
|
self.config.FGO_SERVANT_FOUR_P,
|
|||
|
|
self.config.FGO_SERVANT_THREE_P,
|
|||
|
|
self.config.FGO_CARD_FIVE_P,
|
|||
|
|
self.config.FGO_CARD_FOUR_P,
|
|||
|
|
self.config.FGO_CARD_THREE_P,
|
|||
|
|
],
|
|||
|
|
)
|
|||
|
|
elif mode == 2:
|
|||
|
|
star = self.get_star(
|
|||
|
|
[5, 4], [self.config.FGO_CARD_FIVE_P, self.config.FGO_CARD_FOUR_P]
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
star = self.get_star(
|
|||
|
|
[8, 7, 6],
|
|||
|
|
[
|
|||
|
|
self.config.FGO_SERVANT_FIVE_P,
|
|||
|
|
self.config.FGO_SERVANT_FOUR_P,
|
|||
|
|
self.config.FGO_SERVANT_THREE_P,
|
|||
|
|
],
|
|||
|
|
)
|
|||
|
|
if star > 5:
|
|||
|
|
star -= 3
|
|||
|
|
chars = [x for x in self.ALL_CHAR if x.star == star and not x.limited]
|
|||
|
|
else:
|
|||
|
|
chars = [x for x in self.ALL_CARD if x.star == star and not x.limited]
|
|||
|
|
return random.choice(chars)
|
|||
|
|
|
|||
|
|
def get_cards(self, count: int, **kwargs) -> List[Tuple[FgoData, int]]:
|
|||
|
|
card_list = [] # 获取所有角色
|
|||
|
|
servant_count = 0 # 保底计算
|
|||
|
|
card_count = 0 # 保底计算
|
|||
|
|
for i in range(count):
|
|||
|
|
servant_count += 1
|
|||
|
|
card_count += 1
|
|||
|
|
if card_count == 9: # 四星卡片保底
|
|||
|
|
mode = 2
|
|||
|
|
elif servant_count == 10: # 三星从者保底
|
|||
|
|
mode = 3
|
|||
|
|
else: # 普通抽
|
|||
|
|
mode = 1
|
|||
|
|
card = self.get_card(mode)
|
|||
|
|
if isinstance(card, FgoCard) and card.star > self.max_star - 2:
|
|||
|
|
card_count = 0
|
|||
|
|
if isinstance(card, FgoChar):
|
|||
|
|
servant_count = 0
|
|||
|
|
card_list.append((card, i + 1))
|
|||
|
|
return card_list
|
|||
|
|
|
|||
|
|
def generate_card_img(self, card: FgoData) -> BuildImage:
|
|||
|
|
sep_w = 5
|
|||
|
|
sep_t = 5
|
|||
|
|
sep_b = 20
|
|||
|
|
w = 128
|
|||
|
|
h = 140
|
|||
|
|
bg = BuildImage(w + sep_w * 2, h + sep_t + sep_b)
|
|||
|
|
img_path = str(self.img_path / f"{cn2py(card.name)}.png")
|
|||
|
|
img = BuildImage(w, h, background=img_path)
|
|||
|
|
bg.paste(img, (sep_w, sep_t), alpha=True)
|
|||
|
|
# 加名字
|
|||
|
|
text = card.name[:6] + "..." if len(card.name) > 7 else card.name
|
|||
|
|
font = load_font(fontsize=16)
|
|||
|
|
text_w, text_h = font.getsize(text)
|
|||
|
|
draw = ImageDraw.Draw(bg.markImg)
|
|||
|
|
draw.text(
|
|||
|
|
(sep_w + (w - text_w) / 2, h + sep_t + (sep_b - text_h) / 2),
|
|||
|
|
text,
|
|||
|
|
font=font,
|
|||
|
|
fill="gray",
|
|||
|
|
)
|
|||
|
|
return bg
|
|||
|
|
|
|||
|
|
def _init_data(self):
|
|||
|
|
self.ALL_CHAR = [
|
|||
|
|
FgoChar(
|
|||
|
|
name=value["名称"],
|
|||
|
|
star=int(value["星级"]),
|
|||
|
|
limited=True
|
|||
|
|
if not ("圣晶石召唤" in value["入手方式"] or "圣晶石召唤(Story卡池)" in value["入手方式"])
|
|||
|
|
else False,
|
|||
|
|
)
|
|||
|
|
for value in self.load_data().values()
|
|||
|
|
]
|
|||
|
|
self.ALL_CARD = [
|
|||
|
|
FgoCard(name=value["名称"], star=int(value["星级"]), limited=False)
|
|||
|
|
for value in self.load_data("fgo_card.json").values()
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
async def _update_info(self):
|
|||
|
|
# fgo.json
|
|||
|
|
fgo_info = {}
|
|||
|
|
for i in range(500):
|
|||
|
|
url = f"http://fgo.vgtime.com/servant/ajax?card=&wd=&ids=&sort=12777&o=desc&pn={i}"
|
|||
|
|
result = await self.get_url(url)
|
|||
|
|
if not result:
|
|||
|
|
logger.warning(f"更新 {self.game_name_cn} page {i} 出错")
|
|||
|
|
continue
|
|||
|
|
fgo_data = json.loads(result)
|
|||
|
|
if int(fgo_data["nums"]) <= 0:
|
|||
|
|
break
|
|||
|
|
for x in fgo_data["data"]:
|
|||
|
|
name = remove_prohibited_str(x["name"])
|
|||
|
|
member_dict = {
|
|||
|
|
"id": x["id"],
|
|||
|
|
"card_id": x["charid"],
|
|||
|
|
"头像": x["icon"],
|
|||
|
|
"名称": remove_prohibited_str(x["name"]),
|
|||
|
|
"职阶": x["classes"],
|
|||
|
|
"星级": int(x["star"]),
|
|||
|
|
"hp": x["lvmax4hp"],
|
|||
|
|
"atk": x["lvmax4atk"],
|
|||
|
|
"card_quick": x["cardquick"],
|
|||
|
|
"card_arts": x["cardarts"],
|
|||
|
|
"card_buster": x["cardbuster"],
|
|||
|
|
"宝具": x["tprop"],
|
|||
|
|
}
|
|||
|
|
fgo_info[name] = member_dict
|
|||
|
|
# 更新额外信息
|
|||
|
|
for key in fgo_info.keys():
|
|||
|
|
url = f'http://fgo.vgtime.com/servant/{fgo_info[key]["id"]}'
|
|||
|
|
result = await self.get_url(url)
|
|||
|
|
if not result:
|
|||
|
|
fgo_info[key]["入手方式"] = ["圣晶石召唤"]
|
|||
|
|
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
dom = etree.HTML(result, etree.HTMLParser())
|
|||
|
|
obtain = dom.xpath(
|
|||
|
|
"//table[contains(string(.),'入手方式')]/tr[8]/td[3]/text()"
|
|||
|
|
)[0]
|
|||
|
|
obtain = str(obtain).strip()
|
|||
|
|
if "限时活动免费获取 活动结束后无法获得" in obtain:
|
|||
|
|
obtain = ["活动获取"]
|
|||
|
|
elif "非限时UP无法获得" in obtain:
|
|||
|
|
obtain = ["限时召唤"]
|
|||
|
|
else:
|
|||
|
|
if "&" in obtain:
|
|||
|
|
obtain = obtain.split("&")
|
|||
|
|
else:
|
|||
|
|
obtain = obtain.split(" ")
|
|||
|
|
obtain = [s.strip() for s in obtain if s.strip()]
|
|||
|
|
fgo_info[key]["入手方式"] = obtain
|
|||
|
|
except IndexError:
|
|||
|
|
fgo_info[key]["入手方式"] = ["圣晶石召唤"]
|
|||
|
|
logger.warning(f"{self.game_name_cn} 获取额外信息错误 {key}")
|
|||
|
|
self.dump_data(fgo_info)
|
|||
|
|
logger.info(f"{self.game_name_cn} 更新成功")
|
|||
|
|
# fgo_card.json
|
|||
|
|
fgo_card_info = {}
|
|||
|
|
for i in range(500):
|
|||
|
|
url = f"http://fgo.vgtime.com/equipment/ajax?wd=&ids=&sort=12958&o=desc&pn={i}"
|
|||
|
|
result = await self.get_url(url)
|
|||
|
|
if not result:
|
|||
|
|
logger.warning(f"更新 {self.game_name_cn}卡牌 page {i} 出错")
|
|||
|
|
continue
|
|||
|
|
fgo_data = json.loads(result)
|
|||
|
|
if int(fgo_data["nums"]) <= 0:
|
|||
|
|
break
|
|||
|
|
for x in fgo_data["data"]:
|
|||
|
|
name = remove_prohibited_str(x["name"])
|
|||
|
|
member_dict = {
|
|||
|
|
"id": x["id"],
|
|||
|
|
"card_id": x["equipid"],
|
|||
|
|
"头像": x["icon"],
|
|||
|
|
"名称": name,
|
|||
|
|
"星级": int(x["star"]),
|
|||
|
|
"hp": x["lvmax_hp"],
|
|||
|
|
"atk": x["lvmax_atk"],
|
|||
|
|
"skill_e": str(x["skill_e"]).split("<br />")[:-1],
|
|||
|
|
}
|
|||
|
|
fgo_card_info[name] = member_dict
|
|||
|
|
self.dump_data(fgo_card_info, "fgo_card.json")
|
|||
|
|
logger.info(f"{self.game_name_cn} 卡牌更新成功")
|
|||
|
|
# 下载头像
|
|||
|
|
for value in fgo_info.values():
|
|||
|
|
await self.download_img(value["头像"], value["名称"])
|
|||
|
|
for value in fgo_card_info.values():
|
|||
|
|
await self.download_img(value["头像"], value["名称"])
|