From 3dd68e9a0eb3e0daf3d1689c105f25138827612b Mon Sep 17 00:00:00 2001
From: CMHopeSunshine <277073121@qq.com>
Date: Tue, 28 Jun 2022 19:44:18 +0800
Subject: [PATCH] =?UTF-8?q?`ysd`=E6=94=AF=E6=8C=81=E6=97=85=E8=A1=8C?=
=?UTF-8?q?=E8=80=85=E3=80=81=E5=A2=9E=E5=8A=A0=E5=9C=B0=E5=8C=BA=E5=9B=BE?=
=?UTF-8?q?=E6=A0=87=E3=80=81=E4=BC=98=E5=8C=96=E8=AF=84=E5=88=86=E7=AE=97?=
=?UTF-8?q?=E6=B3=95=EF=BC=8Cfix=20bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Guess_voice/download_data.py | 9 -
Guess_voice/handler.py | 21 +-
Paimon_Gacha/gacha_res.py | 5 +-
Paimon_Gacha_Log/api.py | 2 +-
Paimon_Gacha_Log/get_img.py | 2 +-
Paimon_Info/draw_abyss_info.py | 2 +-
Paimon_Info/draw_daily_note.py | 2 +-
Paimon_Info/draw_month_info.py | 2 +-
Paimon_Info/draw_player_card.py | 2 +-
Paimon_Info/draw_role_card.py | 233 ++++-----
README.md | 64 +--
UPDATE_LOG.md | 8 +-
res/player_card2/璃月.png | Bin 0 -> 5182 bytes
res/player_card2/稻妻.png | Bin 0 -> 6420 bytes
res/player_card2/立绘/空.png | Bin 0 -> 195181 bytes
res/player_card2/立绘/荧.png | Bin 0 -> 201461 bytes
res/player_card2/至冬.png | Bin 0 -> 15355 bytes
res/player_card2/蒙德.png | Bin 0 -> 6540 bytes
utils/alias_handler.py | 24 +-
utils/enka_util.py | 216 ++++----
utils/help.json | 5 -
utils/{ => json}/alias.json | 2 +-
utils/json/role_region.json | 52 ++
utils/json/score.json | 834 +++++++++++++++++++++++++++----
utils/{ => json}/short_name.json | 1 +
25 files changed, 1100 insertions(+), 386 deletions(-)
create mode 100644 res/player_card2/璃月.png
create mode 100644 res/player_card2/稻妻.png
create mode 100644 res/player_card2/立绘/空.png
create mode 100644 res/player_card2/立绘/荧.png
create mode 100644 res/player_card2/至冬.png
create mode 100644 res/player_card2/蒙德.png
delete mode 100644 utils/help.json
rename utils/{ => json}/alias.json (99%)
create mode 100644 utils/json/role_region.json
rename utils/{ => json}/short_name.json (98%)
diff --git a/Guess_voice/download_data.py b/Guess_voice/download_data.py
index 3217170..14a40f5 100644
--- a/Guess_voice/download_data.py
+++ b/Guess_voice/download_data.py
@@ -1,8 +1,3 @@
-# -*- coding: UTF-8 -*-
-"""
-该脚本可以直接获取wiki上的语音文件 并保存进数据库中
-"""
-
import json
import os
from pathlib import Path
@@ -14,7 +9,6 @@ from sqlitedict import SqliteDict # TODO 加入requirements
from utils import aiorequests
from .util import get_path
-# OUT_PUT = Path(__file__).parent / 'voice'
OUT_PUT = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'voice'
BASE_URL = 'https://wiki.biligame.com/ys/'
@@ -28,11 +22,8 @@ config = {
'voice_language': ['日', '英', '韩']
}
-# dir_data = os.path.join(os.path.dirname(__file__), 'data')
dir_data = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'data'
-# if not os.path.exists(dir_data):
-# os.makedirs(dir_data)
dir_data.mkdir(parents=True, exist_ok=True)
diff --git a/Guess_voice/handler.py b/Guess_voice/handler.py
index c3fbe19..574a6a7 100644
--- a/Guess_voice/handler.py
+++ b/Guess_voice/handler.py
@@ -15,21 +15,14 @@ from sqlitedict import SqliteDict
from .download_data import voice_list_by_mys, voice_detail_by_mys
from .util import get_path, require_file
+from utils.alias_handler import get_alias_by_name
scheduler = require('nonebot_plugin_apscheduler').scheduler
-# dir_data = os.path.join(os.path.dirname(__file__), 'data')
dir_data = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'data'
-
-# data_path = os.path.join(os.path.dirname(__file__), 'voice')
data_path = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'voice'
-
-# data2_path = os.path.join(os.path.dirname(__file__), 'voice2')
data2_path = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'voice2'
-# if not os.path.exists(dir_data):
-# os.makedirs(dir_data)
-
dir_data.mkdir(parents=True, exist_ok=True)
db = {}
@@ -57,15 +50,23 @@ with open(os.path.join(os.path.dirname(__file__), 'character.json'), 'r', encodi
def create_guess_matcher(role_name, second, group_id):
+ """
+ 创建一个猜语音的正则匹配matcher,正则内容为角色的别名
+ :param role_name: 角色名
+ :param second: 结束时间(秒)
+ :param group_id: 进行的群组
+ :return: None
+ """
def check_group(event: GroupMessageEvent):
if event.group_id == group_id:
return True
return False
- alias_list = character_json.get(role_name, [])
- re_str = role_name + '|' + '|'.join(alias_list)
+ alias_list = get_alias_by_name(role_name)
+ re_str = '|'.join(alias_list)
guess_matcher = on_regex(re_str, temp=True, rule=Rule(check_group))
guess_matcher.plugin_name = "Guess_voice"
+ guess_matcher.expire_time = datetime.timedelta(seconds=second)
@guess_matcher.handle()
async def _(event: GroupMessageEvent):
diff --git a/Paimon_Gacha/gacha_res.py b/Paimon_Gacha/gacha_res.py
index 93016b7..ec9e4bd 100644
--- a/Paimon_Gacha/gacha_res.py
+++ b/Paimon_Gacha/gacha_res.py
@@ -199,7 +199,7 @@ async def create_item(rank, item_type, name, element, count, dg_time):
return bg
-async def ten(uid, gacha_data) -> PngImagePlugin.PngImageFile:
+async def ten(uid, gacha_data):
gacha_list = []
for i in range(0, 10):
if gacha_data['gacha_type'] == 'all_star':
@@ -210,7 +210,6 @@ async def ten(uid, gacha_data) -> PngImagePlugin.PngImageFile:
role = once(uid, gacha_data).copy()
gacha_list.append(role)
gacha_list.sort(key=lambda x: x["rank"], reverse=True)
- img: PngImagePlugin.PngImageFile
img = Image.open(os.path.join(RES_PATH, 'background.png'))
i = 0
for wish in gacha_list:
@@ -245,4 +244,4 @@ async def more_ten(uid, gacha_data, num, sd):
draw = ImageDraw.Draw(img)
draw.text((27, 575 * num - 30), ('@%s %s Created By LittlePaimon' % (str(sd.nickname), time_str)), font=time_font,
fill="#8E8E8E")
- return MessageBuild.Image(img, quality=75)
+ return MessageBuild.Image(img, quality=75, mode='RGB')
diff --git a/Paimon_Gacha_Log/api.py b/Paimon_Gacha_Log/api.py
index 01d470e..922fe73 100644
--- a/Paimon_Gacha_Log/api.py
+++ b/Paimon_Gacha_Log/api.py
@@ -4,7 +4,7 @@ from utils import aiorequests
def toApi(url):
- spliturl = str(url).split("?")
+ spliturl = str(url).replace('amp;', '').split("?")
if "webstatic-sea" in spliturl[0] or "hk4e-api-os" in spliturl[0]:
spliturl[0] = "https://hk4e-api-os.mihoyo.com/event/gacha_info/api/getGachaLog"
else:
diff --git a/Paimon_Gacha_Log/get_img.py b/Paimon_Gacha_Log/get_img.py
index 46db339..4303330 100644
--- a/Paimon_Gacha_Log/get_img.py
+++ b/Paimon_Gacha_Log/get_img.py
@@ -141,4 +141,4 @@ async def get_gacha_log_img(gacha_data, pool):
img_draw.text((595, 44), f'UID:{gacha_data["uid"]}', font=get_font(16), fill='black')
img_draw.text((530, total_height - 45), 'Created by LittlePaimon', font=get_font(16), fill='black')
- return MessageBuild.Image(img)
+ return MessageBuild.Image(img, mode='RGB')
diff --git a/Paimon_Info/draw_abyss_info.py b/Paimon_Info/draw_abyss_info.py
index 78ee258..74e0d5b 100644
--- a/Paimon_Info/draw_abyss_info.py
+++ b/Paimon_Info/draw_abyss_info.py
@@ -155,4 +155,4 @@ async def draw_abyss_card(data, uid, floor_num):
total_img.alpha_composite(floor_img, (5, 5 + 524 + 5 + h))
h += 1210
- return MessageBuild.Image(total_img, quality=75)
+ return MessageBuild.Image(total_img, quality=75, mode='RGB')
diff --git a/Paimon_Info/draw_daily_note.py b/Paimon_Info/draw_daily_note.py
index e2de6df..50eb9a3 100644
--- a/Paimon_Info/draw_daily_note.py
+++ b/Paimon_Info/draw_daily_note.py
@@ -157,4 +157,4 @@ async def draw_daily_note_card(data, uid):
bg_img.alpha_composite(role_img, (1220, 200))
now = datetime.datetime.now().strftime('%m月%d日%H:%M')
bg_draw.text((554, 1794), 'Created by LittlePaimon·' + now, fill='#5680d2', font=get_font(40, '优设标题黑.ttf'))
- return MessageBuild.Image(bg_img, size=0.35, quality=70)
+ return MessageBuild.Image(bg_img, size=0.35, quality=70, mode='RGB')
diff --git a/Paimon_Info/draw_month_info.py b/Paimon_Info/draw_month_info.py
index 0c68750..b604b65 100644
--- a/Paimon_Info/draw_month_info.py
+++ b/Paimon_Info/draw_month_info.py
@@ -114,4 +114,4 @@ async def draw_monthinfo_card(data):
bg_draw.text((49, 857), f'本月相比上个月,原石{ysstr},摩拉{mlstr}', font=get_font(23), fill='#27384C')
bg_draw.text((167, 900), 'Created by LittlePaimon', font=get_font(21), fill='#27384C')
- return MessageBuild.Image(bg_img, quality=70)
+ return MessageBuild.Image(bg_img, quality=70, mode='RGB')
diff --git a/Paimon_Info/draw_player_card.py b/Paimon_Info/draw_player_card.py
index 21e5ead..eaf9a57 100644
--- a/Paimon_Info/draw_player_card.py
+++ b/Paimon_Info/draw_player_card.py
@@ -495,4 +495,4 @@ async def draw_chara_card(data, skill_data, chara_name, uid):
bg_draw.text((330, 371), 'Created by LittlePaimon', font=get_font(20), fill='white')
- return MessageBuild.Image(bg_img, size=0.95, quality=80)
+ return MessageBuild.Image(bg_img, size=0.95, quality=80, mode='RGB')
diff --git a/Paimon_Info/draw_role_card.py b/Paimon_Info/draw_role_card.py
index 5632dfb..d591948 100644
--- a/Paimon_Info/draw_role_card.py
+++ b/Paimon_Info/draw_role_card.py
@@ -1,8 +1,8 @@
from PIL import Image, ImageDraw, ImageFont
from pathlib import Path
-from utils.file_handler import load_image
-from utils.enka_util import artifact_total_score, check_effective
+from utils.file_handler import load_image, load_json
+from utils.enka_util import get_artifact_suit, artifact_total_value, get_expect_score, get_effective, check_effective
from utils import aiorequests
from utils.message_util import MessageBuild
@@ -34,78 +34,86 @@ for i in range(1, 6):
paint = load_image(res_path / 'player_card2' / '立绘框.png', mode='RGBA')
lock = load_image(res_path / 'player_card2' / '锁.png', mode='RGBA', size=(45, 45))
loading = load_image(res_path / 'player_card2' / '加载中.png', mode='RGBA', size=(120, 120))
+region = load_json(path=Path(__file__).parent.parent / 'utils' / 'json' / 'role_region.json')
def get_font(size, font='hywh.ttf'):
return ImageFont.truetype(str(res_path / font), size)
+def draw_right_text(draw, text, width, height, fill, font):
+ text_length = draw.textlength(text, font=font)
+ draw.text((width - text_length, height), text, fill=fill,
+ font=font)
+
+
+def draw_center_text(draw, text, left_width, right_width, height, fill, font):
+ text_length = draw.textlength(text, font=font)
+ draw.text((left_width + (right_width - left_width - text_length) / 2, height), text, fill=fill,
+ font=font)
+
+
async def draw_role_card(uid, data):
bg = Image.new('RGBA', (1080, 1920), (0, 0, 0, 0))
bg.alpha_composite(bg_card[data['元素']], (0, 0))
bg.alpha_composite(base_mask, (0, 0))
+ if data['名称'] not in ['荧', '空', '埃洛伊']:
+ region_icon = load_image(path=res_path / 'player_card2' / f'{region[data["名称"]]}.png', size=(130, 130))
+ bg.alpha_composite(region_icon, (0, 4))
bg_draw = ImageDraw.Draw(bg)
bg_draw.text((131, 100), f"UID{uid}", fill='white', font=get_font(48, 'number.ttf'))
bg_draw.text((134, 150), data['名称'], fill='white', font=get_font(72, '优设标题黑.ttf'))
bg.alpha_composite(level_mask, (298 + 60 * (len(data['名称']) - 2), 172))
- bg_draw.text((330 + 60 * (len(data['名称']) - 2), 174), f'LV{data["等级"]}', fill='black',
- font=get_font(48, 'number.ttf'))
+ draw_center_text(bg_draw, f'LV{data["等级"]}', 298 + 60 * (len(data['名称']) - 2), 298 + 60 * (len(data['名称']) - 2) + 171, 174, 'black', get_font(48, 'number.ttf'))
+
# 属性值
prop = data['属性']
bg_draw.text((89, 262), '生命值', fill='white', font=get_font(34, 'hywh.ttf'))
- text_length = 473 - (len(str(prop['基础生命'])) + len(str(prop['额外生命']))) * 20 - 12
- bg_draw.text((text_length, 264), f"{prop['基础生命']}", fill='white', font=get_font(34, 'number.ttf'))
- bg_draw.text((text_length + len(str(prop['基础生命'])) * 20 + 3, 264), f"+{prop['额外生命']}", fill='#59c538',
- font=get_font(34, 'number.ttf'))
+ text_length = bg_draw.textlength(f"+{prop['额外生命']}", font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"{prop['基础生命']}", 480 - text_length - 5, 264, 'white', get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"+{prop['额外生命']}", 480, 264, '#59c538', get_font(34, 'number.ttf'))
bg_draw.text((89, 319), '攻击力', fill='white', font=get_font(34, 'hywh.ttf'))
- text_length = 473 - (len(str(prop['基础攻击'])) + len(str(prop['额外攻击']))) * 20 - 12
- bg_draw.text((text_length, 321), f"{prop['基础攻击']}", fill='white', font=get_font(34, 'number.ttf'))
- bg_draw.text((text_length + len(str(prop['基础攻击'])) * 20 + 3, 321), f"+{prop['额外攻击']}", fill='#59c538',
- font=get_font(34, 'number.ttf'))
+ text_length = bg_draw.textlength(f"+{prop['额外攻击']}", font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"{prop['基础攻击']}", 480 - text_length - 5, 321, 'white', get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"+{prop['额外攻击']}", 480, 321, '#59c538', get_font(34, 'number.ttf'))
bg_draw.text((89, 377), '防御力', fill='white', font=get_font(34, 'hywh.ttf'))
- text_length = 473 - (len(str(prop['基础防御'])) + len(str(prop['额外防御']))) * 20 - 12
- bg_draw.text((text_length, 379), f"{prop['基础防御']}", fill='white', font=get_font(34, 'number.ttf'))
- bg_draw.text((text_length + len(str(prop['基础防御'])) * 20 + 3, 379), f"+{prop['额外防御']}", fill='#59c538',
- font=get_font(34, 'number.ttf'))
+ text_length = bg_draw.textlength(f"+{prop['额外防御']}", font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"{prop['基础防御']}", 480 - text_length - 5, 379, 'white', get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"+{prop['额外防御']}", 480, 379, '#59c538', get_font(34, 'number.ttf'))
text = round(prop['暴击率'] * 100, 1)
bg_draw.text((89, 436), '暴击率', fill='white', font=get_font(34, 'hywh.ttf'))
- bg_draw.text((473 - len(str(text)) * 17 - 17, 438), f"{text}%", fill='white',
- font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"{text}%", 480, 438, 'white', get_font(34, 'number.ttf'))
text = round(prop['暴击伤害'] * 100, 1)
bg_draw.text((89, 493), '暴击伤害', fill='white', font=get_font(34, 'hywh.ttf'))
- bg_draw.text((473 - len(str(text)) * 17 - 17, 495), f"{text}%", fill='white',
- font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"{text}%", 480, 495, 'white', get_font(34, 'number.ttf'))
bg_draw.text((89, 551), '元素精通', fill='white', font=get_font(34, 'hywh.ttf'))
- bg_draw.text((473 - len(str(prop['元素精通'])) * 18, 553), f"{prop['元素精通']}", fill='white',
- font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, str(prop['元素精通']), 480, 553, 'white', get_font(34, 'number.ttf'))
text = round(prop['元素充能效率'] * 100, 1)
bg_draw.text((89, 610), '充能效率', fill='white', font=get_font(34, 'hywh.ttf'))
- bg_draw.text((473 - len(str(text)) * 17 - 17, 612), f"{text}%", fill='white',
- font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"{text}%", 480, 612, 'white', get_font(34, 'number.ttf'))
max_element = max(prop['伤害加成'])
text = round(max_element * 100, 1)
bg_draw.text((89, 669), f'{element_type[prop["伤害加成"].index(max_element)]}伤害加成', fill='white',
font=get_font(34, 'hywh.ttf'))
- bg_draw.text((473 - len(str(text)) * 16 - 16, 671), f"{text}%", fill='white',
- font=get_font(34, 'number.ttf'))
+ draw_right_text(bg_draw, f"{text}%", 480, 671, 'white', get_font(34, 'number.ttf'))
# 天赋
if data['名称'] in ['神里绫华', '莫娜']:
data['天赋'].pop(2)
for i in range(3):
bg.alpha_composite(base_icon[data['元素']].resize((132, 142)), (564, 253 + 147 * i))
- bg_draw.text((522 if data['天赋'][i]['等级'] < 10 else 513, 310 + 147 * i), str(data['天赋'][i]['等级']), fill='black',
- font=get_font(34, 'number.ttf'))
+ draw_center_text(bg_draw, str(data['天赋'][i]['等级']), 510, 552, 310 + 147 * i, 'black', get_font(34, 'number.ttf'))
skill_icon = res_path2 / 'skill' / f'{data["天赋"][i]["图标"]}.png'
- skill_icon = await aiorequests.get_img(url=skill_url.format(data["天赋"][i]["图标"]), size=(57, 57), save_path=skill_icon)
+ skill_icon = await aiorequests.get_img(url=skill_url.format(data["天赋"][i]["图标"]), size=(57, 57),
+ save_path=skill_icon)
bg.alpha_composite(skill_icon, (603, 298 + 147 * i))
# 命座
@@ -113,7 +121,8 @@ async def draw_role_card(uid, data):
for talent in data['命座']:
bg.alpha_composite((base_icon[data['元素']]).resize((83, 90)), (510 + t * 84, 790))
talent_icon = res_path2 / 'skill' / f'{talent["图标"]}.png'
- talent_icon = await aiorequests.get_img(url=talent_url.format(talent["图标"]), size=(45, 45), save_path=talent_icon)
+ talent_icon = await aiorequests.get_img(url=talent_url.format(talent["图标"]), size=(45, 45),
+ save_path=talent_icon)
bg.alpha_composite(talent_icon, (529 + t * 84, 813))
t += 1
for t2 in range(t, 6):
@@ -123,15 +132,18 @@ async def draw_role_card(uid, data):
# 武器
bg.alpha_composite(weapon_bg[data['武器']['星级'] - 1], (91, 760))
weapon_icon = res_path2 / 'weapon' / f'{data["武器"]["图标"]}.png'
- weapon_icon = await aiorequests.get_img(url=weapon_url.format(data["武器"]["图标"]), size=(150, 150), save_path=weapon_icon)
+ weapon_icon = await aiorequests.get_img(url=weapon_url.format(data["武器"]["图标"]), size=(150, 150),
+ save_path=weapon_icon)
bg.alpha_composite(weapon_icon, (91, 760))
bg_draw.text((268, 758), data['武器']['名称'], fill='white', font=get_font(34, 'hywh.ttf'))
for i in range(data['武器']['星级']):
bg.alpha_composite(star, (267 + i * 30, 799))
- bg_draw.text((283, 835), f'LV{data["武器"]["等级"]}', fill='black', font=get_font(27, 'number.ttf'))
+ draw_center_text(bg_draw, f'LV{data["武器"]["等级"]}', 268, 268 + 98, 835, 'black', get_font(27, 'number.ttf'))
bg_draw.text((266, 869), f'精炼{data["武器"]["精炼等级"]}阶', fill='white', font=get_font(34, 'hywh.ttf'))
# 圣遗物
+ effective = get_effective(data['名称'], data['武器']['名称'], data['圣遗物'], data['元素'])
+ average = get_expect_score(effective)
total_score = 0
# 第一排
for i in range(2):
@@ -141,35 +153,38 @@ async def draw_role_card(uid, data):
break
bg.alpha_composite(weapon_bg[artifact['星级'] - 1].resize((100, 100)), (587 + 317 * i, 1002))
reli_path = res_path2 / 'reli' / f'{artifact["图标"]}.png'
- reli_path = await aiorequests.get_img(url=artifact_url.format(artifact["图标"]), size=(100, 100), save_path=reli_path)
+ reli_path = await aiorequests.get_img(url=artifact_url.format(artifact["图标"]), size=(100, 100),
+ save_path=reli_path)
bg.alpha_composite(reli_path, (587 + 317 * i, 1002))
- bg_draw.text((412 + 317 * i, 950), artifact['名称'], fill='white', font=get_font(40))
- score = artifact_total_score(artifact['词条'])
- total_score += score
- rank = 'SSS' if score >= 45 else 'SS' if 40 <= score < 45 else 'S' if 35 <= score < 40 else 'A' if 30 <= score < 35 else 'B' if 25 <= score < 30 else 'C'
- bg_draw.text((412 + 317 * i, 998), f'{rank}-{score}', fill='#ffde6b', font=get_font(28, 'number.ttf'))
+ bg_draw.text((411 + 317 * i, 951), artifact['名称'], fill='white', font=get_font(40))
+ value, score = artifact_total_value(data['属性'], artifact, effective)
+ total_score += value
+ rank = 'SSS' if score >= 140 else 'SS' if 120 <= score < 140 else 'S' if 100 <= score < 120 else 'A' if 75 <= score < 100 else 'B' if 50 <= score < 75 else 'C'
+ bg_draw.text((412 + 317 * i, 998), f'{rank}-{value}', fill='#ffde6b', font=get_font(28, 'number.ttf'))
bg.alpha_composite(level_mask.resize((98, 30)), (412 + 317 * i, 1032))
- bg_draw.text((433 + 317 * i, 1033), f"LV{artifact['等级']}", fill='black', font=get_font(27, 'number.ttf'))
- bg_draw.text((411 + 317 * i, 1067), artifact['主属性']['属性名'], fill='white', font=get_font(25))
+ draw_center_text(bg_draw, f"LV{artifact['等级']}", 412 + 317 * i, 412 + 317 * i + 98, 1033, 'black', get_font(27, 'number.ttf'))
+ bg_draw.text((411 + 317 * i, 1069), artifact['主属性']['属性名'], fill='white', font=get_font(25))
if artifact['主属性']['属性名'] not in ['生命值', '攻击力', '元素精通']:
- bg_draw.text((408 + 317 * i, 1100), f"+{artifact['主属性']['属性值']}%", fill='white', font=get_font(25, 'number.ttf'))
+ bg_draw.text((408 + 317 * i, 1100), f"+{artifact['主属性']['属性值']}%", fill='white',
+ font=get_font(25, 'number.ttf'))
else:
- bg_draw.text((408 + 317 * i, 1100), f"+{artifact['主属性']['属性值']}", fill='white', font=get_font(48, 'number.ttf'))
+ bg_draw.text((408 + 317 * i, 1100), f"+{artifact['主属性']['属性值']}", fill='white',
+ font=get_font(48, 'number.ttf'))
for j in range(len(artifact['词条'])):
if '百分比' in artifact['词条'][j]['属性名']:
text = artifact['词条'][j]['属性名'].replace('百分比', '')
else:
text = artifact['词条'][j]['属性名']
- bg_draw.text((411 + 317 * i, 1163 + 50 * j), text, fill='white' if check_effective(data['名称'], artifact['词条'][j]['属性名']) else '#afafaf', font=get_font(25))
+ bg_draw.text((411 + 317 * i, 1163 + 50 * j), text,
+ fill='white' if check_effective(artifact['词条'][j]['属性名'], effective) else '#afafaf',
+ font=get_font(25))
if artifact['词条'][j]['属性名'] not in ['攻击力', '防御力', '生命值', '元素精通']:
num = '+' + str(artifact['词条'][j]['属性值']) + '%'
- text_length = 671 - len(str(artifact['词条'][j]['属性值'])) * 13 + 317 * i - 35 + 8
- if '.' not in str(artifact['词条'][j]['属性值']):
- text_length -= 5
else:
num = '+' + str(artifact['词条'][j]['属性值'])
- text_length = 671 - len(str(artifact['词条'][j]['属性值'])) * 13 + 317 * i - 15
- bg_draw.text((text_length, 1163 + 50 * j), num, fill='white' if check_effective(data['名称'], artifact['词条'][j]['属性名']) else '#afafaf', font=get_font(25, 'number.ttf'))
+ draw_right_text(bg_draw, num, 679 + 317 * i, 1163 + 50 * j,
+ fill='white' if check_effective(artifact['词条'][j]['属性名'], effective) else '#afafaf',
+ font=get_font(25, 'number.ttf'))
# 第二排
for i in range(3):
try:
@@ -181,88 +196,78 @@ async def draw_role_card(uid, data):
reli_path = await aiorequests.get_img(url=artifact_url.format(artifact["图标"]), size=(100, 100),
save_path=reli_path)
bg.alpha_composite(reli_path, (270 + 317 * i, 1439))
- bg_draw.text((95 + 317 * i, 1387), artifact['名称'], fill='white', font=get_font(40))
- score = artifact_total_score(artifact['词条'])
- total_score += score
- rank = 'SSS' if score >= 45 else 'SS' if 40 <= score < 45 else 'S' if 35 <= score < 40 else 'A' if 30 <= score < 35 else 'B' if 25 <= score < 30 else 'C'
- bg_draw.text((95 + 317 * i, 1435), f'{rank}-{score}', fill='#ffde6b', font=get_font(28, 'number.ttf'))
+ bg_draw.text((94 + 317 * i, 1388), artifact['名称'], fill='white', font=get_font(40))
+ value, score = artifact_total_value(data['属性'], artifact, effective)
+ total_score += value
+ rank = 'SSS' if score >= 140 else 'SS' if 120 <= score < 140 else 'S' if 100 <= score < 120 else 'A' if 75 <= score < 100 else 'B' if 50 <= score < 75 else 'C'
+ bg_draw.text((95 + 317 * i, 1435), f'{rank}-{value}', fill='#ffde6b', font=get_font(28, 'number.ttf'))
bg.alpha_composite(level_mask.resize((98, 30)), (95 + 317 * i, 1469))
- bg_draw.text((116 + 317 * i, 1470), f"LV{artifact['等级']}", fill='black', font=get_font(27, 'number.ttf'))
- bg_draw.text((94 + 317 * i, 1504), artifact['主属性']['属性名'], fill='white', font=get_font(25))
+ draw_center_text(bg_draw, f"LV{artifact['等级']}", 95 + 317 * i, 95 + 317 * i + 98, 1470, 'black',
+ get_font(27, 'number.ttf'))
+ bg_draw.text((94 + 317 * i, 1506), artifact['主属性']['属性名'], fill='white', font=get_font(25))
if artifact['主属性']['属性名'] not in ['生命值', '攻击力', '元素精通']:
- bg_draw.text((91 + 317 * i, 1537), f"+{artifact['主属性']['属性值']}%", fill='white', font=get_font(48, 'number.ttf'))
+ bg_draw.text((91 + 317 * i, 1537), f"+{artifact['主属性']['属性值']}%", fill='white',
+ font=get_font(48, 'number.ttf'))
else:
- bg_draw.text((91 + 317 * i, 1537), f"+{artifact['主属性']['属性值']}", fill='white', font=get_font(48, 'number.ttf'))
+ bg_draw.text((91 + 317 * i, 1537), f"+{artifact['主属性']['属性值']}", fill='white',
+ font=get_font(48, 'number.ttf'))
for j in range(len(artifact['词条'])):
if '百分比' in artifact['词条'][j]['属性名']:
text = artifact['词条'][j]['属性名'].replace('百分比', '')
else:
text = artifact['词条'][j]['属性名']
- bg_draw.text((94 + 317 * i, 1600 + 50 * j), text, fill='white' if check_effective(data['名称'], artifact['词条'][j]['属性名']) else '#afafaf', font=get_font(25))
+ bg_draw.text((94 + 317 * i, 1600 + 50 * j), text,
+ fill='white' if check_effective(artifact['词条'][j]['属性名'], effective) else '#afafaf',
+ font=get_font(25))
if artifact['词条'][j]['属性名'] not in ['攻击力', '防御力', '生命值', '元素精通']:
num = '+' + str(artifact['词条'][j]['属性值']) + '%'
- text_length = 354 - len(str(artifact['词条'][j]['属性值'])) * 13 + 317 * i - 35 + 8
- if '.' not in str(artifact['词条'][j]['属性值']):
- text_length -= 5
else:
num = '+' + str(artifact['词条'][j]['属性值'])
- text_length = 354 - len(str(artifact['词条'][j]['属性值'])) * 13 + 317 * i - 15
- bg_draw.text((text_length, 1600 + 50 * j), num, fill='white' if check_effective(data['名称'], artifact['词条'][j]['属性名']) else '#afafaf', font=get_font(25, 'number.ttf'))
+ draw_right_text(bg_draw, num, 362 + 317 * i, 1600 + 50 * j,
+ fill='white' if check_effective(artifact['词条'][j]['属性名'], effective) else '#afafaf',
+ font=get_font(25, 'number.ttf'))
# 圣遗物评分
- bg_draw.text((118, 1057), '圣遗物总评分', fill='#afafaf', font=get_font(36))
- bg_draw.text((192, 974), str(round(total_score, 1)), fill='white', font=get_font(60, 'number.ttf'))
- total_rank = 'S' if total_score >= 200 else 'A' if 160 <= total_score < 200 else 'B' if 120 <= total_score < 160 else 'C'
- bg.alpha_composite(rank_icon[total_rank], (110, 964))
+ bg_draw.text((119, 1057), '总有效词条数', fill='#afafaf', font=get_font(36))
+ score_pro = total_score / (average * 5) * 100
+ total_rank = 'SSS' if score_pro >= 140 else 'SS' if 120 <= score_pro < 140 else 'S' if 100 <= score_pro < 120 else 'A' if 75 <= score_pro < 100 else 'B' if 50 <= score_pro < 75 else 'C'
+ if len(total_rank) == 3:
+ bg.alpha_composite(rank_icon[total_rank[0]], (95, 964))
+ bg.alpha_composite(rank_icon[total_rank[0]], (145, 964))
+ bg.alpha_composite(rank_icon[total_rank[0]], (195, 964))
+ bg_draw.text((250, 974), str(round(total_score, 1)), fill='white', font=get_font(60, 'number.ttf'))
+ elif len(total_rank) == 2:
+ bg.alpha_composite(rank_icon[total_rank[0]], (125, 964))
+ bg.alpha_composite(rank_icon[total_rank[0]], (175, 964))
+ bg_draw.text((235, 974), str(round(total_score, 1)), fill='white', font=get_font(60, 'number.ttf'))
+ else:
+ bg.alpha_composite(rank_icon[total_rank[0]], (143, 964))
+ bg_draw.text((217, 974), str(round(total_score, 1)), fill='white', font=get_font(60, 'number.ttf'))
# 圣遗物套装
- suit = []
- suit2 = []
- flag = False
- for artifact in data['圣遗物']:
- suit.append(artifact['所属套装'])
- for s in suit:
- if s not in suit2 and 1 < suit.count(s) < 4:
- suit2.append(s)
- if suit.count(s) >= 4:
- for r in data['圣遗物']:
- if r['所属套装'] == s:
- reli_path = res_path2 / 'reli' / f'{r["图标"]}.png'
- reli_path = await aiorequests.get_img(url=artifact_url.format(r["图标"]), size=(110, 110),
- save_path=reli_path)
- bg.alpha_composite(reli_path, (76, 1130))
- bg.alpha_composite(reli_path, (76, 1255))
- bg_draw.text((184, 1168), f'{s[:2]}四件套', fill='white', font=get_font(36))
- bg_draw.text((184, 1292), f'{s[:2]}四件套', fill='white', font=get_font(36))
- flag = True
- break
- if len(suit2) == 2:
- bg_draw.text((184, 1168), f'{suit2[0][:2]}两件套', fill='white', font=get_font(36))
- bg_draw.text((184, 1292), f'{suit2[1][:2]}两件套', fill='white', font=get_font(36))
- n = 0
- for r in data["圣遗物"]:
- if n == 2:
- break
- if r['所属套装'] in suit2:
- suit2.remove(r['所属套装'])
- reli_path = res_path2 / 'reli' / f'{r["图标"]}.png'
- reli_path = await aiorequests.get_img(url=artifact_url.format(r["图标"]), size=(110, 110),
- save_path=reli_path)
- bg.alpha_composite(reli_path, (76, 1130 + n * 125))
- n += 1
- elif len(suit2) == 1:
- bg_draw.text((184, 1168), f'{suit2[0][:2]}两件套', fill='white', font=get_font(36))
- bg_draw.text((184, 1292), '未激活套装', fill='white', font=get_font(36))
- for r in data["圣遗物"]:
- if r['所属套装'] in suit2:
- reli_path = res_path2 / 'reli' / f'{r["图标"]}.png'
- reli_path = await aiorequests.get_img(url=artifact_url.format(r["图标"]), size=(110, 110),
- save_path=reli_path)
- bg.alpha_composite(reli_path, (76, 1130))
- break
- elif not flag:
+ suit = get_artifact_suit(data['圣遗物'])
+ if not suit:
bg_draw.text((184, 1168), '未激活套装', fill='white', font=get_font(36))
bg_draw.text((184, 1292), '未激活套装', fill='white', font=get_font(36))
+ elif len(suit) == 1:
+ artifact_path = res_path2 / 'reli' / f'{suit[0][1]}.png'
+ artifact_path = await aiorequests.get_img(url=artifact_url.format(suit[0][1]), size=(110, 110),
+ save_path=artifact_path)
+ bg.alpha_composite(artifact_path, (76, 1130))
+ bg.alpha_composite(artifact_path, (76, 1255))
+ bg_draw.text((184, 1168), f'{suit[0][0][:2]}四件套', fill='white', font=get_font(36))
+ bg_draw.text((184, 1292), f'{suit[0][0][:2]}四件套', fill='white', font=get_font(36))
+ else:
+ artifact_path1 = res_path2 / 'reli' / f'{suit[0][1]}.png'
+ artifact_path1 = await aiorequests.get_img(url=artifact_url.format(suit[0][1]), size=(110, 110),
+ save_path=artifact_path1)
+ artifact_path2 = res_path2 / 'reli' / f'{suit[1][1]}.png'
+ artifact_path2 = await aiorequests.get_img(url=artifact_url.format(suit[1][1]), size=(110, 110),
+ save_path=artifact_path2)
+ bg.alpha_composite(artifact_path1, (76, 1130))
+ bg.alpha_composite(artifact_path2, (76, 1255))
+ bg_draw.text((184, 1168), f'{suit[0][0][:2]}两件套', fill='white', font=get_font(36))
+ bg_draw.text((184, 1292), f'{suit[1][0][:2]}两件套', fill='white', font=get_font(36))
# 立绘
paint_path = res_path / 'player_card2' / '立绘' / f'{data["名称"]}.png'
@@ -275,6 +280,4 @@ async def draw_role_card(uid, data):
bg_draw.text((50, 1870), f'更新于{data["更新时间"].replace("2022-", "")}', fill='white', font=get_font(36, '优设标题黑.ttf'))
bg_draw.text((560, 1869), 'Created by LittlePaimon', fill='white', font=get_font(36, '优设标题黑.ttf'))
- return MessageBuild.Image(bg, quality=75)
-
-
+ return MessageBuild.Image(bg, quality=75, mode='RGB')
diff --git a/README.md b/README.md
index c93eb7a..135d393 100644
--- a/README.md
+++ b/README.md
@@ -2,85 +2,70 @@
1698^@`wKbFtgZtT0rMIl$cif}@-71S{YK}DW}{j^o}xHR$Y zrrkH-3eL*$we}BfWwM#RxpfuGRs P^lRh1 z=mN1(dB`2N<4R*O9=v$ZB`!UzLPhJSGgp2A`Zc?Ej7F@ }njy%&ogmcJSF^VbCt)ZLn`;?j7}IG2&kdIiuV$2Z}fBHq^4+49oVh0GA9k ztLwj*V$}wpLVy$2@bO%v$B>fau35Qe35Z*O^qh>`dI)(#?`NR;=Cg=`0-CEJqXs=W zb)~YYt9Xj5yV~wnOqtSO=+A~H^WYiM@;d6KoGmPq(s0?IMp<6a@n7=hsvS`t?JK30 z;|`5Eped{v^5L-A;Y8@w5K;t8miNsUqyDzx!^#!v>d8EzT%psAFelM}IZcL-rExgB zj}s5{*#Tp$RXn<{VwFBdJUY1-#U8Q&ZmTE;#wPMuA3Pt_@NKK8gIUD)4`t=S&uanu zsTOgu<$pB+epnC7kp1d6gN>4|OEQytS?=s;xeYWR6q#=w1MSZNG0|5`&)8Q^p`uFz z7Y=W`Mn*<`G!=?Un!VPp`9>{6tUz{T>t+HyedC?QKP=#pIy`5GQl-BU1!-Q*_Hi^Q zYCF=B)hY*ja$%I^Z5PUJeOfqr3eByO#UdKoFN)Q+6V7e|!c?Wo rZeuYUWG-inkCzt+SzK@gI#msCM6gt4()C|fd(%pYY_Hu zL-x={JRh*Ev}uc1CZ6Bl`~so}wT;}4XSnlcrwzi1abv+57ttY_3xv?Rt^IX42cliK z5KV^N*xC+_4TRko(QrqpjODx+^OE`>%Gzm_GHD&r9C>I#^K4}m9sWh;x}LYZT=eYU zWOdIlGiwH~eL7mCT^i-^q%z498+7D@*ip91Bd7QET5W4?a<79>^XG||nD6;I-E{3J zlfjRmY<#N~xA^;OWEdMSB7`aNU%$ft>d(gB?pJz-LP6Dc>fYLYaOpuwH2fk6IkI>- z;p*3XgfPofK2_ngAO-#h(*6-u@AdIk=5;^&yP0Qcr|H)oYB@lH)6j+er5@q^J73Q_ z`L0{>&FF|$VZ=T2 %=um z!`3c{8EoGo`!lOPSDhvT 0jIiIbuv6xagKckV5PCOf%fNtIOHwJLb#Z z)_)3ESb_XBLe4aKyJ{qM-(4@$Q>)*2Hbh}mqK`5Px!*>yF8fh^fp&?KhW&$d2FDo% zb-`3BPz1&GVw`Vz5CG>1h3r35()8&^0a@7Dxm=zigsZ*JDZ~oVepDK`Uuds94Al|a zu(IH7Bdj_@y7ea6UiY|7gTAOb2omw1n~HvdEYv;{BZ=2o;3B=`ik&>Ql7r5j4l; zs2uPhGrL`}fK-+xCbdG1aRemGVG3o`yNKc5aUP!e_N!lJUFuWU+85Ab0I}#Ocp-a# z%QQN+t5g#AWdtXk4<16^U&e-<@^jzgu?3V0QJ;}PmlE_w9~})_8r}$WSQD&J1Qqzg z(`ZjEm9x_*$Bblq?u}Aw8Z9M~D5i|{!M_t_-DsqV6Pq%9VB2c-&(EI{@4j~LxS8u( zQx|Dg3q<7%^k?* biy?rzDDndx6A_z~MApD9le$Ey zomh5P4WAkgvVjFOaDJL*1(7{o_E0Ti@4?E>>~wXgAzVQt|A2$+jg?66eS@1zybssZ zBP04&*)t;ep4)SS8HNQ9!XHJu`}R_N1r@Kc?gv#^CssU7ybn@G?gN=V@yk^Nw;5P{ zg3%OZJwy#WvbMdD!NS?EGijdQDwF0(AEguNv(=-y!Az5 7ux{LduJHgx_&DZJUc;W(Ii^(sWg2Xc2sIIK+{zo)mMfOll? zeuirLBFQq-$vKfxtn5oH-kPL;sM4R{4!7Eu{r>4!L}ukgOnJt{0T>mq#QeDlYKyYj z7GWB#*i9R9I~!(Cu-qcb-2^R%YA0sh;4d9@Wj)2;dE7$nPI*w7a7n7)4+=H;8 ebgRt*?%#T!8&nMSITud><#j8D`6c`SJVg^Z9wRb;DZE zPsqm%7Mpll)+EA>Fb-oPteszX@{UUJiF8$AdxBV~I!bu$B0*H^$5A0QNFqK^3-5+` z>lgoy5DSm8<2iv#n7c#5W< LLe5OfB z-jyn%piBy5Lw70;MP}9{PE`C$AMZta5$|T8?5d0$_%-NkR3BHz_K@7n4kwbbQYnEu z^`fs-rCQI*O=A1+cgyK-BLKqT!vty}xZx zz>1C|yT7Y@GT@_Y=GQX@QzEa*N^zKWLfGdsOHPI7AcRr@cx*e=@X7?APuY-rOm%IV z)3bb9!1MZJFXNdFIs|3# Qxfri@Q zM `Fm*F0#X)G$4 zM4#Q6EN9>NH@~Ju2R$ySsfmJ3JtvkzTjAXFd9qRSN9ht}6un^>WQjZmJ?T2{c8xhA z2R0`&xBV%o#_Q;`yCD?~BM^G@hWRWJpC9ag&jt~7K_A?GG%s;Q->PwY*f{~klg213 zd7;mn*9gA4ZeYtGVn6eh>WXi1OU&NuB?dS!^VOb!4ep!hpTk1V-bu~VpIRaNn9Ptp zeqIp2XZeo_t~%Fv_j#}`20?J6weGPF0Raf1@9S55sX3xbn*_Hr=jX>Uyfu{a#FDfu z0p&(*65SYfh2@9h4Flb(S-nmqoS(5263F6iS9t8cPq>Dee(5FMH)QamCKXSN=h&JH zcW`<$E01du9WOzN{cmBxO+m~8M$)d@m(=^&XEz`4XFBi14PCapZM^QU@Q#@xT;tC| z!s-1@yf2T2x)C07*$h3lSIyWPaLG|{F5q&R7mW9?Y9=>*VE5rgt}n5C&|+YePY%K0 zyubGP_Y`enerZp6gWU_m+=|0ipJW-QHxS#8*4&JQ*7cksl)2@rJYj7zu13*vt(flk zwGpHe?~ZVA0)Bt4%Ix1_)KbPbXirT56p5h*aVW Nq?-7qhZipSYWVmEY#^ zzx)7_6S6*w9c})bB9O{rvyH?dZn%8u(jAYUVIdc`Dngwq6f-6+_|I76+7I{P<Pk znOE0ddd>T*8G9WW^yI4G+S;WpdtP t!ZHn!tQ{YjtQ zPfPpP=FF$kz8j;}nlPBmV?>%=LSvK2Fp*wPEOPw|%lQz)p}=aSzvT~tuEM-s{p*m0 zSkMin+(`!BNoej}jPMO(B^th`_)e11f|BU+jlDXKHpzoibmi>HWb7J7R$9T5ZTJEF zg_qymo9N?xPi$7Y&(|W8pHO31n!h?V>!DE6J{XSw^Xa?AMOm!h!EKKNj7dZ4@ePe@ z80+IrV5#V$HxSPT%4@Q4W2KxRIhP_N>mi5N;W!{swrT}gKXLyGb84&O5fQ}R$f~dT z!D2@*<_fSSFG(sRyFR2Vk&ouO30A0c@SpDk3zOJX4OmA^hjNdJ5$@zjGR9J#JFD+K zxQ)x-OP%??A*%8J9;vUd&U}O|TBTES!(qfX25J=99{tQN_Waoyo&jX3S)-lI>BBNi zXtA2AbB+7B9A~pB{OvwAp=2tt0@~05&Rz7K&S_fcW#bR<%uF1e@o{$o<8KW8dL7MF zVZB8!=B{0Ix?S#0iYKvL;>Ry! %5VECKR{)<00B0G8n6Hi>Ac7}SxC(9af0ftpU0C1iv`1F&SI@3ZbC8-hv=vRK& z1V+e2FW!TCfu#6ShXRAd(JdPC?&XY?s1nz?^QM~$mvH@0b4?2rIwr$J4MXNJLe}wQ z{FllQS?8j-tjgk*PT`>wa~0qn;<&DY2te*6fco95RM^Px$jm3xEq>OH71XX2*fQ@> zyNs&t2`#-(FdtWbc5m&)ru}tH)qjxBC*y!1!V5Vb70nd(Iuyn7iof-sk?jHCZ)7*0 zUm5=VXS6(B7^X5|RJCDY-R;G`aOlR5IeWUC8PPsVSQys-@l9A!nf7aE@BhsLC_BF* z^j6u{IN$XlNM?w$vsfTBO|h_d{J3Gsp0kvkroHe<;FhorIA;#lX29S0jSohVw(`$p zpc~~6uWia|(enS5=Dd`~M$*{8qs%D~H^5skg`hVtwJ#8W|G+B&sV?X^&Z^1H+n#HE zzH;ff=m3@T^1Iv#HAct@b<1gHI%BA*h3q~<(z~y0l$8eYY{L4)DzfwX=6rduTXwD( z5>CDPBn*7f)W4C)FOh+wjNAGS0*e|~&KDLBxoTeGzHak-E`d(DA*%wFLaDJXLC&Gy zyUTlO{;alLp p%>IY|C96$VhiCPi*Xw&qU{ at!*c6MmOEbx(aI z$XA$ElC#QaUna6FuO6HLyVRZPMJsqj*`K3HSZz>ODcl%-$!=0tvS!Y(47Pao=qecF z?Rd)PyA%Os^MR kX*`-Lpm5Cx9XXt%_y z-&KtXdAk3gI#2ld!E 1&Ohv3VB7_)+$VUu~g z6wkC?ofDdmTXoH*2S0|+5!e1x8pxlVPFK6dNFh!dm@_zM?jmR}esg!f3*!MluWR;~ zff;+d-z3)9Ce0^5mLDvjQ(nj^PAni(Em0lnjQ5ToBk$it^fDYb`?irM-B1ozK4K4f z%$QzB2`R}YWNpV9Z4CUYKd6kHCQ~#sq9O{o!UqO?G)0%%`|13Tik=GrM|D0VJP(pX zs|njh&oN&zjP`?yo{zYYg$fhsDVfvuF)=B$!82_B%BSxM?=sybD?Nu!@KZDgtlsz3 zn04Ao^SU#irEIoA IEClMvZG%(ds?kMbPfgxOm)B?q4sFJhn!TJ5CjHzBoH0I_wdl zLC#%->=H7wzGP@*XYA~Z*j(M=^l3Z ;!D;DZ+;E%2q`Tk7(~%vrqgwdGyFR*9PH*%$Z_< zb&KMVX)h%et%}FC{eBBXPM}%aU5=h0xo7S*R_eVe#gO$VEXs-^6@K~pBg@_edp9iD zl6qY`ZWLOjf>z$;yexG<1vxskVTR&l4^^!OI&WATLtiG1m$bZ(;;8}_sJ6x?l>ptC z9WINuH%0bgWiOY7OlHMh<_AMWO7nVdTuxZP<*HGl{wfmo+7`z!D31Jc*^f}{c^o3& ze!5k;o{sg2nWa}ztx}${sj7Q9Vz#cB?la#T;P}xHdH%dHGE<#YhifTND#mZ@ST%f5 zXJCXV5>WCnqyly!#3>)tlUT4)i5%P@E5sx&t2#g<2Tq~IlR{MA`aq$ &Z{bC#Lx)i>Z>ZjfHuX~cE^&O83wYsL2wwS>Jhy=3i% z?rQG&phzKyl^VX|aAaZHZrt&Hf>rx`oH}}QZH(+F5rd9|XG`9nWjEYTjnW$nFey9) zPUZP&DNu)RiZ3tMFu&7^Tb^hv2^^?4V__#{TvYEbW!D7(iGufWl?FWYq?>1@k4aUS zf&+wDDJSD{5DWE;^l8V`i4zk& T8!FAF8y2A zTy5ZR`oz|H->6mEcl5x(Im6T!0up) -*G_Xtl6UvqL^*xNUW%W7w)+yqnx|McOp_8o8-ukeQ`# zjKv|Q!{b#ArJhI5F@-n9xHcLs!e}77aDzKpS7I{iJeFJ=if4SSclX$@#32s7!L3&W z xD} zfFJ|zL?2aWc*|bm7b90=N(6W(e^fvv+sDBT#@uJfxzqL_v!WtzDKFh6Ah#S6#iCYu z#Mrgv<^W51-oy{&YAG>5znZX@K$aQ#RGU(HOgvN|@3Xw~>k3dFy DHHVVA z0CmGe0Kxz(h1d-&cR>$DK$!o-m5Zo9$qT3E{(S9-$u5Fq<6w-Igft<|X);{oGnU26 zSWt?wHwqW_)glS`_QWn^w(TA;8p|)j6GEX~szt)U*ed+aq@XayZ7?ROCTsUOFd}c% z**3(! MWmAqWmI6s*@OfcUkf3jzv3B%>r}?yH zS?LX40LFBi7@B$CgkqYkgAA>+f5E6FMHAxV^t(xc%nvDw=XBjzhvxkFTP z(H5SJziV=~j=LT+SDh=JK3g5Deg7zf)qbgtNC{u>X}pow0r%g$0S?nC&`w8DZNmSq zKfI{1u0o!&Oei?1pDvo-e?1ebAYo7ic{)7BBu(srrRsXgLV97j= TE|!& iB1D+ SLLN9vP4U0<)Xc_yZ(oBtsd-7FW5`i;8T7COfM>vx+t*O&1PU9_AeWEC~j zCynj_#Qt61ICUVBh`wAM%Wv!GfkS-8U5(5fP^k)+4Xx+Vw4O)u(um70=^E?z;HZ%7 z;MW0OY3pv5{TvN~W5s8G1bHMWM7;%!5)?>j9a;fX4n;ykiaTvtK?e{NiizdJelf68 z#q4JVb-T$(@BDNDaAMw%t$G`={>|tvT|mIDOgrW~{3X1Z<#SRHPiRpmIR4acZt~+G z#l~6kB#xqZ!M<*bd%CnwMy)nTOsr8n2hDz6FOSzVkgxkN@=^#^5EAI{lTxm|sOR$E zHGFcMa*2ZF*9?8bV~6ADX=GcV`o=T46@{pbRqM!jCf`V16mE%1VINE;;WuPO1+`Eg z3q}?s)9If*V3V#knQAOMJcZ*Oy1)<%z0g`>TbAU~(0wFsLV{AI@w^vIUw) c-uB=xu# m*6`}iFDqLo82GyWFuS42Eo4;-Bj_O@nq(NvxSGU6 z?z^k^eG(F=;#~+27f{7;(0?D}Kslj?#va0O-Z1=pe;(Bzi=|&SC=5iS%D7`344!Pp z$P{Mu*L14VJBj@KpPOq6HBnayes3w!9cu({GJ?DN1_rnVIBdRpZjF@KXqGQ3 A}(CMHt;pqbR}WNvtv&EfM8$>8l6@H!KsKC1V7^qT+qVOx zN46qD7j7{gm-qdT5y zgTz`qdTKARtJ)1zu64D(+J15-Z4AEV-8+sO>Cu;%(f`@rR%^GNb_IZ{!fWePkod;q zbZw#O v1XBW+&$*j9?FZ%c*QIT*Rbrz_||E5}`K znfclN<=!2pa-}mUxB26$R4u~XVIn2IFSn9mSqtYMm@ih!Ekqvi)It$FOFUnzuo5fV zbAPclv3vb`o#}Vpzri$aHg6<|+FKk+{QH%M;B2*U3gPy9A%%OhEnUYq&SMoaM+~c$ zXU1K##@-~`8}D4IF;#W5szaR*Aj6PY&4hyCLsxwdb#Mmtx71H#6gz#HYa`<%Xx8ke zM-L;}CR1wS@-lfcutAa~m;#ELJB+8hUb_$%7YX)Y%5tUrm)aM5%qC)b4EC_HtxUk0 zFf<`q&xU5P5UddR;E=z#-g}a#JaPbs*PgI9SbM-?wNI1T*1K@T^683vGuOZM#dn4% zQL(m$fvc+2(h7n(2I^9kIJApxl)h0KeTixpV)`!}BTV7WDYdL{-0n(-rWn (41&BYrH{k4vV}$LePWG@Bw=Il#0&${k? gj05Gn1(1c#bL;yqqxERWfA8B zc+i}vj@a|1q&Zt4YWbYmchBm584Kn;6eMy~{U%B*+gXnUEoN(zEazzKl%c(zXzWgw zMu{Rfu(jN7(Wf&RS}GIp4m(TeIzXqwrw0ou3wgQZ;%Rj&;=xHx#VdYjn>bCKlBZ8E z`9SL`HThp_R02V#J5=9EaMcE1rTj|NDTSph3#2tGREro7)@;8z^@;C#7FRaF@VSV| z^FewN@zQ%?PTj*kUZ~E*Cq{~;H+mv~KNk ZGUeG`Bv@1It6rljsjITYxOCGo?w`zD2fHsy)Q>U#{w zyOGiFt5&P`IO!EoR(1h1JwpOh<99_OZ3gEE)lde_v~TztuJKfkO(c#Zra?e*^|qGw zMc^xIC#<=ljN^w&r#hgeAS4@`>(yG_!LbuTjnXkcgA!fLAZmgGG1zI)r%LY6F2NJ1 zB!@0O?)8=~J4FG}i@Z;e*yY~sI8mJ{c>qsfFbl?D>XapZk8#P6&N$p->+t%&y3#(m z-)bKFLzBaJ45H&F>aH9jURwA_FQbz|lW6op>L8y>)F>z-Y_#1m<9@qSZn=m{bd?ii zhQqD^79?fLx*P1VVkW^C;lT$8W?)2n4ZPo-`yQA0QxNa1td{$smW9**Y}Vp&T{>v5 zkXpmIvwxuwIhaqjiqP9zykSfNS_o(!bC@-5?Y*a%`DzrIay4H!Ax19C8Q6XVcyGGP z0G6@dZ_KhU4AuNiV&YGJpH}Hroc;69QDYku#Xxl3Oy~xKEd9mWgKH5F8NZp0o>#l= zmJ|?vasFg&3ql7h*?`+ue`;5>x)HT+4i@~ukY)TBVoPP9uP-ehPK;sPc_qj8n(VMq zIJs)-yvL7=dn>-~Z`8phK|FxeeLxcRudVwu0@%d4aC|OosPoVFJAz(w$i%Fjm&Z$K z;Ei|N`0s#Dk6oEs1)do=YFGpoR> SPKqQ>+6z3rkml`wB)_HX;uzm_-IN3p_f zXAR~lCD^^YDeJT0Gg{&UNq9N^jJgRT)zg{$MykLq*xXoEZoGkOq4yco2 zHAOh%*ld(y7%V`{XbL5#suh>OVRdF8bqy0_^E&**e=qP*8M~%Y(yyfCa}1pw$AG z_c!4QQFqLAx6A9`PdXy~3qHGC9p@@ #-iPInUUXaVgCgK zrO(LF&p(_HemI~isdtX86>PPf(e)IW8+2-`l3LIbfk`54sonR-!AFt?;8?qHR(Etb zsy44cI`|=4Frrv5iDnb)b_j74S`p>TCpVR}AHaR?swYEd6sEg#gd1zuq@r9>z^8`x z&{9sRMvmw~DckSx{&TvDHq3?}=(O9a4ME64A(;rZDMqKK!(I_)AhBbB!sK(^tKWh) z!@>`OZ*q7Agaf~HQRJDt@e5vHm@U>dRB c5+nP-*oHTZSTv3Dc^jSGrwd%}bQgZwXH4 zhlM>lr-??4!C%DAO*dM`+4>}rh^Xr3Q^>ufHOn02lfd#!w;yKinEv^%+m(4Y3lQfy zABf53?Z-t1wQa&~{Gj$Xfq$Dmn `=&wsv> z5fBj$*$*qSf#obxcZjoIXxU{BQ3XUwAAdW|=+x~B5t@uBAOcA-&ek^NLcZn_tYdv_ z6JwOqm*@7#*|(tnZgmqK`;#!W`M5|jx|T9auoOpRCRPl7LgS!!5BYFA3^xzQHNIvS zu2z<>3X$0`A{V)bD?_;+0i2f<8}{2eh!ICyC#BV8U+apy7t8zT76q{0e?%-eIouX$ z*!=`rd-_Xwoto<%vwcpgoNiG8v9ayH_aEZE@N736m+cIK9o_(T1Pa-h|A?~w{5{eW zp&H)syNH~vWgfolA;?=z`P1^#1Kh8XF4F3ZlhUnvzGw2DGZe8F=~!_EvHzV9<_OHp zAJ$0No9X)d=3vuxZ~X#GaK64>Y_&d~nJXmDjh#Ti7=o=yN6%Pk*4QcU^A#rvtgDn` zW$KmPx$A-tC`2pSI&6=RQEwY4e4dPs#M?mpZ62Q!cIAB~)UScc2> CBCZBITmvjl-7CAsuBfV!4<{rNCl{(CULz2R4uo3 z43uiHnX4tab#zdIrZ9qsK4`(%(o$lpw>`qnYr&u}i+x8v1XW6t91Eeb%*d1C%GQ!o z*6N$1Vdy69=ND--OnItQ7ofA_XRu6S%jZP`X2)w0`%1yI)h^%mh)%U5mtFYMGcxx6 zq}M}x$CM3YUM&H42_y?9rp`}J#-5kgLXU&&pZ(M``aj%b?CXYdBR_AFq01s7?cnR$ z9#pddwU6MP>}JiADAa98Nm_En{u?eZxWhSNMzIDBKkYi!e0agTn1p!E*n2^N2)Izv zOoL9SV7QjLSM$2^dhhrsalXk7Nwe;VuTJm?86+gX9kE$j4er4zQ&fz*N6$`Tn3UNs zJHB&ULXSZX?z#5ni=(~Z@Whm+Omc0f1sPJU5*L*)RDz=5PQHq#Kq7*eDC0Tdv0H)B zNoSo$*;egDnV?A0L*^t@m}m|?fln|D3PQcFHH@55^SXxYK}=N<>NDeL1ZT1!{H}Ag zir ts=4?vv>{Xx%2savv^;03~wQw--Y~;`Gsmo zKg7h=G`MKahRd^Z6HL~b;RTzcnWUekT-QtFT!r1o^JUYsv^3P3H=BhE$BxD90F?Aw zH~MCUl86~z?POM8pE9GGvI8aniBn7#D=9JAu{K A=Pc#LRcH}($> zLBG8=3COP^j=V3IG-7V+g@bLmC!QkD&lZF(*n2RuNYa0`g}P7fMH-wpg~*@+y-9@t z7SCh(*(jUSA=|u4Rc+suNc!TlTywgd!CVUg6BVO~=o^d2yB$^%uo2frkl};X)6?<| z+^Nsu)j|s*k-|+)WX0ej7;6s}q6i(gLnhy0E(+U)C(GV2*Z_o*T76&5$GVTHn2$qc zNZu)Y@4G*BcP$^rbw6OU8G2`R;0Q=qA+)MVI%V5u0HvXmM{(}$4`#urfMKp+oZ>w! zWW^6luoW2Uavcl+d=Pa2JC3utDvqWh0;gg|5I(#bMq;rh6FwB-i)W4V1YPDsGK*q? z<>-7#g9H&{YoWsh(L6>C)@D`GYRbeK6QAk_s}$rnzY~$G-Xzt6rlUR{8;kc6Gb3No zY`?9xv#_%{KmD~yqUW# 3aJUYGCy-JevfbU|x59@`6NN1dKTnVrpd z`P3)j=$F2 mb+5 zR1 DJX>T-Q;s5X)zwygVLuKwE#s^SK CWn%I*DITY&K|i5m4*rN8k}s~CSkodI7uI+nR` zC0lK)7#anMb{dC3v&bz;mfx10$K_7-dg19WxeSki6o-Yi07p>!w7EZU8WtG96FPAO zaB_1VOCL0A42b*M^OAQ!A6dmwNDoW#z+>l8fsZbtbbYX8#P0iM5Mc5-l|V&S>&pYu zCswFg8UQlfGK;c%kyOzGgSg*dPQC7}B~x5~h90m9h^ond%P-?2cFm|@6CocwSW%_< zkV8MMNBEDqh9$8@_}E5qvxut*ezQG{l^Hu2AsH^6s|VaN$VDB;glJx>GM8@9CD+a) zV@C%tfD@{mr&N0UhWjliKN9|fZc&4&cO|2if}IKhfMz#sWX9Y{PIV#ti b6dwHL zo(mXyTP`l4s8Of~!7D%Cl|r_s&&y@ZE7o75S%+n%?a8g@y`ODP3?c;s1}^+;B9lvP zNF7P+9VkNlEshJ*W8%G+_;TB9lsB6tp)PJv3#JBBz*(HK&5g)a;&go9M!bzcRF}J| zMngccjhAnEgP~?<7$gqDLuJOZjLTA=?v6VAv>of(?h4U}ZX`BCFcy;HRxA9M1Ib?0 zjAL?cd>h>Of=lF_Xr>sdXw+QO({H_*&;q?dr?6q^`pK?gB7%t{=fcnf1tt=YT*^4^ z7+pob?NlqlK6NfxD}{hS&)67*X|9|r5S@fm)o2?AET`#K|EzBt#fa=9Rgzv%CFLO^ z|G0rhg yV*4|kIR1VS?lde=-u=}uqlb)$S7@V z4ciaH4~}y+P=M<|tTwUPq1lj=nj4i7L3iEW+h0R}!Ti`#iq#36GKHrc^;pvuhUv8L z6HgF sLOiK?Yu`%U{;vC$#L=du0gJK z(bNvxa4$S--$5~fK0<~#vRmCkg8sT#OjQ(z!uSPWKZIAZ3eUotuYqI*V|sjwdt~#0 zJjP~S*cxuu5rNw k8+*s-+0P z0yiivEvJB6G`5Q504zgD48{dYhgwY9&Y%kwssBA@`)O0>X_02s?rxsJ8=9|?!Okfv zs=}5U*%6&2c7WLS_flVs03J3mQAf6<-XcK`{K1JR{im{^os;hqhVKPLL+JI-c^q*E ztnIn;Y&$W<)Un5=!_1*+S+cuC&&C};{)0UkEv+(VbJ2dBnZSU? W=udg}{`c@z~SUN2{NH8hnHfb0pMt#v03 z?z9hJVB|BR&wlPQ9BdE*hz|S^I8aw_ lhWYsdZnKGPMy{)x5U4 ~0`GkL56Is8Sq?t*#Ofw)W!vyVvFpEHyYJ6xP6sQV3_gUXg1~cWl;@UpBiBuv zSh^?5Y_`Jh?;Z$ o~DQN8?-d zg%vNZN{WRdmbryuvq2_q6Pgy4MuqY533A!Us71`8Q7Yq?D#Us+2ulOcCv+QxQX+%| z0fw# =^V>vNG84
kxXl_u zX_%&k?}vmzfMFU7Kq6Znl$sF4lPT(r8g?uJQWE$+Zo{QktuZq-LA_EYkxUVbMG0>7 zKt~`jbq!yJ7`jPjn?ob?89VVUem-`DgCF?{`ToJRPv)97{MRn)qO&FZnwo0{gIjef z*kB+C1CM%XmUy~nNeY@M)~JU@xp2ei;;x MJ7?$-J%v$}Zj}2sBnV^_dE5d5 zujwLV4w|lzErvP`hkP#2?A$cvQi*J)A4F@1-`@SV4ZQ6;Bw8`a?bF6pZ@5wdC8LU= z0w Xi!hTA5nIMVp@|lgVJ)CWc`WN{I|Zq?E*B4q@O^nk!)FIx{m< zG#h2g#aT>EA*I5xW294Qqzo|)D;l!|Q`Zooq~So`Owp6wL(p)!a_Ema>uhJs9S<|O zY3cOW#mNbju9NTYAa&)UPHZs=Lq`?f|L+^uy?w!8_3EK+jX;J0_0lY{bkCB^0*gQ} zw=58J4Ftk4 zN6iU}#S+`LZKqLt4?7W~stMjYF-9`Ki{Y)?nIC_TgptCo2l$mLQdgi$@ZE@0M@8AT zgivS-glwIVgo-kYsdjQ0KQc6{khU#fDAmf`75V&|LSUOFP1nV7%(nXuD1mL* zsxF@6MsBOEHdqL75-o6u0Aj)9y8sl?J#5E?2~D9Xg^~e5QzA4$E|(*h%@BkEzUR_t z)NwtJFboiy7Nwe0D)I!Xg;b04%uG#US`NP7#Ibb-2L~w5&EN-;EnA19GlYr;5*d;s z_ft*R(1j!j6q>H1B^@^9Ov0eZ)QLZ3^l%?mY8wMXBOs!P?9$vEB9QER;QrN3HS1m6 zIs=5;4-8g+D(I%2K+2GMd6sx;>9s{SOycPt>dOE@S3n>-87tm6{0=e4X_0Y#u;lc+ zum20+cUD)cb27O031B$@2m}9yXuVpwT>t=}Tq?6=Z$DQiYuND~-g^5K2Os=6m(HEV zj>l*=8}uf6D9_E{c})ThY{w>Wn}mUn-qMqctKS@{2>l@XUIU0yFp35L(dZ FNTmdhog(lxYPBl55oP?kMyJ{uM6~&Dc?T^FidH{S|00SE zi^^#dp+yGjC>B6q8YZS?5zk~n*YGMODy0%KR7fRJL4fahXu8fF`ww6lCbepr>8S|{ zb2C_m#qK@3v2B}rqd}w5AeBmDnl^z9BNkEtrqWSDi!xLO0f7v$Oq)$Z18fGGwKEh) zkD`erg^79GO?UFqPk*+%&%&x@ lc EI-Q8Tcl;)rh)Cj;R4AcEyKfQs=ZC)E^3x9y zQjhfVSMS){^v&&!yi%Y=QN*rWr&+hL94qoTYU}znK{}nLTCGv36iFtN7`jP|)S<;i zq%F+*;@_ lCJ@7{7d( zQlZF}kzsQAB(7V-bzLNaO07XCL-N@ire&k_kRS{RRck=4Q;NXA4;4cCgv!OX6x+9? zsgwfd)aLa8fY!e6Yj5IOS^u8-h70Y6oC z0&sEl{aQk`tuzptwy4sJT!s)r;WwK!%H@dWLDMiz6Vr?W(^_kNtEmVyyk-->>EhPv zxV0+fa+$j8(l^jgrYDaOvNd#p-qHup6$%)dBBm#>;u^YbM8RaCYN^ja7p;E-LRbjX zW^As`=_!kkfBCCxo&AN|px%FPmU^^1HwC<}!rI=Go2w$aL2nyuCs+i6r9BVZ#FSTi z4Rr+s9LM6_WAE}m{SW^=s>2j$w}brdzx?MJ;M=Uy6;wB@4l{y@ Pi`aXUjv9yRXI@;8$h}5$c58!(N zfgeUI?=`>aDsLXt0%dd5Z rTr9|wqPiYXeB^54IJU%dmfEOok}%In1fVNwlY*??3Ph}1YKz8 zdcklSn2>B$G6o9=fhT6Bwq6RFFs~n3 aN>xeO4b z^3=-(Ky?QMY}@46sT0)BjFGXNRxr)&Ek8W|k`8 -2KrnbI+D-tDN{7Ne3P?D_z^*)4|PC5#2%{sN4VuOq*CL zN25~c4hXcfI(=pMAiLu^ye_&oZlL^Y;M1$AplSNDyZZNwlgutl1+i!YSpRh2QvLr8 z0O0B?`AmjOm#0W)7b8|n^$MD9MG>x^N3+?$mjPMF0ij2!A6vSAB_$GpCM8mc$iRw5 zrBWrGsz!Q$p|iL}C(`p@ hr zY=C!OeV)Skvsfnd^yUbKj^_m!P8uUV%>HM-&d}y<@0+ 3z@cg+aAdH~pX_0Lk@CI@;r{+B;vC?*&5@0v0YXf%DFHq~Gvk;I9|qgIqa*Q2zL zp&zio712`lC