GenshinUID/genshinuid_enka/draw_char_card.py
2022-09-04 01:39:35 +08:00

936 lines
28 KiB
Python

import json
import math
import asyncio
from io import BytesIO
from pathlib import Path
from typing import Tuple, Union, Optional
from httpx import get
from PIL import Image, ImageDraw, ImageChops
from ..utils.db_operation.db_operation import config_check
from ..utils.draw_image_tools.send_image_tool import convert_img
from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
from .dmgCalc.dmg_calc import (
DMG_PATH,
calc_prop,
draw_dmgCacl_img,
get_char_percent,
avatarName2SkillAdd,
)
R_PATH = Path(__file__).parent
RESOURCE_PATH = Path(__file__).parents[1] / 'resource'
TEXT_PATH = R_PATH / 'texture2D'
ICON_PATH = RESOURCE_PATH / 'icon'
GACHA_PATH = RESOURCE_PATH / 'gacha_img'
STAND_PATH = RESOURCE_PATH / 'char_stand'
PLAYER_PATH = Path(__file__).parents[1] / 'player'
RELIC_PATH = RESOURCE_PATH / 'reliquaries'
ETC_PATH = R_PATH / 'etc'
COLOR_MAP = {
'Anemo': (43, 170, 163),
'Cryo': (97, 168, 202),
'Dendro': (84, 169, 62),
'Electro': (150, 62, 169),
'Geo': (169, 143, 62),
'Hydro': (66, 98, 182),
'Pyro': (169, 62, 67),
}
SCORE_MAP = {
'暴击率': 2,
'暴击伤害': 1,
'元素精通': 0.25,
'元素充能效率': 0.65,
'百分比血量': 0.86,
'百分比攻击力': 1,
'百分比防御力': 0.7,
'血量': 0.014,
'攻击力': 0.12,
'防御力': 0.18,
}
VALUE_MAP = {
'攻击力': 4.975,
'血量': 4.975,
'防御力': 6.2,
'元素精通': 19.75,
'元素充能效率': 5.5,
'暴击率': 3.3,
'暴击伤害': 6.6,
}
# 引入ValueMap
with open(ETC_PATH / 'ValueAttrMap.json', 'r', encoding='UTF-8') as f:
ATTR_MAP = json.load(f)
# 引入offset
with open(ETC_PATH / 'avatarOffsetMap.json', 'r', encoding='UTF-8') as f:
avatarOffsetMap = json.load(f)
# 引入offset2
with open(ETC_PATH / 'avatarCardOffsetMap.json', 'r', encoding='UTF-8') as f:
avatarCardOffsetMap = json.load(f)
def get_star_png(star: int) -> Image.Image:
png = Image.open(TEXT_PATH / 's-{}.png'.format(str(star)))
return png
def strLenth(r: str, size: int, limit: int = 540) -> str:
result = ''
temp = 0
for i in r:
if temp >= limit:
result += '\n' + i
temp = 0
else:
result += i
if i.isdigit():
temp += round(size / 10 * 6)
elif i == '/':
temp += round(size / 10 * 2.2)
elif i == '.':
temp += round(size / 10 * 3)
elif i == '%':
temp += round(size / 10 * 9.4)
else:
temp += size
return result
async def get_artifacts_score(subName: str, subValue: int) -> int:
score = subValue * SCORE_MAP[subName]
return score
async def get_artifacts_value(
subName: str,
subValue: int,
baseAtk: int,
baseHp: int,
baseDef: int,
charName: str,
) -> float:
if charName not in ATTR_MAP:
ATTR_MAP[charName] = ['攻击力', '暴击率', '暴击伤害']
if subName in ATTR_MAP[charName] and subName in ['血量', '防御力', '攻击力']:
if subName == '血量':
base = (subValue / baseHp) * 100
elif subName == '防御力':
base = (subValue / baseDef) * 100
elif subName == '攻击力':
base = (subValue / baseAtk) * 100
else:
base = 1.0
value = float('{:.2f}'.format(base / VALUE_MAP[subName]))
elif subName in ['百分比血量', '百分比防御力', '百分比攻击力']:
subName = subName.replace('百分比', '')
if subName in ATTR_MAP[charName]:
value = float('{:.2f}'.format(subValue / VALUE_MAP[subName]))
else:
return 0
else:
if subName in ATTR_MAP[charName]:
value = float('{:.2f}'.format(subValue / VALUE_MAP[subName]))
else:
value = 0
if charName == '胡桃' and subName == '攻击力':
value = value * 0.4
return value
async def get_all_artifacts_value(
raw_data: dict, baseHp: int, baseAtk: int, baseDef: int, char_name: str
) -> int:
artifactsValue = 0
for aritifact in raw_data:
for i in aritifact['reliquarySubstats']:
subName = i['statName']
subValue = i['statValue']
value_temp = await get_artifacts_value(
subName, subValue, baseAtk, baseHp, baseDef, char_name
)
artifactsValue += value_temp
return artifactsValue
async def draw_char_img(
raw_data: dict, charUrl: Optional[str] = None
) -> bytes:
char_name = raw_data['avatarName']
char_level = raw_data['avatarLevel']
char_fetter = raw_data['avatarFetter']
if await config_check('RandomPic') and charUrl is None:
if char_name == '旅行者':
char_name_url = ''
else:
char_name_url = char_name
charUrl = f'http://img.genshin.cherishmoon.fun/{char_name_url}'
based_w, based_h = 600, 1200
if charUrl:
offset_x, offset_y = 200, 0
char_img = Image.open(BytesIO(get(charUrl).content)).convert('RGBA')
else:
if char_name in avatarOffsetMap:
offset_x, offset_y = (
avatarOffsetMap[char_name][0],
avatarOffsetMap[char_name][1],
)
else:
offset_x, offset_y = 200, 0
if char_name == '旅行者':
char_img = (
Image.open(STAND_PATH / f'{raw_data["avatarId"]}.png')
.convert('RGBA')
.resize((1421, 800))
)
else:
char_img = Image.open(GACHA_PATH / f'{char_name}.png') # 角色图像
# 确定图片的长宽
w, h = char_img.size
if (w, h) != (based_w, based_h):
# offset_all = offset_x if offset_x >= offset_y else offset_y
based_new_w, based_new_h = based_w + offset_x, based_h + offset_y
based_scale = '%.3f' % (based_new_w / based_new_h)
scale_f = '%.3f' % (w / h)
new_w = math.ceil(based_new_h * float(scale_f))
new_h = math.ceil(based_new_w / float(scale_f))
if scale_f > based_scale:
bg_img2 = char_img.resize(
(new_w, based_new_h), Image.Resampling.LANCZOS # type: ignore
)
x1 = new_w / 2 - based_new_w / 2 + offset_x
y1 = 0 + offset_y / 2
x2 = new_w / 2 + based_new_w / 2
y2 = based_new_h - offset_y / 2
else:
bg_img2 = char_img.resize(
(based_new_w, new_h), Image.Resampling.LANCZOS # type: ignore
)
x1 = 0 + offset_x
y1 = new_h / 2 - based_new_h / 2 + offset_y / 2
x2 = based_new_w
y2 = new_h / 2 + based_new_h / 2 - offset_y / 2
char_img = bg_img2.crop((x1, y1, x2, y2)) # type: ignore
with open(DMG_PATH / 'char_action.json', "r", encoding='UTF-8') as f:
char_action = json.load(f)
# 拿到倍率表
power_list = char_action[char_name]
new_prop = await calc_prop(raw_data, power_list)
if char_name not in char_action:
dmg_img, dmg_len = Image.new('RGBA', (950, 1)), 0
else:
dmg_img, dmg_len = await draw_dmgCacl_img(
raw_data, power_list, new_prop
)
img_w, img_h = 950, 1850 + dmg_len * 40
overlay = Image.open(TEXT_PATH / 'overlay.png')
overlay_w, overlay_h = overlay.size
if overlay_h < img_h:
new_overlay_h = img_h
new_overlay_w = math.ceil(new_overlay_h * overlay_w / overlay_h)
overlay = overlay.resize(
(new_overlay_w, new_overlay_h), Image.Resampling.LANCZOS
)
overlay = overlay.crop((0, 0, img_w, img_h))
color_img = Image.new(
'RGBA', overlay.size, COLOR_MAP[raw_data['avatarElement']]
)
img = ImageChops.overlay(color_img, overlay)
char_info_1 = Image.open(TEXT_PATH / 'char_info_1.png')
char_info_mask = Image.open(TEXT_PATH / 'char_info_mask.png')
img_temp = Image.new('RGBA', (based_w, based_h), (0, 0, 0, 0))
img_temp.paste(char_img, (0, 0), char_info_mask)
img.paste(img_temp, (0, 0), img_temp)
img.paste(char_info_1, (0, 0), char_info_1)
img.paste(dmg_img, (0, 1850), dmg_img)
lock_img = Image.open(TEXT_PATH / 'icon_lock.png')
# 命座处理
holo_img = Image.open(TEXT_PATH / 'holo.png')
holo_color = Image.new(
'RGBA', holo_img.size, COLOR_MAP[raw_data['avatarElement']]
)
for talent_num in range(0, 6):
if talent_num + 1 <= len(raw_data['talentList']):
talent = raw_data['talentList'][talent_num]
talent_img = Image.open(
ICON_PATH / '{}.png'.format(talent['talentIcon'])
)
talent_img_new = talent_img.resize(
(50, 50), Image.Resampling.LANCZOS # type: ignore
).convert("RGBA")
img.paste(holo_color, (775, 300 + talent_num * 81), holo_img)
img.paste(
talent_img_new, (850, 375 + talent_num * 81), talent_img_new
)
else:
img.paste(lock_img, (850, 375 + talent_num * 81), lock_img)
# 天赋处理
skillList = raw_data['avatarSkill']
# a_skill_name = skillList[0]['skillName'].replace('普通攻击·', '')
a_skill_level = skillList[0]['skillLevel']
# e_skill_name = skillList[1]['skillName']
e_skill_level = skillList[1]['skillLevel']
# q_skill_name = skillList[-1]['skillName']
q_skill_level = skillList[-1]['skillLevel']
skill_add = avatarName2SkillAdd[char_name]
for skillAdd_index in range(0, 2):
if len(raw_data['talentList']) >= 3 + skillAdd_index * 2:
if skill_add[skillAdd_index] == 'E':
e_skill_level += 3
elif skill_add[skillAdd_index] == 'Q':
q_skill_level += 3
for skill_num, skill in enumerate(skillList[0:2] + [skillList[-1]]):
skill_img = Image.open(ICON_PATH / '{}.png'.format(skill['skillIcon']))
skill_img_new = skill_img.resize(
(50, 50), Image.Resampling.LANCZOS # type: ignore
).convert("RGBA")
img.paste(skill_img_new, (78, 756 + 101 * skill_num), skill_img_new)
# 武器部分
weapon_img = Image.open(TEXT_PATH / 'char_info_weapon.png')
weapon_star_img = get_star_png(raw_data['weaponInfo']['weaponStar'])
weaponName = raw_data['weaponInfo']['weaponName']
weaponAtk = raw_data['weaponInfo']['weaponStats'][0]['statValue']
weaponLevel = raw_data['weaponInfo']['weaponLevel']
weaponAffix = raw_data['weaponInfo']['weaponAffix']
weaponEffect = raw_data['weaponInfo']['weaponEffect']
weapon_type = raw_data['weaponInfo']['weaponType']
weapon_img.paste(weapon_star_img, (25, 235), weapon_star_img)
weapon_text = ImageDraw.Draw(weapon_img)
weapon_text.text(
(35, 80),
weaponName,
(255, 255, 255),
genshin_font_origin(50),
anchor='lm',
)
weapon_text.text(
(35, 120),
weapon_type,
(255, 255, 255),
genshin_font_origin(20),
anchor='lm',
)
weapon_text.text(
(35, 160),
'基础攻击力',
(255, 255, 255),
genshin_font_origin(32),
anchor='lm',
)
weapon_text.text(
(368, 160),
str(weaponAtk),
(255, 255, 255),
genshin_font_origin(32),
anchor='rm',
)
if len(raw_data['weaponInfo']['weaponStats']) == 2:
weapon_sub_info = raw_data['weaponInfo']['weaponStats'][1]['statName']
weapon_sub_value = raw_data['weaponInfo']['weaponStats'][1][
'statValue'
]
weapon_text.text(
(35, 211),
weapon_sub_info,
(255, 255, 255),
genshin_font_origin(32),
anchor='lm',
)
weapon_text.text(
(368, 211),
str(weapon_sub_value),
(255, 255, 255),
genshin_font_origin(32),
anchor='rm',
)
else:
weapon_text.text(
(35, 211),
'该武器无副词条',
(255, 255, 255),
genshin_font_origin(32),
anchor='lm',
)
weapon_text.text(
(73, 303),
f'Lv.{weaponLevel}',
(255, 255, 255),
genshin_font_origin(28),
anchor='mm',
)
weapon_text.text(
(130, 305),
f'精炼{str(weaponAffix)}',
(255, 239, 173),
genshin_font_origin(28),
anchor='lm',
)
weaponEffect = strLenth(weaponEffect, 25, 455)
weapon_text.text(
(25, 335), weaponEffect, (255, 255, 255), genshin_font_origin(25)
)
img.paste(weapon_img, (387, 590), weapon_img)
fight_prop = raw_data['avatarFightProp']
hp = fight_prop['hp']
baseHp = fight_prop['baseHp']
attack = fight_prop['atk']
baseAtk = fight_prop['baseAtk']
defense = fight_prop['def']
baseDef = fight_prop['baseDef']
em = fight_prop['elementalMastery']
critrate = fight_prop['critRate']
critdmg = fight_prop['critDmg']
ce = fight_prop['energyRecharge']
dmgBonus = (
fight_prop['dmgBonus']
if fight_prop['physicalDmgBonus'] <= fight_prop['dmgBonus']
else fight_prop['physicalDmgBonus']
)
hp_green = fight_prop['addHp']
attack_green = fight_prop['addAtk']
defense_green = fight_prop['addDef']
# 圣遗物部分
artifactsAllScore = 0
for aritifact in raw_data['equipList']:
artifacts_img = Image.open(TEXT_PATH / 'char_info_artifacts.png')
artifacts_piece_img = Image.open(
RELIC_PATH / '{}.png'.format(aritifact['aritifactName'])
)
artifacts_piece_new_img = artifacts_piece_img.resize(
(75, 75), Image.Resampling.LANCZOS # type: ignore
).convert("RGBA")
# artifacts_piece_new_img.putalpha(
# artifacts_piece_new_img.getchannel('A').point(
# lambda x: round(x * 0.5) if x > 0 else 0
# )
artifacts_img.paste(
artifacts_piece_new_img, (195, 35), artifacts_piece_new_img
)
aritifactStar_img = get_star_png(aritifact['aritifactStar'])
artifactsPos = aritifact['aritifactPieceName']
artifacts_img.paste(aritifactStar_img, (20, 165), aritifactStar_img)
artifacts_text = ImageDraw.Draw(artifacts_img)
artifacts_text.text(
(30, 66),
aritifact['aritifactName'][:4],
(255, 255, 255),
genshin_font_origin(34),
anchor='lm',
)
artifacts_text.text(
(30, 102),
artifactsPos,
(255, 255, 255),
genshin_font_origin(20),
anchor='lm',
)
mainValue = aritifact['reliquaryMainstat']['statValue']
mainName = aritifact['reliquaryMainstat']['statName']
mainLevel = aritifact['aritifactLevel']
if mainName in ['攻击力', '血量', '防御力', '元素精通']:
mainValueStr = str(mainValue)
else:
mainValueStr = str(mainValue) + '%'
mainNameNew = (
mainName.replace('百分比', '')
.replace('伤害加成', '伤加成')
.replace('元素', '')
.replace('', '')
)
artifacts_text.text(
(30, 141),
mainNameNew,
(255, 255, 255),
genshin_font_origin(28),
anchor='lm',
)
artifacts_text.text(
(263, 141),
mainValueStr,
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
artifacts_text.text(
(55, 219),
'+{}'.format(str(mainLevel)),
(255, 255, 255),
genshin_font_origin(24),
anchor='mm',
)
artifactsScore = 0
for index, i in enumerate(aritifact['reliquarySubstats']):
subName = i['statName']
subValue = i['statValue']
if subName in ['攻击力', '血量', '防御力', '元素精通']:
subValueStr = str(subValue)
else:
subValueStr = str(subValue) + '%'
# artifactsScore += await get_artifacts_score(subName, subValue)
value_temp = await get_artifacts_value(
subName, subValue, baseAtk, baseHp, baseDef, char_name
)
artifactsScore += value_temp
subNameStr = subName.replace('百分比', '').replace('元素', '')
if value_temp == 0:
artifacts_color = (160, 160, 160)
elif value_temp >= 4.5:
artifacts_color = (247, 50, 50)
else:
artifacts_color = (255, 255, 100)
artifacts_text.text(
(20, 256 + index * 33),
'·{}'.format(subNameStr),
artifacts_color,
genshin_font_origin(25),
anchor='lm',
)
artifacts_text.text(
(268, 256 + index * 33),
'{}'.format(subValueStr),
artifacts_color,
genshin_font_origin(25),
anchor='rm',
)
if artifactsScore >= 6:
artifactsScore_color = (247, 26, 26)
else:
artifactsScore_color = (255, 255, 255)
artifactsAllScore += artifactsScore
artifacts_text.text(
(268, 190),
'{:.2f}'.format(artifactsScore) + '',
artifactsScore_color,
genshin_font_origin(23),
anchor='rm',
)
if artifactsPos == '生之花':
img.paste(artifacts_img, (18, 1075), artifacts_img)
elif artifactsPos == '死之羽':
img.paste(artifacts_img, (318, 1075), artifacts_img)
elif artifactsPos == '时之沙':
img.paste(artifacts_img, (618, 1075), artifacts_img)
elif artifactsPos == '空之杯':
img.paste(artifacts_img, (18, 1447), artifacts_img)
elif artifactsPos == '理之冠':
img.paste(artifacts_img, (318, 1447), artifacts_img)
# 角色基本信息
img_text = ImageDraw.Draw(img)
img_text.text(
(411, 72),
char_name,
(255, 255, 255),
genshin_font_origin(55),
anchor='lm',
)
img_text.text(
(411, 122),
'等级{}'.format(char_level),
(255, 255, 255),
genshin_font_origin(40),
anchor='lm',
)
img_text.text(
(747, 126),
str(char_fetter),
(255, 255, 255),
genshin_font_origin(28),
anchor='lm',
)
# aeq
# img_text.text(
# (110, 771),
# a_skill_name,
# (255, 255, 255),
# genshin_font_origin(26),
# anchor='lm',
# )
img_text.text(
(103, 812),
f'{str(a_skill_level)}',
(255, 255, 255),
genshin_font_origin(30),
anchor='mm',
)
# img_text.text(
# (110, 872),
# e_skill_name,
# (255, 255, 255),
# genshin_font_origin(26),
# anchor='lm',
# )
img_text.text(
(103, 915),
f'{str(e_skill_level)}',
(255, 255, 255),
genshin_font_origin(30),
anchor='mm',
)
# img_text.text(
# (110, 973),
# q_skill_name,
# (255, 255, 255),
# genshin_font_origin(26),
# anchor='lm',
# )
img_text.text(
(103, 1016),
f'{str(q_skill_level)}',
(255, 255, 255),
genshin_font_origin(30),
anchor='mm',
)
# 属性
img_text.text(
(785, 174),
str(round(hp)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(785, 227),
str(round(attack)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(785, 280),
str(round(defense)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(785, 333),
str(round(em)),
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(785, 386),
f'{str(round(critrate * 100, 2))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(785, 439),
f'{str(round(critdmg * 100, 2))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(785, 492),
f'{str(round(ce * 100, 1))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(785, 545),
f'{str(round(dmgBonus * 100, 1))}%',
(255, 255, 255),
genshin_font_origin(28),
anchor='rm',
)
img_text.text(
(805, 174),
f'(+{str(round(hp_green))})',
(95, 251, 80),
genshin_font_origin(28),
anchor='lm',
)
img_text.text(
(805, 227),
f'(+{str(round(attack_green))})',
(95, 251, 80),
genshin_font_origin(28),
anchor='lm',
)
img_text.text(
(805, 280),
f'(+{str(round(defense_green))})',
(95, 251, 80),
genshin_font_origin(28),
anchor='lm',
)
uid = raw_data['playerUid']
data_time = raw_data['dataTime']
# uid
img_text.text(
(350, 1035),
f'UID{uid}',
(255, 255, 255),
genshin_font_origin(24),
anchor='rm',
)
# 数据最后更新时间
img_text.text(
(780, 600),
f'数据最后更新于{data_time}',
(255, 255, 255),
genshin_font_origin(22),
anchor='rm',
)
# 角色评分
img_text.text(
(768, 1557),
f'{round(artifactsAllScore, 1)}',
(255, 255, 255),
genshin_font_origin(50),
anchor='mm',
)
percent = await get_char_percent(raw_data, new_prop, char_name)
img_text.text(
(768, 1690),
f'{str(percent)+"%"}',
(255, 255, 255),
genshin_font_origin(50),
anchor='mm',
)
img = img.convert('RGB')
result_buffer = BytesIO()
img.save(result_buffer, format='JPEG', subsampling=0, quality=90)
res = result_buffer.getvalue()
return res
async def draw_single_card(
img: Image.Image,
char: dict,
index: int,
color: Tuple[int, int, int],
x_limit: int,
char_card_mask: Image.Image,
char_card_1: Image.Image,
img_card: Image.Image,
):
size_36 = genshin_font_origin(36)
size_46 = genshin_font_origin(46)
overlay = Image.open(TEXT_PATH / 'overlay.png')
color_img = Image.new(
'RGBA', overlay.size, COLOR_MAP[char['avatarElement']]
)
img_base = ImageChops.overlay(color_img, overlay)
char_img_raw = Image.open(STAND_PATH / f'{char["id"]}.png')
char_img = char_img_raw.resize(
(round(char_img_raw.size[0] * 0.5), round(char_img_raw.size[1] * 0.5))
).convert('RGBA')
offset_x, offset_y = 0, 0
if char['char_name'] == '八重神子':
offset_x = -100
elif char['char_name'] == '早柚':
offset_x = 50
img_base.paste(char_img, (-380 + offset_x, 200 + offset_y), char_img)
img_card.paste(img_base, (-25, -260), char_card_mask)
img_card = Image.alpha_composite(img_card, char_card_1)
# img_card.paste(img_card, (0, 0), img_card)
char_card_text = ImageDraw.Draw(img_card)
char_card_text.text(
(448, 59.2),
f'{str(round(char["critrate"] * 100, 2))}%',
color,
size_36,
anchor='lm',
)
char_card_text.text(
(448, 122.2),
f'{str(round(char["critdmg"] * 100, 2))}%',
color,
size_36,
anchor='lm',
)
char_card_text.text(
(410.9, 252.6), str(char['a_skill_level']), color, size_36, anchor='mm'
)
char_card_text.text(
(485, 252.6), str(char['e_skill_level']), color, size_36, anchor='mm'
)
char_card_text.text(
(558, 252.6), str(char['q_skill_level']), color, size_36, anchor='mm'
)
if float(char['percent']) >= 100:
percent_color = (204, 57, 78)
else:
percent_color = color
if char['value'] >= 28.5:
value_color = (204, 57, 78)
else:
value_color = color
char_card_text.text(
(742, 253.1),
str(char['percent']) + '%',
percent_color,
size_46,
anchor='mm',
)
char_card_text.text(
(742, 113.1),
str(char['value']) + '',
value_color,
size_46,
anchor='mm',
)
char_card_text.text(
(21.2, 70.5),
f'{str(char["talent_num"])}',
color,
size_36,
anchor='lm',
)
char_card_text.text(
(21.2, 129.8),
f'{str(char["weapon_affix"])}',
color,
size_36,
anchor='lm',
)
img.paste(
img_card, ((index % x_limit) * 900, (index // x_limit) * 300), img_card
)
async def draw_cahrcard_list(uid: str, limit: int = 24) -> Union[str, bytes]:
uid_fold = PLAYER_PATH / str(uid)
char_file_list = uid_fold.glob('*')
char_list = []
for i in char_file_list:
file_name = i.name
if '\u4e00' <= file_name[0] <= '\u9fff':
char_list.append(file_name.split('.')[0])
if not char_list:
return '你还没有已缓存的角色!\n请先使用【强制刷新】进行刷新!'
char_done_list = []
with open(DMG_PATH / 'char_action.json', "r", encoding='UTF-8') as f:
char_action = json.load(f)
for char_name in char_list:
temp = {}
with open(uid_fold / f'{char_name}.json', 'r', encoding='UTF-8') as f:
raw_data = json.load(f)
fight_prop = raw_data['avatarFightProp']
skillList = raw_data['avatarSkill']
temp['char_name'] = char_name
temp['id'] = raw_data['avatarId']
temp['avatarEnName'] = raw_data['avatarEnName']
temp['avatarElement'] = raw_data['avatarElement']
# 拿到倍率表
power_list = char_action[char_name]
new_prop = await calc_prop(raw_data, power_list)
temp['percent'] = await get_char_percent(raw_data, new_prop, char_name)
temp['critrate'] = fight_prop['critRate']
temp['critdmg'] = fight_prop['critDmg']
baseHp = fight_prop['baseHp']
baseAtk = fight_prop['baseAtk']
baseDef = fight_prop['baseDef']
temp['value'] = await get_all_artifacts_value(
raw_data['equipList'], baseHp, baseAtk, baseDef, char_name
)
temp['value'] = float('{:.2f}'.format(temp['value']))
temp['avatarElement'] = raw_data['avatarElement']
temp['a_skill_level'] = skillList[0]['skillLevel']
temp['e_skill_level'] = skillList[1]['skillLevel']
temp['q_skill_level'] = skillList[-1]['skillLevel']
temp['talent_num'] = len(raw_data['talentList'])
temp['weapon_affix'] = raw_data['weaponInfo']['weaponAffix']
char_done_list.append(temp)
# 排序
char_done_list.sort(key=lambda x: (-float(x['percent'])))
char_done_list = char_done_list[:limit]
char_card_1 = Image.open(TEXT_PATH / 'charcard_1.png')
char_card_mask = Image.open(TEXT_PATH / 'charcard_mask.png')
x_limit = 2
color = (255, 255, 255)
x_tile = (len(char_done_list) + x_limit - 1) // x_limit
y_tile = math.ceil(len(char_done_list) / x_tile)
x_tile, y_tile = (
x_tile if x_tile <= y_tile else y_tile,
y_tile if y_tile >= x_tile else x_tile,
)
img = Image.new('RGBA', (900 * x_tile, 300 * y_tile), (0, 0, 0))
img_card = Image.new('RGBA', (900, 300))
tasks = []
for index, char in enumerate(char_done_list):
tasks.append(
draw_single_card(
img,
char,
index,
color,
x_limit,
char_card_mask,
char_card_1,
img_card,
)
)
await asyncio.wait(tasks)
res = await convert_img(img)
return res