mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 06:12:53 +08:00
224 lines
8.2 KiB
Python
224 lines
8.2 KiB
Python
import random
|
||
|
||
import ujson as json
|
||
from lxml import etree
|
||
from PIL import ImageDraw
|
||
|
||
from zhenxun.services.log import logger
|
||
from zhenxun.utils.image_utils import BuildImage
|
||
|
||
from ..config import draw_config
|
||
from ..util import cn2py, load_font, remove_prohibited_str
|
||
from .base_handle import BaseData, BaseHandle
|
||
|
||
|
||
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
|
||
|
||
async 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)
|
||
await bg.paste(img, (sep_w, sep_t))
|
||
# 加名字
|
||
text = card.name[:6] + "..." if len(card.name) > 7 else card.name
|
||
font = load_font(fontsize=16)
|
||
text_w, text_h = BuildImage.get_text_size(text, font)
|
||
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):
|
||
# TODO: fgo获取链接失效
|
||
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["名称"])
|