初步完成面板查询

This commit is contained in:
qwerdvd 2023-05-13 11:57:21 +08:00
parent 2da65b6992
commit a71f476773
20 changed files with 3697 additions and 16 deletions

View File

@ -13,10 +13,6 @@ from ..utils.convert import get_uid
from ..utils.error_reply import UID_HINT from ..utils.error_reply import UID_HINT
from ..utils.image.convert import convert_img from ..utils.image.convert import convert_img
from .draw_char_img import draw_char_info_img from .draw_char_img import draw_char_info_img
# from ..utils.map.GS_MAP_PATH import alias_data
# from .draw_char_rank import draw_cahrcard_list
# from .get_enka_img import draw_enka_img, get_full_char
from ..utils.resource.RESOURCE_PATH import TEMP_PATH from ..utils.resource.RESOURCE_PATH import TEMP_PATH
sv_char_info_config = SV('sr面板设置', pm=2) sv_char_info_config = SV('sr面板设置', pm=2)

View File

@ -1,12 +1,80 @@
import re import re
import json import json
from pathlib import Path
from typing import Dict, Union, Optional from typing import Dict, Union, Optional
from mpmath import mp, nstr
from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import CHAR_HINT from gsuid_core.utils.error_reply import CHAR_HINT
from gsuid_core.utils.image.convert import convert_img
from gsuid_core.utils.image.image_tools import draw_text_by_line
from .mono.Character import Character from .mono.Character import Character
from ..utils.resource.RESOURCE_PATH import PLAYER_PATH from ..utils.map.SR_MAP_PATH import RelicId2Rarity
from ..utils.excel.read_excel import light_cone_ranks
from ..utils.map.name_covert import name_to_avatar_id, alias_to_char_name from ..utils.map.name_covert import name_to_avatar_id, alias_to_char_name
from ..utils.resource.RESOURCE_PATH import (
RELIC_PATH,
SKILL_PATH,
PLAYER_PATH,
WEAPON_PATH,
CHAR_PORTRAIT,
)
from ..utils.fonts.starrail_fonts import (
sr_font_20,
sr_font_23,
sr_font_24,
sr_font_26,
sr_font_28,
sr_font_34,
sr_font_38,
)
mp.dps = 14
TEXT_PATH = Path(__file__).parent / 'texture2D'
bg_img = Image.open(TEXT_PATH / "bg.png")
white_color = (213, 213, 213)
NUM_MAP = {
0: '',
1: '',
2: '',
3: '',
4: '',
5: '',
6: '',
}
RANK_MAP = {
1: '_rank1.png',
2: '_rank2.png',
3: '_ultimate.png',
4: '_rank4.png',
5: '_skill.png',
6: '_rank6.png',
}
skill_type_map = {
'Normal': ('普攻', 'basic_atk'),
'BPSkill': ('战技', 'skill'),
'Ultra': ('终结技', 'ultimate'),
'': ('天赋', 'talent'),
'MazeNormal': 'dev_连携',
'Maze': ('秘技', 'technique'),
}
RELIC_POS = {
'1': (26, 1162),
'2': (367, 1162),
'3': (700, 1162),
'4': (26, 1593),
'5': (367, 1593),
'6': (700, 1593),
}
async def draw_char_info_img(raw_mes: str, sr_uid: str, url: Optional[str]): async def draw_char_info_img(raw_mes: str, sr_uid: str, url: Optional[str]):
@ -14,8 +82,396 @@ async def draw_char_info_img(raw_mes: str, sr_uid: str, url: Optional[str]):
char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', raw_mes)) char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', raw_mes))
char_data = await get_char_data(sr_uid, char_name) char_data = await get_char_data(sr_uid, char_name)
print(char_data) char = await cal_char_info(char_data)
await cal_char_info(char_data)
# 放角色立绘
char_info = bg_img.copy()
char_img = Image.open(CHAR_PORTRAIT / f'{char.char_id}.png').resize(
(1050, 1050)
)
char_info.paste(char_img, (-140, -100), char_img)
# 放属性图标
attr_img = Image.open(TEXT_PATH / f'IconAttribute{char.char_element}.png')
char_info.paste(attr_img, (580, 131), attr_img)
# 放角色名
char_img_draw = ImageDraw.Draw(char_info)
char_img_draw.text(
(690, 175), char.char_name, white_color, sr_font_38, 'mm'
)
# 放等级
char_img_draw.text(
(765, 183), f'LV.{str(char.char_level)}', white_color, sr_font_20, 'mm'
)
# 放星级
rarity_img = Image.open(
TEXT_PATH / f'LightCore_Rarity{char.char_rarity}.png'
).resize((306, 72))
char_info.paste(rarity_img, (540, 198), rarity_img)
# 放命座
rank_img = Image.open(TEXT_PATH / 'ImgNewBg.png')
rank_img_draw = ImageDraw.Draw(rank_img)
rank_img_draw.text(
(70, 44), f'{NUM_MAP[char.char_rank]}', white_color, sr_font_28, 'mm'
)
char_info.paste(rank_img, (772, 190), rank_img)
# 放属性列表
attr_bg = Image.open(TEXT_PATH / 'attr_bg.png')
attr_bg_draw = ImageDraw.Draw(attr_bg)
# 生命值
hp = mp.mpf(char.base_attributes.get('hp'))
add_hp = mp.mpf(
char.add_attr['HPDelta'] if char.add_attr.get('HPDelta') else 0
) + hp * mp.mpf(
char.add_attr['HPAddedRatio']
if char.add_attr.get('HPAddedRatio')
else 0
)
hp = int(mp.floor(hp))
add_hp = int(mp.floor(add_hp))
attr_bg_draw.text(
(500, 31), f'{hp + add_hp} (+{add_hp})', white_color, sr_font_26, 'rm'
)
# 攻击力
attack = mp.mpf(char.base_attributes['attack'])
add_attack = mp.mpf(
char.add_attr['AttackDelta'] if char.add_attr.get('AttackDelta') else 0
) + attack * mp.mpf(
char.add_attr['AttackAddedRatio']
if char.add_attr.get('AttackAddedRatio')
else 0
)
atk = int(mp.floor(attack))
add_attack = int(mp.floor(add_attack))
attr_bg_draw.text(
(500, 31 + 48),
f'{atk + add_attack} (+{add_attack})',
white_color,
sr_font_26,
'rm',
)
# 防御力
defence = mp.mpf(char.base_attributes['defence'])
add_defence = mp.mpf(
char.add_attr.get('DefenceDelta')
if char.add_attr.get('DefenceDelta')
else 0
) + defence * mp.mpf(
char.add_attr.get('DefenceAddedRatio')
if char.add_attr.get('DefenceAddedRatio')
else 0
)
defence = int(mp.floor(defence))
add_defence = int(mp.floor(add_defence))
attr_bg_draw.text(
(500, 31 + 48 * 2),
f'{defence + add_defence} (+{add_defence})',
white_color,
sr_font_26,
'rm',
)
# 速度
speed = mp.mpf(char.base_attributes['speed'])
add_speed = mp.mpf(
char.add_attr['SpeedDelta'] if char.add_attr.get('SpeedDelta') else 0
)
speed = int(mp.floor(speed))
add_speed = int(mp.floor(add_speed))
attr_bg_draw.text(
(500, 31 + 48 * 3),
f'{speed + add_speed} (+{add_speed})',
white_color,
sr_font_26,
'rm',
)
# 暴击率
critical_chance = mp.mpf(char.base_attributes['CriticalChance'])
critical_chance_base = mp.mpf(
char.add_attr['CriticalChanceBase']
if char.add_attr.get('CriticalChanceBase')
else 0
)
critical_chance = (critical_chance + critical_chance_base) * 100
critical_chance = nstr(critical_chance, 3)
attr_bg_draw.text(
(500, 31 + 48 * 4),
f'{critical_chance}%',
white_color,
sr_font_26,
'rm',
)
# 暴击伤害
critical_damage = mp.mpf(char.base_attributes['CriticalDamage'])
critical_damage_base = mp.mpf(
char.add_attr['CriticalDamageBase']
if char.add_attr.get('CriticalDamageBase')
else 0
)
critical_damage = (critical_damage + critical_damage_base) * 100
critical_damage = nstr(critical_damage, 4)
attr_bg_draw.text(
(500, 31 + 48 * 5),
f'{critical_damage}%',
white_color,
sr_font_26,
'rm',
)
# 效果命中
status_probability_base = (
mp.mpf(
char.add_attr.get('StatusProbabilityBase')
if char.add_attr.get('StatusProbabilityBase')
else 0
)
* 100
)
status_probability = nstr(status_probability_base, 3)
attr_bg_draw.text(
(500, 31 + 48 * 6),
f'{status_probability}%',
white_color,
sr_font_26,
'rm',
)
# 效果抵抗
status_resistance_base = (
mp.mpf(
char.add_attr['StatusResistanceBase']
if char.add_attr.get('StatusResistanceBase')
else 0
)
* 100
)
status_resistance = nstr(status_resistance_base, 3)
attr_bg_draw.text(
(500, 31 + 48 * 7),
f'{status_resistance}%',
white_color,
sr_font_26,
'rm',
)
char_info.paste(attr_bg, (517, 265), attr_bg)
# 命座
lock_img = Image.open(TEXT_PATH / 'icon_lock.png').resize((50, 50))
for rank in range(0, 6):
rank_bg = Image.open(TEXT_PATH / 'mz_bg.png')
if rank < char.char_rank:
rank_img = Image.open(
SKILL_PATH / f'{char.char_id}{RANK_MAP[rank + 1]}'
).resize((50, 50))
rank_bg.paste(rank_img, (19, 19), rank_img)
char_info.paste(rank_bg, (20 + rank * 80, 630), rank_bg)
else:
rank_img = Image.open(
SKILL_PATH / f'{char.char_id}{RANK_MAP[rank + 1]}'
).resize((50, 50))
rank_bg.paste(rank_img, (19, 19), rank_img)
rank_bg.paste(lock_img, (19, 19), lock_img)
char_info.paste(rank_bg, (20 + rank * 80, 630), rank_bg)
# 技能
skill_bg = Image.open(TEXT_PATH / 'skill_bg.png')
i = 0
for skill in char.char_skill:
skill_attr_img = Image.open(TEXT_PATH / 'skill_attr4.png')
skill_panel_img = Image.open(TEXT_PATH / 'skill_panel.png')
skill_img = Image.open(
SKILL_PATH / f'{char.char_id}_'
f'{skill_type_map[skill["skillAttackType"]][1]}.png'
).resize((55, 55))
skill_panel_img.paste(skill_img, (18, 15), skill_img)
skill_panel_img.paste(skill_attr_img, (80, 10), skill_attr_img)
skill_panel_img_draw = ImageDraw.Draw(skill_panel_img)
skill_panel_img_draw.text(
(108, 25),
f'{skill_type_map[skill["skillAttackType"]][0]}',
white_color,
sr_font_26,
'lm',
)
skill_panel_img_draw.text(
(89, 55),
f'Lv.{skill["skillLevel"]}',
white_color,
sr_font_26,
'lm',
)
skill_panel_img_draw.text(
(60, 88),
f'{skill["skillName"]}',
(105, 105, 105),
sr_font_20,
'lm',
)
skill_bg.paste(skill_panel_img, (50 + 187 * i, 35), skill_panel_img)
i += 1
char_info.paste(skill_bg, (0, 710), skill_bg)
# 武器
weapon_bg = Image.open(TEXT_PATH / 'weapon_bg.png')
weapon_id = char.equipment['equipmentID']
weapon_img = Image.open(WEAPON_PATH / f'{weapon_id}.png').resize(
(240, 240)
)
weapon_bg.paste(weapon_img, (-10, 50), weapon_img)
weapon_bg_draw = ImageDraw.Draw(weapon_bg)
weapon_bg_draw.text(
(370, 47),
f'{char.equipment["equipmentName"]}',
white_color,
sr_font_34,
'mm',
)
weapon_bg_draw.text(
(536, 47),
f'{NUM_MAP[char.equipment["equipmentRank"]]}',
white_color,
sr_font_28,
'mm',
)
rarity_img = Image.open(
TEXT_PATH / f'LightCore_Rarity{char.equipment["equipmentRank"]}.png'
).resize((306, 72))
weapon_bg.paste(rarity_img, (160, 55), rarity_img)
weapon_bg_draw.text(
(430, 90),
f'Lv.{char.equipment["equipmentLevel"]}',
white_color,
sr_font_28,
'mm',
)
# 武器技能
desc = light_cone_ranks[str(char.equipment['equipmentID'])]['desc']
desc_params = light_cone_ranks[str(char.equipment['equipmentID'])][
'params'
][char.equipment['equipmentRank']]
for i in range(0, len(desc_params)):
desc = desc.replace(f'#{i + 1}[i]%', f'{str(desc_params[i] * 100)}%')
for i in range(0, len(desc_params)):
desc = desc.replace(f'#{i + 1}[i]', str(desc_params[i]))
draw_text_by_line(weapon_bg, (220, 115), desc, sr_font_24, '#F9F9F9', 372)
char_info.paste(weapon_bg, (22, 870), weapon_bg)
# 遗器
weapon_rank_bg = Image.open(TEXT_PATH / 'rank_bg.png')
char_info.paste(weapon_rank_bg, (690, 880), weapon_rank_bg)
for relic in char.char_relic:
relic_img = Image.open(TEXT_PATH / 'yq_bg3.png')
if str(relic["SetId"])[0] == '3':
relic_piece_img = Image.open(
RELIC_PATH / f'{relic["SetId"]}_{relic["Type"] - 5}.png'
)
else:
relic_piece_img = Image.open(
RELIC_PATH / f'{relic["SetId"]}_{relic["Type"] - 1}.png'
)
relic_piece_new_img = relic_piece_img.resize(
(105, 105), Image.Resampling.LANCZOS
).convert("RGBA")
relic_img.paste(relic_piece_new_img, (200, 90), relic_piece_new_img)
rarity_img = Image.open(
TEXT_PATH
/ f'LightCore_Rarity{RelicId2Rarity[str(relic["relicId"])]}.png'
).resize((200, 48))
relic_img.paste(rarity_img, (-20, 80), rarity_img)
relic_img_draw = ImageDraw.Draw(relic_img)
# if len(relic['name']) <= 5:
# main_name = relic['relicName']
# else:
# main_name = (
# relic['relicName'][:2] + relic['relicName'][4:]
# )
if len(relic['name']) <= 5:
main_name = relic['name']
else:
main_name = relic['name'][:2] + relic['name'][4:]
relic_img_draw.text(
(30, 70),
main_name,
(255, 255, 255),
sr_font_34,
anchor='lm',
)
# 主属性
main_value = mp.mpf(relic['MainAffix']['Value'])
main_name: str = relic['MainAffix']['Name']
main_level: int = relic['Level']
if main_name in ['攻击力', '生命值', '防御力', '速度']:
mainValueStr = nstr(main_value, 3)
else:
mainValueStr = nstr(main_value * 100, 3) + '%'
mainNameNew = (
main_name.replace('百分比', '')
.replace('伤害加成', '伤加成')
.replace('属性伤害', '伤害')
)
relic_img_draw.text(
(35, 150),
mainNameNew,
(255, 255, 255),
sr_font_28,
anchor='lm',
)
relic_img_draw.text(
(35, 195),
'+{}'.format(mainValueStr),
(255, 255, 255),
sr_font_28,
anchor='lm',
)
relic_img_draw.text(
(230, 60),
'+{}'.format(str(main_level)),
(255, 255, 255),
sr_font_23,
anchor='mm',
)
# relicScore = 0
for index, i in enumerate(relic['SubAffixList']):
subName: str = i['Name']
subValue = mp.mpf(i['Value'])
if subName in ['攻击力', '生命值', '防御力', '速度']:
subValueStr = nstr(subValue, 3)
else:
subValueStr = nstr(subValue * 100, 3) + '%'
subNameStr = subName.replace('百分比', '').replace('元素', '')
# 副词条文字颜色
relic_color = (255, 255, 255)
relic_img_draw.text(
(47, 237 + index * 47),
'{}'.format(subNameStr),
relic_color,
sr_font_26,
anchor='lm',
)
relic_img_draw.text(
(290, 237 + index * 47),
'{}'.format(subValueStr),
relic_color,
sr_font_26,
anchor='rm',
)
char_info.paste(relic_img, RELIC_POS[str(relic["Type"])], relic_img)
# 发送图片
res = await convert_img(char_info)
logger.info('[sr面板]绘图已完成,等待发送!')
return res
async def cal_char_info(char_data: dict): async def cal_char_info(char_data: dict):
@ -23,6 +479,7 @@ async def cal_char_info(char_data: dict):
await char.get_equipment_info() await char.get_equipment_info()
await char.get_char_attribute_bonus() await char.get_char_attribute_bonus()
await char.get_relic_info() await char.get_relic_info()
return char
async def get_char_data( async def get_char_data(
@ -30,9 +487,7 @@ async def get_char_data(
) -> Union[Dict, str]: ) -> Union[Dict, str]:
player_path = PLAYER_PATH / str(sr_uid) player_path = PLAYER_PATH / str(sr_uid)
SELF_PATH = player_path / 'SELF' SELF_PATH = player_path / 'SELF'
print(char_name)
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
print(char_id)
if '开拓者' in char_name: if '开拓者' in char_name:
char_name = '开拓者' char_name = '开拓者'
else: else:

View File

@ -18,6 +18,7 @@ class Character:
self.char_id: str = card_prop['avatarId'] self.char_id: str = card_prop['avatarId']
self.char_name: str = card_prop['avatarName'] self.char_name: str = card_prop['avatarName']
self.char_rank = card_prop['rank'] if card_prop.get('rank') else 0 self.char_rank = card_prop['rank'] if card_prop.get('rank') else 0
self.char_rarity = card_prop['avatarRarity']
self.char_element = card_prop['avatarElement'] self.char_element = card_prop['avatarElement']
self.char_promotion = card_prop['avatarPromotion'] self.char_promotion = card_prop['avatarPromotion']
self.char_skill = card_prop['avatarSkill'] self.char_skill = card_prop['avatarSkill']
@ -81,7 +82,6 @@ class Character:
# 计算圣遗物效果 # 计算圣遗物效果
set_id_list = [] set_id_list = []
for relic in self.char_relic: for relic in self.char_relic:
print(json.dumps(relic, ensure_ascii=False))
set_id_list.append(relic['SetId']) set_id_list.append(relic['SetId'])
# 处理主属性 # 处理主属性
relic_property = relic['MainAffix']['Property'] relic_property = relic['MainAffix']['Property']

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

View File

@ -14,16 +14,19 @@ from .cal_value import cal_relic_sub_affix, cal_relic_main_affix
from ..utils.excel.read_excel import AvatarPromotion, EquipmentPromotion from ..utils.excel.read_excel import AvatarPromotion, EquipmentPromotion
from ..utils.map.SR_MAP_PATH import ( from ..utils.map.SR_MAP_PATH import (
SetId2Name, SetId2Name,
ItemId2Name,
Property2Name, Property2Name,
RelicId2SetId, RelicId2SetId,
EquipmentID2Name, EquipmentID2Name,
EquipmentID2Rarity,
rankId2Name, rankId2Name,
skillId2Name, skillId2Name,
skillId2Type,
avatarId2Name, avatarId2Name,
skillId2Effect,
avatarId2EnName, avatarId2EnName,
avatarId2Rarity, avatarId2Rarity,
characterSkillTree, characterSkillTree,
skillId2AttackType,
avatarId2DamageType, avatarId2DamageType,
) )
@ -55,7 +58,6 @@ async def api_to_dict(
return [] return []
if isinstance(sr_data, dict): if isinstance(sr_data, dict):
if 'PlayerDetailInfo' not in sr_data: if 'PlayerDetailInfo' not in sr_data:
print(sr_data)
im = '服务器正在维护或者关闭中...\n检查lulu api是否可以访问\n如可以访问,尝试上报Bug!' im = '服务器正在维护或者关闭中...\n检查lulu api是否可以访问\n如可以访问,尝试上报Bug!'
return im return im
elif sr_data is None: elif sr_data is None:
@ -124,7 +126,12 @@ async def get_data(char: dict, sr_data: dict, sr_uid: str):
char['AvatarID'] * 100 + behavior['BehaviorID'] % 10 char['AvatarID'] * 100 + behavior['BehaviorID'] % 10
) )
skill_temp['skillName'] = skillId2Name[str(skill_temp['skillId'])] skill_temp['skillName'] = skillId2Name[str(skill_temp['skillId'])]
skill_temp['skillType'] = skillId2Type[str(skill_temp['skillId'])] skill_temp['skillEffect'] = skillId2Effect[
str(skill_temp['skillId'])
]
skill_temp['skillAttackType'] = skillId2AttackType[
str(skill_temp['skillId'])
]
skill_temp['skillLevel'] = behavior['Level'] skill_temp['skillLevel'] = behavior['Level']
char_data['avatarSkill'].append(skill_temp) char_data['avatarSkill'].append(skill_temp)
@ -172,8 +179,9 @@ async def get_data(char: dict, sr_data: dict, sr_uid: str):
for relic in char['RelicList']: for relic in char['RelicList']:
relic_temp = {} relic_temp = {}
relic_temp['relicId'] = relic['ID'] relic_temp['relicId'] = relic['ID']
relic_temp['relicName'] = ItemId2Name[str(relic['ID'])]
relic_temp['SetId'] = int(RelicId2SetId[str(relic['ID'])]) relic_temp['SetId'] = int(RelicId2SetId[str(relic['ID'])])
relic_temp['name'] = SetId2Name[str(relic_temp['SetId'])] relic_temp['SetName'] = SetId2Name[str(relic_temp['SetId'])]
relic_temp['Level'] = relic['Level'] if 'Level' in relic else 1 relic_temp['Level'] = relic['Level'] if 'Level' in relic else 1
relic_temp['Type'] = relic['Type'] relic_temp['Type'] = relic['Type']
@ -275,6 +283,9 @@ async def get_data(char: dict, sr_data: dict, sr_uid: str):
equipment_info['equipmentLevel'] = char['EquipmentID']['Level'] equipment_info['equipmentLevel'] = char['EquipmentID']['Level']
equipment_info['equipmentPromotion'] = char['EquipmentID']['Promotion'] equipment_info['equipmentPromotion'] = char['EquipmentID']['Promotion']
equipment_info['equipmentRank'] = char['EquipmentID']['Rank'] equipment_info['equipmentRank'] = char['EquipmentID']['Rank']
equipment_info['equipmentRarity'] = EquipmentID2Rarity[
str(equipment_info['equipmentID'])
]
equipment_base_attributes = {} equipment_base_attributes = {}
equipment_promotion_base = EquipmentPromotion[ equipment_promotion_base = EquipmentPromotion[
str(equipment_info['equipmentID']) str(equipment_info['equipmentID'])

File diff suppressed because it is too large Load Diff

View File

@ -14,3 +14,6 @@ with open(EXCEL / 'AvatarPromotionConfig.json', 'r', encoding='utf8') as f:
with open(EXCEL / 'EquipmentPromotionConfig.json', 'r', encoding='utf8') as f: with open(EXCEL / 'EquipmentPromotionConfig.json', 'r', encoding='utf8') as f:
EquipmentPromotion = json.load(f) EquipmentPromotion = json.load(f)
with open(EXCEL / 'light_cone_ranks.json', 'r', encoding='utf8') as f:
light_cone_ranks = json.load(f)

View File

@ -15,6 +15,7 @@ sr_font_15 = starrail_font_origin(15)
sr_font_18 = starrail_font_origin(18) sr_font_18 = starrail_font_origin(18)
sr_font_20 = starrail_font_origin(20) sr_font_20 = starrail_font_origin(20)
sr_font_22 = starrail_font_origin(22) sr_font_22 = starrail_font_origin(22)
sr_font_23 = starrail_font_origin(23)
sr_font_24 = starrail_font_origin(24) sr_font_24 = starrail_font_origin(24)
sr_font_25 = starrail_font_origin(25) sr_font_25 = starrail_font_origin(25)
sr_font_26 = starrail_font_origin(26) sr_font_26 = starrail_font_origin(26)

View File

@ -4,8 +4,8 @@ from io import BytesIO
from pathlib import Path from pathlib import Path
from typing import Tuple, Union, Optional from typing import Tuple, Union, Optional
from PIL import Image
from httpx import get from httpx import get
from PIL import Image, ImageDraw, ImageFont
from ...starrailuid_config.sr_config import srconfig from ...starrailuid_config.sr_config import srconfig
from ..resource.RESOURCE_PATH import CU_BG_PATH, TEXT2D_PATH from ..resource.RESOURCE_PATH import CU_BG_PATH, TEXT2D_PATH
@ -24,6 +24,51 @@ else:
bg_path = NM_BG_PATH bg_path = NM_BG_PATH
def draw_text_by_line(
img: Image.Image,
pos: Tuple[int, int],
text: str,
font: ImageFont.FreeTypeFont,
fill: Union[Tuple[int, int, int, int], str],
max_length: float,
center=False,
line_space: Optional[float] = None,
):
"""
在图片上写长段文字, 自动换行
max_length单行最大长度, 单位像素
line_space 行间距, 单位像素, 默认是字体高度的0.3
"""
x, y = pos
_, h = font.getsize('X')
if line_space is None:
y_add = math.ceil(1.3 * h)
else:
y_add = math.ceil(h + line_space)
draw = ImageDraw.Draw(img)
row = "" # 存储本行文字
length = 0 # 记录本行长度
for character in text:
w, h = font.getsize(character) # 获取当前字符的宽度
if length + w * 2 <= max_length:
row += character
length += w
else:
row += character
if center:
font_size = font.getsize(row)
x = math.ceil((img.size[0] - font_size[0]) / 2)
draw.text((x, y), row, font=font, fill=fill)
row = ""
length = 0
y += y_add
if row != "":
if center:
font_size = font.getsize(row)
x = math.ceil((img.size[0] - font_size[0]) / 2)
draw.text((x, y), row, font=font, fill=fill)
async def get_qq_avatar( async def get_qq_avatar(
qid: Optional[Union[int, str]] = None, avatar_url: Optional[str] = None qid: Optional[Union[int, str]] = None, avatar_url: Optional[str] = None
) -> Image.Image: ) -> Image.Image:

View File

@ -26,6 +26,10 @@ EquipmentID2AbilityProperty_fileName = (
f'EquipmentID2AbilityProperty_mapping_{version}.json' f'EquipmentID2AbilityProperty_mapping_{version}.json'
) )
RelicSetSkill_fileName = f'RelicSetSkill_mapping_{version}.json' RelicSetSkill_fileName = f'RelicSetSkill_mapping_{version}.json'
skillId2AttackType_fileName = f'skillId2AttackType_mapping_{version}.json'
EquipmentID2Rarity_fileName = f'EquipmentID2Rarity_mapping_{version}.json'
RelicId2Rarity_fileName = f'RelicId2Rarity_mapping_{version}.json'
ItemId2Name_fileName = f'ItemId2Name_mapping_{version}.json'
class TS(TypedDict): class TS(TypedDict):
@ -49,7 +53,7 @@ with open(MAP / skillId2Name_fileName, 'r', encoding='UTF-8') as f:
skillId2Name = msgjson.decode(f.read(), type=Dict[str, str]) skillId2Name = msgjson.decode(f.read(), type=Dict[str, str])
with open(MAP / skillId2Type_fileName, 'r', encoding='UTF-8') as f: with open(MAP / skillId2Type_fileName, 'r', encoding='UTF-8') as f:
skillId2Type = msgjson.decode(f.read(), type=Dict[str, str]) skillId2Effect = msgjson.decode(f.read(), type=Dict[str, str])
with open(MAP / Property2Name_fileName, 'r', encoding='UTF-8') as f: with open(MAP / Property2Name_fileName, 'r', encoding='UTF-8') as f:
Property2Name = msgjson.decode(f.read(), type=Dict[str, str]) Property2Name = msgjson.decode(f.read(), type=Dict[str, str])
@ -84,3 +88,15 @@ with open(
with open(MAP / RelicSetSkill_fileName, 'r', encoding='UTF-8') as f: with open(MAP / RelicSetSkill_fileName, 'r', encoding='UTF-8') as f:
RelicSetSkill = msgjson.decode(f.read(), type=Dict[str, dict]) RelicSetSkill = msgjson.decode(f.read(), type=Dict[str, dict])
with open(MAP / skillId2AttackType_fileName, 'r', encoding='UTF-8') as f:
skillId2AttackType = msgjson.decode(f.read(), type=Dict[str, str])
with open(MAP / EquipmentID2Rarity_fileName, 'r', encoding='UTF-8') as f:
EquipmentID2Rarity = msgjson.decode(f.read(), type=Dict[str, int])
with open(MAP / RelicId2Rarity_fileName, 'r', encoding='UTF-8') as f:
RelicId2Rarity = msgjson.decode(f.read(), type=Dict[str, int])
with open(MAP / ItemId2Name_fileName, 'r', encoding='UTF-8') as f:
ItemId2Name = msgjson.decode(f.read(), type=Dict[str, str])

View File

@ -0,0 +1 @@
{"20000": 3, "20001": 3, "20002": 3, "20003": 3, "20004": 3, "20005": 3, "20006": 3, "20007": 3, "20008": 3, "20009": 3, "20010": 3, "20011": 3, "20012": 3, "20013": 3, "20014": 3, "20015": 3, "20016": 3, "20017": 3, "20018": 3, "20019": 3, "20020": 3, "21000": 4, "21001": 4, "21002": 4, "21003": 4, "21004": 4, "21005": 4, "21006": 4, "21007": 4, "21008": 4, "21009": 4, "21010": 4, "21011": 4, "21012": 4, "21013": 4, "21014": 4, "21015": 4, "21016": 4, "21017": 4, "21018": 4, "21019": 4, "21020": 4, "21021": 4, "21022": 4, "21023": 4, "21024": 4, "21025": 4, "21026": 4, "21027": 4, "21028": 4, "21029": 4, "21030": 4, "21031": 4, "21032": 4, "21033": 4, "21034": 4, "23000": 5, "23001": 5, "23002": 5, "23003": 5, "23004": 5, "23005": 5, "23010": 5, "23012": 5, "23013": 5, "24000": 5, "24001": 5, "24002": 5, "29000": 3}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"31011": 2, "31012": 2, "31013": 2, "31014": 2, "31021": 2, "31022": 2, "31023": 2, "31024": 2, "31031": 2, "31032": 2, "31033": 2, "31034": 2, "31041": 2, "31042": 2, "31043": 2, "31044": 2, "31051": 2, "31052": 2, "31053": 2, "31054": 2, "31061": 2, "31062": 2, "31063": 2, "31064": 2, "31071": 2, "31072": 2, "31073": 2, "31074": 2, "31081": 2, "31082": 2, "31083": 2, "31084": 2, "31091": 2, "31092": 2, "31093": 2, "31094": 2, "31101": 2, "31102": 2, "31103": 2, "31104": 2, "31111": 2, "31112": 2, "31113": 2, "31114": 2, "31121": 2, "31122": 2, "31123": 2, "31124": 2, "33015": 2, "33016": 2, "33025": 2, "33026": 2, "33035": 2, "33036": 2, "33045": 2, "33046": 2, "33055": 2, "33056": 2, "33065": 2, "33066": 2, "33075": 2, "33076": 2, "33085": 2, "33086": 2, "41011": 3, "41012": 3, "41013": 3, "41014": 3, "41021": 3, "41022": 3, "41023": 3, "41024": 3, "41031": 3, "41032": 3, "41033": 3, "41034": 3, "41041": 3, "41042": 3, "41043": 3, "41044": 3, "41051": 3, "41052": 3, "41053": 3, "41054": 3, "41061": 3, "41062": 3, "41063": 3, "41064": 3, "41071": 3, "41072": 3, "41073": 3, "41074": 3, "41081": 3, "41082": 3, "41083": 3, "41084": 3, "41091": 3, "41092": 3, "41093": 3, "41094": 3, "41101": 3, "41102": 3, "41103": 3, "41104": 3, "41111": 3, "41112": 3, "41113": 3, "41114": 3, "41121": 3, "41122": 3, "41123": 3, "41124": 3, "43015": 3, "43016": 3, "43025": 3, "43026": 3, "43035": 3, "43036": 3, "43045": 3, "43046": 3, "43055": 3, "43056": 3, "43065": 3, "43066": 3, "43075": 3, "43076": 3, "43085": 3, "43086": 3, "51011": 4, "51012": 4, "51013": 4, "51014": 4, "51021": 4, "51022": 4, "51023": 4, "51024": 4, "51031": 4, "51032": 4, "51033": 4, "51034": 4, "51041": 4, "51042": 4, "51043": 4, "51044": 4, "51051": 4, "51052": 4, "51053": 4, "51054": 4, "51061": 4, "51062": 4, "51063": 4, "51064": 4, "51071": 4, "51072": 4, "51073": 4, "51074": 4, "51081": 4, "51082": 4, "51083": 4, "51084": 4, "51091": 4, "51092": 4, "51093": 4, "51094": 4, "51101": 4, "51102": 4, "51103": 4, "51104": 4, "51111": 4, "51112": 4, "51113": 4, "51114": 4, "51121": 4, "51122": 4, "51123": 4, "51124": 4, "53015": 4, "53016": 4, "53025": 4, "53026": 4, "53035": 4, "53036": 4, "53045": 4, "53046": 4, "53055": 4, "53056": 4, "53065": 4, "53066": 4, "53075": 4, "53076": 4, "53085": 4, "53086": 4, "55001": 4, "55002": 4, "55003": 4, "55004": 4, "55005": 4, "55006": 4, "61011": 5, "61012": 5, "61013": 5, "61014": 5, "61021": 5, "61022": 5, "61023": 5, "61024": 5, "61031": 5, "61032": 5, "61033": 5, "61034": 5, "61041": 5, "61042": 5, "61043": 5, "61044": 5, "61051": 5, "61052": 5, "61053": 5, "61054": 5, "61061": 5, "61062": 5, "61063": 5, "61064": 5, "61071": 5, "61072": 5, "61073": 5, "61074": 5, "61081": 5, "61082": 5, "61083": 5, "61084": 5, "61091": 5, "61092": 5, "61093": 5, "61094": 5, "61101": 5, "61102": 5, "61103": 5, "61104": 5, "61111": 5, "61112": 5, "61113": 5, "61114": 5, "61121": 5, "61122": 5, "61123": 5, "61124": 5, "63015": 5, "63016": 5, "63025": 5, "63026": 5, "63035": 5, "63036": 5, "63045": 5, "63046": 5, "63055": 5, "63056": 5, "63065": 5, "63066": 5, "63075": 5, "63076": 5, "63085": 5, "63086": 5}

View File

@ -0,0 +1 @@
{"100101": "Normal", "100103": "Ultra", "100104": "", "100106": "MazeNormal", "100107": "Maze", "100201": "Normal", "100202": "BPSkill", "100203": "Ultra", "100204": "", "100206": "MazeNormal", "100207": "Maze", "100302": "BPSkill", "100306": "MazeNormal", "100307": "Maze", "100401": "Normal", "100402": "BPSkill", "100404": "", "100406": "MazeNormal", "100501": "Normal", "100502": "BPSkill", "100503": "Ultra", "100504": "", "100506": "MazeNormal", "100507": "Maze", "100801": "Normal", "100802": "BPSkill", "100803": "Ultra", "100804": "", "100806": "MazeNormal", "100807": "Maze", "100901": "Normal", "100902": "BPSkill", "100903": "Ultra", "100904": "", "100906": "MazeNormal", "100907": "Maze", "101301": "Normal", "101302": "BPSkill", "101303": "Ultra", "101304": "", "101306": "MazeNormal", "101307": "Maze", "110101": "Normal", "110102": "BPSkill", "110103": "Ultra", "110104": "", "110106": "MazeNormal", "110107": "Maze", "110203": "Ultra", "110206": "MazeNormal", "110207": "Maze", "110301": "Normal", "110302": "BPSkill", "110303": "Ultra", "110304": "", "110306": "MazeNormal", "110307": "Maze", "110401": "Normal", "110402": "BPSkill", "110403": "Ultra", "110404": "", "110406": "MazeNormal", "110407": "Maze", "110501": "Normal", "110502": "BPSkill", "110503": "Ultra", "110506": "MazeNormal", "110601": "Normal", "110602": "BPSkill", "110604": "", "110606": "MazeNormal", "110607": "Maze", "110801": "Normal", "110802": "BPSkill", "110803": "Ultra", "110806": "MazeNormal", "110807": "Maze", "110901": "Normal", "110902": "BPSkill", "110903": "Ultra", "110904": "", "110906": "MazeNormal", "110907": "Maze", "110909": "BPSkill", "120101": "Normal", "120108": "Normal", "120103": "Ultra", "120104": "", "120106": "MazeNormal", "120107": "Maze", "120201": "Normal", "120206": "MazeNormal", "120207": "Maze", "120301": "Normal", "120302": "BPSkill", "120303": "Ultra", "120304": "", "120306": "MazeNormal", "120307": "Maze", "120601": "Normal", "120602": "BPSkill", "120603": "Ultra", "120604": "", "120606": "MazeNormal", "120607": "Maze", "120901": "Normal", "120902": "BPSkill", "120903": "Ultra", "120904": "", "120906": "MazeNormal", "120907": "Maze", "121101": "Normal", "121102": "BPSkill", "121103": "Ultra", "121106": "MazeNormal", "121107": "Maze", "800101": "Normal", "800102": "BPSkill", "800103": "Ultra", "800104": "", "800106": "MazeNormal", "800107": "Maze", "800108": "Ultra", "800109": "Ultra", "800201": "Normal", "800202": "BPSkill", "800203": "Ultra", "800204": "", "800206": "MazeNormal", "800207": "Maze", "800208": "Ultra", "800209": "Ultra", "800301": "Normal", "800308": "Normal", "800303": "Ultra", "800304": "", "800306": "MazeNormal", "800307": "Maze", "800401": "Normal", "800408": "Normal", "800403": "Ultra", "800404": "", "800406": "MazeNormal", "800407": "Maze", "100601": "Normal", "100602": "BPSkill", "100603": "Ultra", "100604": "", "100606": "MazeNormal", "100607": "Maze", "120401": "Normal", "120402": "BPSkill", "120403": "Ultra", "120404": "", "120406": "MazeNormal", "909807": "Maze", "110603": "Ultra", "110507": "Maze", "800402": "BPSkill", "800302": "BPSkill", "120202": "BPSkill", "120204": "", "110804": "", "110504": "", "110202": "BPSkill", "110204": "", "100301": "Normal", "100304": "", "100303": "Ultra", "110701": "Normal", "110702": "BPSkill", "110703": "Ultra", "110704": "", "110706": "MazeNormal", "110707": "Maze", "110201": "Normal", "121104": "", "120407": "Maze", "100407": "Maze", "120102": "BPSkill", "100102": "BPSkill", "120203": "Ultra", "100403": "Ultra"}

View File

@ -14,6 +14,7 @@ CHAR_ICON_PATH = RESOURCE_PATH / 'character'
WEAPON_PATH = RESOURCE_PATH / 'light_cone' WEAPON_PATH = RESOURCE_PATH / 'light_cone'
CHAR_PORTRAIT = RESOURCE_PATH / 'character_portrait' CHAR_PORTRAIT = RESOURCE_PATH / 'character_portrait'
SKILL_PATH = RESOURCE_PATH / 'skill' SKILL_PATH = RESOURCE_PATH / 'skill'
RELIC_PATH = RESOURCE_PATH / 'relic'
TEXT2D_PATH = Path(__file__).parent / 'texture2d' TEXT2D_PATH = Path(__file__).parent / 'texture2d'
@ -29,6 +30,7 @@ def init_dir():
TEMP_PATH, TEMP_PATH,
CHAR_PORTRAIT, CHAR_PORTRAIT,
SKILL_PATH, SKILL_PATH,
RELIC_PATH,
]: ]:
i.mkdir(parents=True, exist_ok=True) i.mkdir(parents=True, exist_ok=True)