From b6243b16aa1dc8d8fc7f21f5d9e67c8fd19e0828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=A3=E8=90=BD?= <34079036+a376148946@users.noreply.github.com> Date: Sun, 14 May 2023 17:58:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=A7=92=E8=89=B2=E5=88=AB?= =?UTF-8?q?=E5=90=8D=E6=9F=A5=E8=AF=A2=20(#15)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 别名查询修改 * 别名查询修改 * add some functions * 别名查询修改 * 🚨 `pre-commit-ci`修复格式错误 * 修改别名 * 🚨 `pre-commit-ci`修复格式错误 * 修改别名 * 🚨 `pre-commit-ci`修复格式错误 * Add files via upload * 🚨 `pre-commit-ci`修复格式错误 * 修复别名查询 * 🚨 `pre-commit-ci`修复格式错误 * 修复别名查询 * 🚨 `pre-commit-ci`修复格式错误 * 修复别名查询 * 修复角色别名 * 🚨 `pre-commit-ci`修复格式错误 * 别名查询修复 * 🚨 `pre-commit-ci`修复格式错误 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../starrailuid_charinfo/draw_char_img.py | 1195 ++++++++--------- StarRailUID/utils/map/name_covert.py | 110 +- 2 files changed, 649 insertions(+), 656 deletions(-) diff --git a/StarRailUID/starrailuid_charinfo/draw_char_img.py b/StarRailUID/starrailuid_charinfo/draw_char_img.py index badd482..e6df86e 100644 --- a/StarRailUID/starrailuid_charinfo/draw_char_img.py +++ b/StarRailUID/starrailuid_charinfo/draw_char_img.py @@ -1,601 +1,594 @@ -import re -import json -import math -from pathlib import Path -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.image.convert import convert_img -from gsuid_core.utils.image.image_tools import draw_text_by_line - -from .mono.Character import Character -from ..utils.map.SR_MAP_PATH import RelicId2Rarity -from ..utils.excel.read_excel import light_cone_ranks -from ..utils.fonts.first_world import fw_font_28, fw_font_120 - -# 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: '六', 7: '七'} - -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]): - # 获取角色名 - char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', raw_mes)) - - char_data = await get_char_data(sr_uid, char_name) - if isinstance(char_data, str): - return char_data - char = 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, (-220, -130), char_img) - - # 放属性图标 - attr_img = Image.open(TEXT_PATH / f'IconAttribute{char.char_element}.png') - char_info.paste(attr_img, (540, 166), attr_img) - - # 放角色名 - char_img_draw = ImageDraw.Draw(char_info) - char_img_draw.text( - (620, 207), char.char_name, (255, 255, 255), sr_font_38, 'lm' - ) - char_name_len = sr_font_38.getsize(char.char_name)[0] - - # 放等级 - char_img_draw.text( - (620 + char_name_len + 50, 212), - f'LV.{str(char.char_level)}', - white_color, - sr_font_24, - 'mm', - ) - - # 放星级 - rarity_img = Image.open( - TEXT_PATH / f'LightCore_Rarity{char.char_rarity}.png' - ).resize((306, 72)) - char_info.paste(rarity_img, (490, 233), 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, (722, 225), rank_img) - - # 放uid - char_img_draw.text( - (995, 715), - f'uid {sr_uid}', - white_color, - fw_font_28, - 'rm', - stroke_width=1, - ) - - # 放属性列表 - 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( - (413, 31), f'{hp + add_hp}', white_color, sr_font_26, 'rm' - ) - attr_bg_draw.text( - (428, 31), - f'(+{str(round(add_hp))})', - (95, 251, 80), - sr_font_26, - anchor='lm', - ) - # 攻击力 - 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( - (413, 31 + 48), - f'{atk + add_attack}', - white_color, - sr_font_26, - 'rm', - ) - attr_bg_draw.text( - (428, 31 + 48), - f'(+{str(round(add_attack))})', - (95, 251, 80), - sr_font_26, - anchor='lm', - ) - # 防御力 - 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( - (413, 31 + 48 * 2), - f'{defence + add_defence}', - white_color, - sr_font_26, - 'rm', - ) - attr_bg_draw.text( - (428, 31 + 48 * 2), - f'(+{str(round(add_defence))})', - (95, 251, 80), - sr_font_26, - anchor='lm', - ) - # 速度 - 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( - (413, 31 + 48 * 3), - f'{speed + add_speed}', - white_color, - sr_font_26, - 'rm', - ) - attr_bg_draw.text( - (428, 31 + 48 * 3), - f'(+{str(round(add_speed))})', - (95, 251, 80), - sr_font_26, - anchor='lm', - ) - # 暴击率 - 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, (475, 300), attr_bg) - - # 命座 - for rank in range(0, 6): - rank_bg = Image.open(TEXT_PATH / 'mz_bg.png') - rank_no_bg = Image.open(TEXT_PATH / 'mz_no_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)) - .convert("RGBA") - ) - rank_img.putalpha( - rank_img.getchannel('A').point( - lambda x: round(x * 0.45) if x > 0 else 0 - ) - ) - rank_no_bg.paste(rank_img, (19, 19), rank_img) - char_info.paste(rank_no_bg, (20 + rank * 80, 630), rank_no_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 / f'skill_attr{i + 1}.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( - (75, 90), - f'{skill["skillName"]}', - (105, 105, 105), - sr_font_20, - 'mm', - ) - skill_bg.paste(skill_panel_img, (50 + 187 * i, 35), skill_panel_img) - i += 1 - char_info.paste(skill_bg, (0, 710), skill_bg) - - # 武器 - if char.equipment != {}: - 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( - (270, 240) - ) - weapon_bg.paste(weapon_img, (20, 50), weapon_img) - weapon_bg_draw = ImageDraw.Draw(weapon_bg) - weapon_bg_draw.text( - (345, 47), - f'{char.equipment["equipmentName"]}', - white_color, - sr_font_34, - 'lm', - ) - weapon_name_len = sr_font_34.getsize(char.equipment["equipmentName"])[ - 0 - ] - # 放阶 - 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.equipment["equipmentRank"]]}阶', - white_color, - sr_font_28, - 'mm', - ) - weapon_bg.paste(rank_img, (weapon_name_len + 330, 2), rank_img) - - rarity_img = Image.open( - TEXT_PATH - / f'LightCore_Rarity{char.equipment["equipmentRarity"]}.png' - ).resize((306, 72)) - weapon_bg.paste(rarity_img, (223, 55), rarity_img) - weapon_bg_draw.text( - (498, 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'] - 1] - for i in range(0, len(desc_params)): - temp = math.floor(desc_params[i] * 1000) / 10 - desc = desc.replace(f'#{i + 1}[i]%', f'{str(temp)}%') - 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, (286, 115), desc, sr_font_24, '#F9F9F9', 372 - ) - char_info.paste(weapon_bg, (-10, 870), weapon_bg) - else: - char_img_draw.text( - (525, 1005), - 'No light cone!', - white_color, - fw_font_120, - 'mm', - ) - - # 遗器 - if char.char_relic: - weapon_rank_bg = Image.open(TEXT_PATH / 'rank_bg.png') - char_info.paste(weapon_rank_bg, (690, 880), weapon_rank_bg) - relic_score = 0 - - for relic in char.char_relic: - rarity = RelicId2Rarity[str(relic["relicId"])] - relic_img = Image.open(TEXT_PATH / f'yq_bg{rarity}.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' - f'{RelicId2Rarity[str(relic["relicId"])]}.png' - ).resize((200, 48)) - relic_img.paste(rarity_img, (-10, 80), rarity_img) - relic_img_draw = ImageDraw.Draw(relic_img) - if len(relic['relicName']) <= 5: - main_name = relic['relicName'] - else: - main_name = relic['relicName'][:2] + relic['relicName'][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 = str(math.floor(main_value * 1000) / 10) + '%' - - 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( - (180, 105), - '+{}'.format(str(main_level)), - (255, 255, 255), - sr_font_23, - anchor='mm', - ) - - for index, i in enumerate(relic['SubAffixList']): - subName: str = i['Name'] - subValue = mp.mpf(i['Value']) - subProperty = i['Property'] - if subProperty == 'CriticalDamageBase': - relic_score += subValue - if subProperty == 'CriticalChanceBase': - relic_score += subValue * 2 - 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 - ) - if relic_score > 1: - relic_value_level = Image.open(TEXT_PATH / 'CommonIconS.png') - char_info.paste(relic_value_level, (780, 963), relic_value_level) - elif relic_score > 0.6: - relic_value_level = Image.open(TEXT_PATH / 'CommonIconA.png') - char_info.paste(relic_value_level, (780, 963), relic_value_level) - elif relic_score > 0.3: - relic_value_level = Image.open(TEXT_PATH / 'CommonIconB.png') - char_info.paste(relic_value_level, (780, 963), relic_value_level) - elif relic_score > 0: - relic_value_level = Image.open(TEXT_PATH / 'CommonIconC.png') - char_info.paste(relic_value_level, (780, 963), relic_value_level) - - else: - char_img_draw.text( - (525, 1565), - 'No relic!', - white_color, - fw_font_120, - 'mm', - ) - - # 发送图片 - res = await convert_img(char_info) - logger.info('[sr面板]绘图已完成,等待发送!') - return res - - -async def cal_char_info(char_data: dict): - char = Character(char_data) - await char.get_equipment_info() - await char.get_char_attribute_bonus() - await char.get_relic_info() - return char - - -async def get_char_data( - sr_uid: str, char_name: str, enable_self: bool = True -) -> Union[Dict, str]: - player_path = PLAYER_PATH / str(sr_uid) - SELF_PATH = player_path / 'SELF' - # char_id = await name_to_avatar_id(char_name) - if '开拓者' in char_name: - char_name = '开拓者' - # else: - # char_name = await alias_to_char_name(char_id, char_name) - - char_path = player_path / f'{char_name}.json' - char_self_path = SELF_PATH / f'{char_name}.json' - - if char_path.exists(): - path = char_path - elif enable_self and char_self_path.exists(): - path = char_self_path - else: - return CHAR_HINT.format(char_name) - - with open(path, 'r', encoding='utf8') as fp: - char_data = json.load(fp) - return char_data +import re +import json +import math +from pathlib import Path +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.image.convert import convert_img +from gsuid_core.utils.image.image_tools import draw_text_by_line + +from .mono.Character import Character +from ..utils.error_reply import CHAR_HINT +from ..utils.map.SR_MAP_PATH import RelicId2Rarity +from ..utils.excel.read_excel import light_cone_ranks +from ..utils.map.name_covert import alias_to_char_name +from ..utils.fonts.first_world import fw_font_28, fw_font_120 +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: '六', 7: '七'} + +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]): + # 获取角色名 + char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', raw_mes)) + + char_data = await get_char_data(sr_uid, char_name) + if isinstance(char_data, str): + return char_data + char = 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, (-220, -130), char_img) + + # 放属性图标 + attr_img = Image.open(TEXT_PATH / f'IconAttribute{char.char_element}.png') + char_info.paste(attr_img, (540, 166), attr_img) + + # 放角色名 + char_img_draw = ImageDraw.Draw(char_info) + char_img_draw.text( + (620, 207), char.char_name, (255, 255, 255), sr_font_38, 'lm' + ) + char_name_len = sr_font_38.getsize(char.char_name)[0] + + # 放等级 + char_img_draw.text( + (620 + char_name_len + 50, 212), + f'LV.{str(char.char_level)}', + white_color, + sr_font_24, + 'mm', + ) + + # 放星级 + rarity_img = Image.open( + TEXT_PATH / f'LightCore_Rarity{char.char_rarity}.png' + ).resize((306, 72)) + char_info.paste(rarity_img, (490, 233), 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, (722, 225), rank_img) + + # 放uid + char_img_draw.text( + (995, 715), + f'uid {sr_uid}', + white_color, + fw_font_28, + 'rm', + stroke_width=1, + ) + + # 放属性列表 + 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( + (413, 31), f'{hp + add_hp}', white_color, sr_font_26, 'rm' + ) + attr_bg_draw.text( + (428, 31), + f'(+{str(round(add_hp))})', + (95, 251, 80), + sr_font_26, + anchor='lm', + ) + # 攻击力 + 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( + (413, 31 + 48), + f'{atk + add_attack}', + white_color, + sr_font_26, + 'rm', + ) + attr_bg_draw.text( + (428, 31 + 48), + f'(+{str(round(add_attack))})', + (95, 251, 80), + sr_font_26, + anchor='lm', + ) + # 防御力 + 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( + (413, 31 + 48 * 2), + f'{defence + add_defence}', + white_color, + sr_font_26, + 'rm', + ) + attr_bg_draw.text( + (428, 31 + 48 * 2), + f'(+{str(round(add_defence))})', + (95, 251, 80), + sr_font_26, + anchor='lm', + ) + # 速度 + 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( + (413, 31 + 48 * 3), + f'{speed + add_speed}', + white_color, + sr_font_26, + 'rm', + ) + attr_bg_draw.text( + (428, 31 + 48 * 3), + f'(+{str(round(add_speed))})', + (95, 251, 80), + sr_font_26, + anchor='lm', + ) + # 暴击率 + 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, (475, 300), attr_bg) + + # 命座 + for rank in range(0, 6): + rank_bg = Image.open(TEXT_PATH / 'mz_bg.png') + rank_no_bg = Image.open(TEXT_PATH / 'mz_no_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)) + .convert("RGBA") + ) + rank_img.putalpha( + rank_img.getchannel('A').point( + lambda x: round(x * 0.45) if x > 0 else 0 + ) + ) + rank_no_bg.paste(rank_img, (19, 19), rank_img) + char_info.paste(rank_no_bg, (20 + rank * 80, 630), rank_no_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 / f'skill_attr{i + 1}.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( + (75, 90), + f'{skill["skillName"]}', + (105, 105, 105), + sr_font_20, + 'mm', + ) + skill_bg.paste(skill_panel_img, (50 + 187 * i, 35), skill_panel_img) + i += 1 + char_info.paste(skill_bg, (0, 710), skill_bg) + + # 武器 + if char.equipment != {}: + 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( + (270, 240) + ) + weapon_bg.paste(weapon_img, (20, 50), weapon_img) + weapon_bg_draw = ImageDraw.Draw(weapon_bg) + weapon_bg_draw.text( + (345, 47), + f'{char.equipment["equipmentName"]}', + white_color, + sr_font_34, + 'lm', + ) + weapon_name_len = sr_font_34.getsize(char.equipment["equipmentName"])[ + 0 + ] + # 放阶 + 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.equipment["equipmentRank"]]}阶', + white_color, + sr_font_28, + 'mm', + ) + weapon_bg.paste(rank_img, (weapon_name_len + 330, 2), rank_img) + + rarity_img = Image.open( + TEXT_PATH + / f'LightCore_Rarity{char.equipment["equipmentRarity"]}.png' + ).resize((306, 72)) + weapon_bg.paste(rarity_img, (223, 55), rarity_img) + weapon_bg_draw.text( + (498, 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'] - 1] + for i in range(0, len(desc_params)): + temp = math.floor(desc_params[i] * 1000) / 10 + desc = desc.replace(f'#{i + 1}[i]%', f'{str(temp)}%') + 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, (286, 115), desc, sr_font_24, '#F9F9F9', 372 + ) + char_info.paste(weapon_bg, (-10, 870), weapon_bg) + else: + char_img_draw.text( + (525, 1005), + 'No light cone!', + white_color, + fw_font_120, + 'mm', + ) + + # 遗器 + if char.char_relic: + weapon_rank_bg = Image.open(TEXT_PATH / 'rank_bg.png') + char_info.paste(weapon_rank_bg, (690, 880), weapon_rank_bg) + relic_score = 0 + + for relic in char.char_relic: + rarity = RelicId2Rarity[str(relic["relicId"])] + relic_img = Image.open(TEXT_PATH / f'yq_bg{rarity}.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' + f'{RelicId2Rarity[str(relic["relicId"])]}.png' + ).resize((200, 48)) + relic_img.paste(rarity_img, (-10, 80), rarity_img) + relic_img_draw = ImageDraw.Draw(relic_img) + if len(relic['relicName']) <= 5: + main_name = relic['relicName'] + else: + main_name = relic['relicName'][:2] + relic['relicName'][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 = str(math.floor(main_value * 1000) / 10) + '%' + + 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( + (180, 105), + '+{}'.format(str(main_level)), + (255, 255, 255), + sr_font_23, + anchor='mm', + ) + + for index, i in enumerate(relic['SubAffixList']): + subName: str = i['Name'] + subValue = mp.mpf(i['Value']) + subProperty = i['Property'] + if subProperty == 'CriticalDamageBase': + relic_score += subValue + if subProperty == 'CriticalChanceBase': + relic_score += subValue * 2 + 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 + ) + if relic_score > 1: + relic_value_level = Image.open(TEXT_PATH / 'CommonIconS.png') + char_info.paste(relic_value_level, (780, 963), relic_value_level) + elif relic_score > 0.6: + relic_value_level = Image.open(TEXT_PATH / 'CommonIconA.png') + char_info.paste(relic_value_level, (780, 963), relic_value_level) + elif relic_score > 0.3: + relic_value_level = Image.open(TEXT_PATH / 'CommonIconB.png') + char_info.paste(relic_value_level, (780, 963), relic_value_level) + elif relic_score > 0: + relic_value_level = Image.open(TEXT_PATH / 'CommonIconC.png') + char_info.paste(relic_value_level, (780, 963), relic_value_level) + + else: + char_img_draw.text( + (525, 1565), + 'No relic!', + white_color, + fw_font_120, + 'mm', + ) + + # 发送图片 + res = await convert_img(char_info) + logger.info('[sr面板]绘图已完成,等待发送!') + return res + + +async def cal_char_info(char_data: dict): + char = Character(char_data) + await char.get_equipment_info() + await char.get_char_attribute_bonus() + await char.get_relic_info() + return char + + +async def get_char_data( + sr_uid: str, char_name: str, enable_self: bool = True +) -> Union[Dict, str]: + player_path = PLAYER_PATH / str(sr_uid) + SELF_PATH = player_path / 'SELF' + char_name = await alias_to_char_name(char_name) + char_path = player_path / f'{char_name}.json' + char_self_path = SELF_PATH / f'{char_name}.json' + if char_path.exists(): + path = char_path + elif enable_self and char_self_path.exists(): + path = char_self_path + else: + return CHAR_HINT.format(char_name) + + with open(path, 'r', encoding='utf8') as fp: + char_data = json.load(fp) + return char_data diff --git a/StarRailUID/utils/map/name_covert.py b/StarRailUID/utils/map/name_covert.py index 48e3b62..3431e81 100644 --- a/StarRailUID/utils/map/name_covert.py +++ b/StarRailUID/utils/map/name_covert.py @@ -1,55 +1,55 @@ -from .SR_MAP_PATH import ( - EquipmentID2Name, - EquipmentID2EnName, - alias_data, - avatarId2Name, -) - - -async def avatar_id_to_name(avatar_id: str) -> str: - char_name = avatarId2Name[avatar_id] - return char_name - - -async def name_to_avatar_id(name: str) -> str: - avatar_id = '' - for i in avatarId2Name: - if avatarId2Name[i] == name: - avatar_id = i - break - return avatar_id - - -async def alias_to_char_name(char_id: str, char_name: str) -> str: - for i in alias_data['characters'][char_id]: - if (char_name in i) or (char_name in alias_data[i]): - return i - return char_name - - -async def weapon_id_to_name(weapon_id: str) -> str: - weapon_name = EquipmentID2Name[weapon_id] - return weapon_name - - -async def name_to_weapon_id(name: str) -> str: - weapon_id = '' - for i in EquipmentID2Name: - if EquipmentID2Name[i] == name: - weapon_id = i - break - return weapon_id - - -async def weapon_id_to_en_name(weapon_id: str) -> str: - weapon_en_name = EquipmentID2EnName[weapon_id] - return weapon_en_name - - -async def en_name_to_weapon_id(name: str) -> str: - weapon_id = '' - for i in EquipmentID2EnName: - if EquipmentID2EnName[i] == name: - weapon_id = i - break - return weapon_id +from .SR_MAP_PATH import ( + EquipmentID2Name, + EquipmentID2EnName, + alias_data, + avatarId2Name, +) + + +async def avatar_id_to_name(avatar_id: str) -> str: + char_name = avatarId2Name[avatar_id] + return char_name + + +async def name_to_avatar_id(name: str) -> str: + avatar_id = '' + for i in avatarId2Name: + if avatarId2Name[i] == name: + avatar_id = i + break + return avatar_id + + +async def alias_to_char_name(char_name: str) -> str: + for i in alias_data['characters']: + if char_name in alias_data['characters'][i]: + return alias_data['characters'][i][0] + return char_name + + +async def weapon_id_to_name(weapon_id: str) -> str: + weapon_name = EquipmentID2Name[weapon_id] + return weapon_name + + +async def name_to_weapon_id(name: str) -> str: + weapon_id = '' + for i in EquipmentID2Name: + if EquipmentID2Name[i] == name: + weapon_id = i + break + return weapon_id + + +async def weapon_id_to_en_name(weapon_id: str) -> str: + weapon_en_name = EquipmentID2EnName[weapon_id] + return weapon_en_name + + +async def en_name_to_weapon_id(name: str) -> str: + weapon_id = '' + for i in EquipmentID2EnName: + if EquipmentID2EnName[i] == name: + weapon_id = i + break + return weapon_id