diff --git a/StarRailUID/starrailuid_rogue/draw_rogue_card.py b/StarRailUID/starrailuid_rogue/draw_rogue_card.py index 2bd4842..f86e6a9 100644 --- a/StarRailUID/starrailuid_rogue/draw_rogue_card.py +++ b/StarRailUID/starrailuid_rogue/draw_rogue_card.py @@ -1,837 +1,840 @@ -import math -from pathlib import Path -from typing import List, Union, Optional - -from PIL import Image, ImageDraw -from gsuid_core.logger import logger -from gsuid_core.utils.error_reply import get_error -from gsuid_core.utils.image.image_tools import ( - get_qq_avatar, - draw_pic_with_ring, -) - -from .utils import get_icon -from ..utils.mys_api import mys_api -from ..utils.image.convert import convert_img -from ..utils.fonts.starrail_fonts import ( - sr_font_22, - sr_font_28, - sr_font_34, - sr_font_42, -) -from ..sruid_utils.api.mys.models import ( - RogueAvatar, - LocustBlocks, - RogueMiracles, - RogueBuffitems, -) - -TEXT_PATH = Path(__file__).parent / 'texture2D' -white_color = (255, 255, 255) -gray_color = (175, 175, 175) -img_bg = Image.open(TEXT_PATH / 'bg.jpg') -level_cover = Image.open(TEXT_PATH / 'level_cover.png').convert('RGBA') -char_bg_4 = Image.open(TEXT_PATH / 'char4_bg.png').convert('RGBA') -char_bg_5 = Image.open(TEXT_PATH / 'char5_bg.png').convert('RGBA') -rank_bg = Image.open(TEXT_PATH / 'rank_bg.png').convert('RGBA') -content_center = Image.open(TEXT_PATH / 'center.png').convert('RGBA') - -elements = { - 'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'), - 'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'), - 'imaginary': Image.open( - TEXT_PATH / 'IconNatureColorImaginary.png' - ).convert('RGBA'), - 'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.png').convert( - 'RGBA' - ), - 'lightning': Image.open(TEXT_PATH / 'IconNatureColorThunder.png').convert( - 'RGBA' - ), - 'wind': Image.open(TEXT_PATH / 'IconNatureColorWind.png').convert('RGBA'), - 'physical': Image.open(TEXT_PATH / 'IconNaturePhysical.png').convert( - 'RGBA' - ), -} - -progresslist = { - 1: '第一世界', - 2: '第二世界', - 3: '第三世界', - 4: '第四世界', - 5: '第五世界', - 6: '第六世界', - 7: '第七世界', -} - -difficultylist = { - 1: 'I', - 2: 'Ⅱ', - 3: 'Ⅲ', - 4: 'Ⅳ', - 5: 'V', - 6: 'Ⅵ', -} - -bufflist = { - 120: '存护', - 121: '记忆', - 122: '虚无', - 123: '丰饶', - 124: '巡猎', - 125: '毁灭', - 126: '欢愉', - 127: '繁育', -} - - -async def get_abyss_star_pic(star: int) -> Image.Image: - return Image.open(TEXT_PATH / f'star{star}.png') - - -async def _draw_rogue_buff( - buffs: List[RogueBuffitems], - buff_icon: str, - buff_name: str, - floor_pic: Image.Image, - buff_height: int, -): - draw_height = 0 - floor_pic_draw = ImageDraw.Draw(floor_pic) - buff_icon_img = Image.open(TEXT_PATH / f'{buff_icon}.png') - buff_icon_img = buff_icon_img.resize((40, 40)) - floor_pic.paste(buff_icon_img, (95, 400 + buff_height), buff_icon_img) - floor_pic_draw.text( - (140, 425 + buff_height), - f'{buff_name}:', - font=sr_font_28, - fill=gray_color, - anchor='lm', - ) - draw_height = draw_height + 40 - buff_num = len(buffs) - need_middle = math.ceil(buff_num / 3) - draw_height = draw_height + need_middle * 55 - zb_list = [] - for m in range(need_middle): - for n in range(3): - zb_list.append([m, n]) - jishu = 0 - for item in buffs: - if item.is_evoluted is True: - is_evoluted = 1 - else: - is_evoluted = 0 - buff_bg = Image.open( - TEXT_PATH / f'zhufu_{item.rank}_{is_evoluted}.png' - ) - buff_bg = buff_bg.resize((233, 35)) - z_left = 90 + 240 * zb_list[jishu][1] - z_top = buff_height + 450 + 55 * zb_list[jishu][0] - jishu = jishu + 1 - floor_pic.paste(buff_bg, (z_left, z_top), mask=buff_bg) - floor_pic_draw.text( - (z_left + 115, z_top + 18), - item.name, - font=sr_font_22, - fill=white_color, - anchor='mm', - ) - return draw_height - - -async def _draw_rogue_blocks( - blocks: List[LocustBlocks], - floor_pic: Image.Image, - buff_height: int, -): - draw_height = 0 - floor_pic_draw = ImageDraw.Draw(floor_pic) - blocks_num = len(blocks) - need_middle = math.ceil(blocks_num / 2) - draw_height = draw_height + need_middle * 80 - zb_list = [] - for m in range(need_middle): - for n in range(2): - zb_list.append([m, n]) - jishu = 0 - for block in blocks: - block_icon = Image.open(TEXT_PATH / f'{block.name}.png') - z_left_bg = 90 + 357 * zb_list[jishu][1] - z_top_bg = buff_height + 470 + 80 * zb_list[jishu][0] - jishu = jishu + 1 - z_left_icon = z_left_bg + 10 - z_top_icon = z_top_bg + 5 - floor_pic.paste(block_icon, (z_left_icon, z_top_icon), mask=block_icon) - floor_pic_draw.text( - (z_left_bg + 80, z_top_bg + 35), - f'{block.name} x{block.num}', - font=sr_font_22, - fill=white_color, - anchor='lm', - ) - return draw_height - - -async def _draw_rogue_miracles( - miracles: List[RogueMiracles], - floor_pic: Image.Image, - buff_height: int, -): - draw_height = 0 - miracles_num = len(miracles) - need_middle = math.ceil(miracles_num / 8) - draw_height = draw_height + need_middle * 90 - zb_list = [] - for m in range(need_middle): - for n in range(8): - zb_list.append([m, n]) - jishu = 0 - for miracle in miracles: - miracles_icon = (await get_icon(miracle.icon)).resize((80, 80)) - z_left = 90 + 90 * zb_list[jishu][1] - z_top = buff_height + 470 + 90 * zb_list[jishu][0] - jishu = jishu + 1 - floor_pic.paste(miracles_icon, (z_left, z_top), mask=miracles_icon) - - return draw_height - - -async def _draw_rogue_card( - char: RogueAvatar, - talent_num: str, - floor_pic: Image.Image, - index_char: int, -): - # char_id = char['id'] - # # 确认角色头像路径 - # char_pic_path = CHAR_ICON_PATH / f'{char_id}.png' - char_bg = (char_bg_4 if char.rarity == 4 else char_bg_5).copy() - char_icon = (await get_icon(char.icon)).resize((151, 170)) - element_icon = elements[char.element] - char_bg.paste(char_icon, (24, 16), mask=char_icon) - char_bg.paste(level_cover, (0, 0), mask=level_cover) - char_bg.paste(element_icon, (35, 25), mask=element_icon) - # 不存在自动下载 - # if not char_pic_path.exists(): - # await create_single_char_card(char_id) - # talent_pic = await get_talent_pic(int(talent_num)) - # talent_pic = talent_pic.resize((90, 45)) - # char_card.paste(talent_pic, (137, 260), talent_pic) - char_card_draw = ImageDraw.Draw(char_bg) - if char.rank > 0: - char_bg.paste(rank_bg, (150, 16), mask=rank_bg) - char_card_draw.text( - (162, 31), - f'{char.rank}', - font=sr_font_22, - fill=white_color, - anchor='mm', - ) - char_card_draw.text( - (100, 165), - f'等级 {char.level}', - font=sr_font_22, - fill=white_color, - anchor='mm', - ) - floor_pic.paste( - char_bg, - (75 + 185 * index_char, 130), - char_bg, - ) - - -async def draw_rogue_img( - qid: Union[str, int], - uid: str, - floor: Optional[int] = None, - schedule_type: str = '3', -) -> Union[bytes, str]: - raw_rogue_data = await mys_api.get_rogue_info(uid, '3') - - if isinstance(raw_rogue_data, int): - return get_error(raw_rogue_data) - - # 计算背景图尺寸 - if schedule_type == '3': - rogue_detail = raw_rogue_data.current_record.records - else: - rogue_detail = raw_rogue_data.last_record.records - - # 记录打的宇宙列表 - detail_list = [] - based_h = 700 - detail_h_list = [] - based_h_list = [] - for detail in rogue_detail: - # 100+70+170 - # 头+底+角色 - detail_h = 340 - progress = detail.progress - detail_list.append(progress) - # 祝福 - if len(detail.base_type_list) > 0: - buff_h = 60 - for buff in detail.buffs: - buff_h = buff_h + 50 - buff_num = len(buff.items) - buff_h = buff_h + math.ceil(buff_num / 3) * 55 - else: - buff_h = 0 - detail_h = detail_h + buff_h - - # 奇物 - if len(detail.miracles) > 0: - miracles_h = 60 - miracles_num = len(detail.miracles) - miracles_h = miracles_h + math.ceil(miracles_num / 8) * 90 - else: - miracles_h = 0 - detail_h = detail_h + miracles_h - detail_h_list.append(detail_h) - based_h_list.append(based_h) - if floor: - if progress == floor: - pass - else: - detail_h = 0 - based_h = based_h + detail_h - - # 获取查询者数据 - if floor: - if floor > 7: - return '世界不能大于第七世界!' - if floor not in detail_list: - return '你还没有挑战该模拟宇宙!' - elif schedule_type == '3': - if raw_rogue_data.current_record.basic.finish_cnt == 0: - return '你还没有挑战本期模拟宇宙!\n可以使用[sr上期模拟宇宙]命令查询上期~' - elif raw_rogue_data.last_record.basic.finish_cnt == 0: - return '你还没有挑战上期模拟宇宙!\n可以使用[sr模拟宇宙]命令查询本期~' - - # 获取背景图片各项参数 - based_w = 900 - img = Image.new('RGB', (based_w, based_h), (10, 18, 49)) - img.paste(img_bg, (0, 0)) - # img = img.crop((0, 0, based_w, based_h)) - rogue_title = Image.open(TEXT_PATH / 'head.png') - img.paste(rogue_title, (0, 0), rogue_title) - - # 获取头像 - _id = str(qid) - if _id.startswith('http'): - char_pic = await get_qq_avatar(avatar_url=_id) - else: - char_pic = await get_qq_avatar(qid=qid) - char_pic = await draw_pic_with_ring(char_pic, 250, None, False) - - img.paste(char_pic, (325, 132), char_pic) - - # 绘制抬头 - img_draw = ImageDraw.Draw(img) - img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') - - # 总体数据 - rogue_data = Image.open(TEXT_PATH / 'data.png') - img.paste(rogue_data, (0, 500), rogue_data) - - # 技能树激活 - img_draw.text( - (165, 569), - f'{raw_rogue_data.basic_info.unlocked_skill_points}', - white_color, - sr_font_42, - 'mm', - ) - img_draw.text( - (165, 615), - '已激活技能树', - gray_color, - sr_font_28, - 'mm', - ) - - # 奇物解锁 - img_draw.text( - (450, 569), - f'{raw_rogue_data.basic_info.unlocked_miracle_num}', - white_color, - sr_font_42, - 'mm', - ) - img_draw.text( - (450, 615), - '已解锁奇物', - gray_color, - sr_font_28, - 'mm', - ) - - # 祝福解锁 - img_draw.text( - (730, 569), - f'{raw_rogue_data.basic_info.unlocked_buff_num}', - white_color, - sr_font_42, - 'mm', - ) - img_draw.text( - (730, 615), - '已解锁祝福', - gray_color, - sr_font_28, - 'mm', - ) - - for index_floor, detail in enumerate(rogue_detail): - if floor: - if floor == detail.progress: - index_floor = 0 # noqa: PLW2901 - else: - continue - - if detail_h_list[index_floor] is None: - continue - - floor_pic = Image.open(TEXT_PATH / 'detail_bg.png').convert('RGBA') - floor_pic = floor_pic.resize((900, detail_h_list[index_floor])) - - floor_top_pic = Image.open(TEXT_PATH / 'floor_bg_top.png').convert( - 'RGBA' - ) - floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic) - - floor_center_pic = Image.open( - TEXT_PATH / 'floor_bg_center.png' - ).convert('RGBA') - floor_center_pic = floor_center_pic.resize( - (900, detail_h_list[index_floor] - 170) - ) - floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic) - - floor_bot_pic = Image.open(TEXT_PATH / 'floor_bg_bot.png').convert( - 'RGBA' - ) - floor_pic.paste( - floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic - ) - - floor_name = progresslist[detail.progress] - difficulty_name = difficultylist[detail.difficulty] - - time_array = detail.finish_time - time_str = f'{time_array.year}-{time_array.month}' - time_str = f'{time_str}-{time_array.day}' - time_str = f'{time_str} {time_array.hour}:{time_array.minute}' - floor_pic_draw = ImageDraw.Draw(floor_pic) - floor_pic_draw.text( - (450, 60), - f'{floor_name} {difficulty_name}', - white_color, - sr_font_42, - 'mm', - ) - floor_pic_draw.text( - (93, 120), - f'挑战时间:{time_str}', - gray_color, - sr_font_22, - 'lm', - ) - floor_pic_draw.text( - (800, 120), - f'当前积分:{detail.score}', - gray_color, - sr_font_22, - 'rm', - ) - - # 角色 - for index_char, char in enumerate(detail.final_lineup): - # 获取命座 - # if char["id"] in char_temp: - # talent_num = char_temp[char["id"]] - # else: - # for i in char_data: - # if i["id"] == char["id"]: - # talent_num = str( - # i["actived_constellation_num"] - # ) - # char_temp[char["id"]] = talent_num - # break - await _draw_rogue_card( - char, - 0, # type: ignore - floor_pic, - index_char, - ) - - # 祝福 - buff_height = 0 - if len(detail.base_type_list) > 0: - floor_pic_draw.text( - (93, 370), - '获得祝福', - white_color, - sr_font_34, - 'lm', - ) - floor_pic.paste(content_center, (0, 390), content_center) - for buff in detail.buffs: - buff_icon = bufflist[buff.base_type.id] - buff_name = buff.base_type.name - buffs = buff.items - draw_height = await _draw_rogue_buff( - buffs, - buff_icon, - buff_name, - floor_pic, - buff_height, - ) - buff_height = buff_height + draw_height - - # 奇物 - if len(detail.miracles) > 0: - floor_pic_draw.text( - (93, 370 + buff_height + 60), - '获得奇物', - white_color, - sr_font_34, - 'lm', - ) - floor_pic.paste( - content_center, (0, 370 + buff_height + 80), content_center - ) - await _draw_rogue_miracles( - detail.miracles, - floor_pic, - buff_height, - ) - - if based_h_list[index_floor] is None: - continue - - img.paste(floor_pic, (0, based_h_list[index_floor]), floor_pic) - # await _draw_floor_card( - # level_star, - # floor_pic, - # img, - # index_floor, - # floor_name, - # round_num, - # ) - - res = await convert_img(img) - logger.info('[查询模拟宇宙]绘图已完成,等待发送!') - return res - - -async def draw_rogue_locust_img( - qid: Union[str, int], - uid: str, -) -> Union[bytes, str]: - raw_rogue_data = await mys_api.get_rogue_locust_info(uid, '3') - - if isinstance(raw_rogue_data, int): - return get_error(raw_rogue_data) - - # 获取数据 - # if raw_data: - # char_data = raw_data['avatars'] - # else: - # return '没有获取到角色数据' - # char_temp = {} - - # 计算背景图尺寸 - rogue_detail = raw_rogue_data.detail.records - - # 记录打的宇宙列表 - # detail_list = [] - based_h = 700 - detail_h_list = [] - based_h_list = [] - for detail in rogue_detail: - # 100+70+170 - # 头+底+角色 - detail_h = 340 - - # 祝福 - if len(detail.base_type_list) > 0: - buff_h = 60 - for buff in detail.buffs: - buff_h = buff_h + 50 - buff_num = len(buff.items) - buff_h = buff_h + math.ceil(buff_num / 3) * 55 - else: - buff_h = 0 - detail_h = detail_h + buff_h - - # 奇物 - if len(detail.miracles) > 0: - miracles_h = 60 - miracles_num = len(detail.miracles) - miracles_h = miracles_h + math.ceil(miracles_num / 8) * 90 - else: - miracles_h = 0 - detail_h = detail_h + miracles_h - - # 事件 - blocks_h = 0 - if len(detail.blocks) > 0: - blocks_h = 60 - blocks_num = len(detail.blocks) - blocks_h = blocks_h + math.ceil(blocks_num / 2) * 80 - else: - blocks_num = 0 - detail_h = detail_h + blocks_h - detail_h_list.append(detail_h) - based_h_list.append(based_h) - based_h = based_h + detail_h - - # 获取查询者数据 - if len(rogue_detail) == 0: - return '你还没有挑战寰宇蝗灾~' - - # 获取背景图片各项参数 - based_w = 900 - img = Image.new('RGB', (based_w, based_h), (10, 18, 49)) - img.paste(img_bg, (0, 0)) - # img = img.crop((0, 0, based_w, based_h)) - rogue_title = Image.open(TEXT_PATH / 'head.png') - img.paste(rogue_title, (0, 0), rogue_title) - - # 获取头像 - _id = str(qid) - if _id.startswith('http'): - char_pic = await get_qq_avatar(avatar_url=_id) - else: - char_pic = await get_qq_avatar(qid=qid) - char_pic = await draw_pic_with_ring(char_pic, 250, None, False) - - img.paste(char_pic, (325, 132), char_pic) - - # 绘制抬头 - img_draw = ImageDraw.Draw(img) - img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') - - # 总体数据 - rogue_data = Image.open(TEXT_PATH / 'data.png') - img.paste(rogue_data, (0, 500), rogue_data) - - # 行者之道激活 - img_draw.text( - (165, 569), - f'{raw_rogue_data.basic.cnt.narrow}', - white_color, - sr_font_42, - 'mm', - ) - img_draw.text( - (165, 615), - '行者之道', - gray_color, - sr_font_28, - 'mm', - ) - - # 奇物解锁 - img_draw.text( - (450, 569), - f'{raw_rogue_data.basic.cnt.miracle}', - white_color, - sr_font_42, - 'mm', - ) - img_draw.text( - (450, 615), - '已解锁奇物', - gray_color, - sr_font_28, - 'mm', - ) - - # 事件解锁 - img_draw.text( - (730, 569), - f'{raw_rogue_data.basic.cnt.event}', - white_color, - sr_font_42, - 'mm', - ) - img_draw.text( - (730, 615), - '已解锁事件', - gray_color, - sr_font_28, - 'mm', - ) - - for index_floor, detail in enumerate(rogue_detail): - if detail_h_list[index_floor] is None: - continue - - floor_pic = Image.open(TEXT_PATH / 'detail_bg.png').convert('RGBA') - floor_pic = floor_pic.resize((900, detail_h_list[index_floor])) - - floor_top_pic = Image.open(TEXT_PATH / 'floor_bg_top.png').convert( - 'RGBA' - ) - floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic) - - floor_center_pic = Image.open( - TEXT_PATH / 'floor_bg_center.png' - ).convert('RGBA') - floor_center_pic = floor_center_pic.resize( - (900, detail_h_list[index_floor] - 170) - ) - floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic) - - floor_bot_pic = Image.open(TEXT_PATH / 'floor_bg_bot.png').convert( - 'RGBA' - ) - floor_pic.paste( - floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic - ) - - floor_name = detail.name - difficulty_name = difficultylist[detail.difficulty] - - time_array = detail.finish_time - time_str = f'{time_array.year}-{time_array.month}' - time_str = f'{time_str}-{time_array.day}' - time_str = f'{time_str} {time_array.hour}:{time_array.minute}' - floor_pic_draw = ImageDraw.Draw(floor_pic) - floor_pic_draw.text( - (450, 60), - f'{floor_name} {difficulty_name}', - white_color, - sr_font_42, - 'mm', - ) - floor_pic_draw.text( - (93, 120), - f'挑战时间:{time_str}', - gray_color, - sr_font_22, - 'lm', - ) - if detail.fury.type == 1: - floor_pic_draw.text( - (800, 120), - f'扰动等级:{detail.fury.point}', - gray_color, - sr_font_22, - 'rm', - ) - else: - floor_pic_draw.text( - (800, 120), - f'位面紊乱倒计时:{detail.fury.point}', - gray_color, - sr_font_22, - 'rm', - ) - - # 角色 - for index_char, char in enumerate(detail.final_lineup): - # 获取命座 - # if char["id"] in char_temp: - # talent_num = char_temp[char["id"]] - # else: - # for i in char_data: - # if i["id"] == char["id"]: - # talent_num = str( - # i["actived_constellation_num"] - # ) - # char_temp[char["id"]] = talent_num - # break - await _draw_rogue_card( - char, - 0, # type: ignore - floor_pic, - index_char, - ) - - # 祝福 - buff_height = 0 - if len(detail.base_type_list) > 0: - floor_pic_draw.text( - (93, 370), - '获得祝福', - white_color, - sr_font_34, - 'lm', - ) - floor_pic.paste(content_center, (0, 390), content_center) - for buff in detail.buffs: - buff_icon = bufflist[buff.base_type.id] - buff_name = buff.base_type.name - buffs = buff.items - draw_height = await _draw_rogue_buff( - buffs, - buff_icon, - buff_name, - floor_pic, - buff_height, - ) - buff_height = buff_height + draw_height - - # 奇物 - miracles_height = buff_height - if len(detail.miracles) > 0: - floor_pic_draw.text( - (93, 370 + miracles_height + 60), - '获得奇物', - white_color, - sr_font_34, - 'lm', - ) - floor_pic.paste( - content_center, (0, 370 + miracles_height + 80), content_center - ) - draw_height = await _draw_rogue_miracles( - detail.miracles, - floor_pic, - miracles_height, - ) - miracles_height = miracles_height + 80 - miracles_height = miracles_height + draw_height - - # 事件 - blocks_height = miracles_height - if len(detail.blocks) > 0: - floor_pic_draw.text( - (93, 370 + blocks_height + 60), - '通过区域类型', - white_color, - sr_font_34, - 'lm', - ) - floor_pic.paste( - content_center, (0, 370 + blocks_height + 80), content_center - ) - draw_height = await _draw_rogue_blocks( - detail.blocks, - floor_pic, - blocks_height, - ) - blocks_height = blocks_height + 80 - blocks_height = blocks_height + draw_height - - if based_h_list[index_floor] is None: - continue - - img.paste(floor_pic, (0, based_h_list[index_floor]), floor_pic) - # await _draw_floor_card( - # level_star, - # floor_pic, - # img, - # index_floor, - # floor_name, - # round_num, - # ) - - res = await convert_img(img) - logger.info('[查询寰宇蝗灾]绘图已完成,等待发送!') - return res +import math +from pathlib import Path +from typing import List, Union, Optional + +from PIL import Image, ImageDraw +from gsuid_core.logger import logger +from gsuid_core.utils.error_reply import get_error +from gsuid_core.utils.image.image_tools import ( + get_qq_avatar, + draw_pic_with_ring, +) + +from .utils import get_icon +from ..utils.mys_api import mys_api +from ..utils.image.convert import convert_img +from ..utils.fonts.starrail_fonts import ( + sr_font_22, + sr_font_28, + sr_font_34, + sr_font_42, +) +from ..sruid_utils.api.mys.models import ( + RogueAvatar, + LocustBlocks, + RogueMiracles, + RogueBuffitems, +) + +TEXT_PATH = Path(__file__).parent / 'texture2D' +white_color = (255, 255, 255) +gray_color = (175, 175, 175) +img_bg = Image.open(TEXT_PATH / 'bg.jpg') +level_cover = Image.open(TEXT_PATH / 'level_cover.png').convert('RGBA') +char_bg_4 = Image.open(TEXT_PATH / 'char4_bg.png').convert('RGBA') +char_bg_5 = Image.open(TEXT_PATH / 'char5_bg.png').convert('RGBA') +rank_bg = Image.open(TEXT_PATH / 'rank_bg.png').convert('RGBA') +content_center = Image.open(TEXT_PATH / 'center.png').convert('RGBA') + +elements = { + 'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'), + 'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'), + 'imaginary': Image.open( + TEXT_PATH / 'IconNatureColorImaginary.png' + ).convert('RGBA'), + 'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.png').convert( + 'RGBA' + ), + 'lightning': Image.open(TEXT_PATH / 'IconNatureColorThunder.png').convert( + 'RGBA' + ), + 'wind': Image.open(TEXT_PATH / 'IconNatureColorWind.png').convert('RGBA'), + 'physical': Image.open(TEXT_PATH / 'IconNaturePhysical.png').convert( + 'RGBA' + ), +} + +progresslist = { + 1: '第一世界', + 2: '第二世界', + 3: '第三世界', + 4: '第四世界', + 5: '第五世界', + 6: '第六世界', + 7: '第七世界', + 8: '第八世界', +} + +difficultylist = { + 1: 'I', + 2: 'Ⅱ', + 3: 'Ⅲ', + 4: 'Ⅳ', + 5: 'V', + 6: 'Ⅵ', + 7: 'Ⅶ', + 8: 'Ⅷ', +} + +bufflist = { + 120: '存护', + 121: '记忆', + 122: '虚无', + 123: '丰饶', + 124: '巡猎', + 125: '毁灭', + 126: '欢愉', + 127: '繁育', +} + + +async def get_abyss_star_pic(star: int) -> Image.Image: + return Image.open(TEXT_PATH / f'star{star}.png') + + +async def _draw_rogue_buff( + buffs: List[RogueBuffitems], + buff_icon: str, + buff_name: str, + floor_pic: Image.Image, + buff_height: int, +): + draw_height = 0 + floor_pic_draw = ImageDraw.Draw(floor_pic) + buff_icon_img = Image.open(TEXT_PATH / f'{buff_icon}.png') + buff_icon_img = buff_icon_img.resize((40, 40)) + floor_pic.paste(buff_icon_img, (95, 400 + buff_height), buff_icon_img) + floor_pic_draw.text( + (140, 425 + buff_height), + f'{buff_name}:', + font=sr_font_28, + fill=gray_color, + anchor='lm', + ) + draw_height = draw_height + 40 + buff_num = len(buffs) + need_middle = math.ceil(buff_num / 3) + draw_height = draw_height + need_middle * 55 + zb_list = [] + for m in range(need_middle): + for n in range(3): + zb_list.append([m, n]) + jishu = 0 + for item in buffs: + if item.is_evoluted is True: + is_evoluted = 1 + else: + is_evoluted = 0 + buff_bg = Image.open( + TEXT_PATH / f'zhufu_{item.rank}_{is_evoluted}.png' + ) + buff_bg = buff_bg.resize((233, 35)) + z_left = 90 + 240 * zb_list[jishu][1] + z_top = buff_height + 450 + 55 * zb_list[jishu][0] + jishu = jishu + 1 + floor_pic.paste(buff_bg, (z_left, z_top), mask=buff_bg) + floor_pic_draw.text( + (z_left + 115, z_top + 18), + item.name, + font=sr_font_22, + fill=white_color, + anchor='mm', + ) + return draw_height + + +async def _draw_rogue_blocks( + blocks: List[LocustBlocks], + floor_pic: Image.Image, + buff_height: int, +): + draw_height = 0 + floor_pic_draw = ImageDraw.Draw(floor_pic) + blocks_num = len(blocks) + need_middle = math.ceil(blocks_num / 2) + draw_height = draw_height + need_middle * 80 + zb_list = [] + for m in range(need_middle): + for n in range(2): + zb_list.append([m, n]) + jishu = 0 + for block in blocks: + block_icon = Image.open(TEXT_PATH / f'{block.name}.png') + z_left_bg = 90 + 357 * zb_list[jishu][1] + z_top_bg = buff_height + 470 + 80 * zb_list[jishu][0] + jishu = jishu + 1 + z_left_icon = z_left_bg + 10 + z_top_icon = z_top_bg + 5 + floor_pic.paste(block_icon, (z_left_icon, z_top_icon), mask=block_icon) + floor_pic_draw.text( + (z_left_bg + 80, z_top_bg + 35), + f'{block.name} x{block.num}', + font=sr_font_22, + fill=white_color, + anchor='lm', + ) + return draw_height + + +async def _draw_rogue_miracles( + miracles: List[RogueMiracles], + floor_pic: Image.Image, + buff_height: int, +): + draw_height = 0 + miracles_num = len(miracles) + need_middle = math.ceil(miracles_num / 8) + draw_height = draw_height + need_middle * 90 + zb_list = [] + for m in range(need_middle): + for n in range(8): + zb_list.append([m, n]) + jishu = 0 + for miracle in miracles: + miracles_icon = (await get_icon(miracle.icon)).resize((80, 80)) + z_left = 90 + 90 * zb_list[jishu][1] + z_top = buff_height + 470 + 90 * zb_list[jishu][0] + jishu = jishu + 1 + floor_pic.paste(miracles_icon, (z_left, z_top), mask=miracles_icon) + + return draw_height + + +async def _draw_rogue_card( + char: RogueAvatar, + talent_num: str, + floor_pic: Image.Image, + index_char: int, +): + # char_id = char['id'] + # # 确认角色头像路径 + # char_pic_path = CHAR_ICON_PATH / f'{char_id}.png' + char_bg = (char_bg_4 if char.rarity == 4 else char_bg_5).copy() + char_icon = (await get_icon(char.icon)).resize((151, 170)) + element_icon = elements[char.element] + char_bg.paste(char_icon, (24, 16), mask=char_icon) + char_bg.paste(level_cover, (0, 0), mask=level_cover) + char_bg.paste(element_icon, (35, 25), mask=element_icon) + # 不存在自动下载 + # if not char_pic_path.exists(): + # await create_single_char_card(char_id) + # talent_pic = await get_talent_pic(int(talent_num)) + # talent_pic = talent_pic.resize((90, 45)) + # char_card.paste(talent_pic, (137, 260), talent_pic) + char_card_draw = ImageDraw.Draw(char_bg) + if char.rank > 0: + char_bg.paste(rank_bg, (150, 16), mask=rank_bg) + char_card_draw.text( + (162, 31), + f'{char.rank}', + font=sr_font_22, + fill=white_color, + anchor='mm', + ) + char_card_draw.text( + (100, 165), + f'等级 {char.level}', + font=sr_font_22, + fill=white_color, + anchor='mm', + ) + floor_pic.paste( + char_bg, + (75 + 185 * index_char, 130), + char_bg, + ) + + +async def draw_rogue_img( + qid: Union[str, int], + uid: str, + floor: Optional[int] = None, + schedule_type: str = '3', +) -> Union[bytes, str]: + raw_rogue_data = await mys_api.get_rogue_info(uid, '3') + + if isinstance(raw_rogue_data, int): + return get_error(raw_rogue_data) + + # 计算背景图尺寸 + if schedule_type == '3': + rogue_detail = raw_rogue_data.current_record.records + else: + rogue_detail = raw_rogue_data.last_record.records + + # 记录打的宇宙列表 + detail_list = [] + based_h = 700 + detail_h_list = [] + based_h_list = [] + for detail in rogue_detail: + # 100+70+170 + # 头+底+角色 + detail_h = 340 + progress = detail.progress + detail_list.append(progress) + # 祝福 + if len(detail.base_type_list) > 0: + buff_h = 60 + for buff in detail.buffs: + buff_h = buff_h + 50 + buff_num = len(buff.items) + buff_h = buff_h + math.ceil(buff_num / 3) * 55 + else: + buff_h = 0 + detail_h = detail_h + buff_h + + # 奇物 + if len(detail.miracles) > 0: + miracles_h = 60 + miracles_num = len(detail.miracles) + miracles_h = miracles_h + math.ceil(miracles_num / 8) * 90 + else: + miracles_h = 0 + detail_h = detail_h + miracles_h + detail_h_list.append(detail_h) + based_h_list.append(based_h) + if floor: + if progress == floor: + pass + else: + detail_h = 0 + based_h = based_h + detail_h + + # 获取查询者数据 + if floor: + if floor > 8: + return '世界不能大于第八世界!' + if floor not in detail_list: + return '你还没有挑战该模拟宇宙!' + elif schedule_type == '3': + if raw_rogue_data.current_record.basic.finish_cnt == 0: + return '你还没有挑战本期模拟宇宙!\n可以使用[sr上期模拟宇宙]命令查询上期~' + elif raw_rogue_data.last_record.basic.finish_cnt == 0: + return '你还没有挑战上期模拟宇宙!\n可以使用[sr模拟宇宙]命令查询本期~' + + # 获取背景图片各项参数 + based_w = 900 + img = Image.new('RGB', (based_w, based_h), (10, 18, 49)) + img.paste(img_bg, (0, 0)) + # img = img.crop((0, 0, based_w, based_h)) + rogue_title = Image.open(TEXT_PATH / 'head.png') + img.paste(rogue_title, (0, 0), rogue_title) + + # 获取头像 + _id = str(qid) + if _id.startswith('http'): + char_pic = await get_qq_avatar(avatar_url=_id) + else: + char_pic = await get_qq_avatar(qid=qid) + char_pic = await draw_pic_with_ring(char_pic, 250, None, False) + + img.paste(char_pic, (325, 132), char_pic) + + # 绘制抬头 + img_draw = ImageDraw.Draw(img) + img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') + + # 总体数据 + rogue_data = Image.open(TEXT_PATH / 'data.png') + img.paste(rogue_data, (0, 500), rogue_data) + + # 技能树激活 + img_draw.text( + (165, 569), + f'{raw_rogue_data.basic_info.unlocked_skill_points}', + white_color, + sr_font_42, + 'mm', + ) + img_draw.text( + (165, 615), + '已激活技能树', + gray_color, + sr_font_28, + 'mm', + ) + + # 奇物解锁 + img_draw.text( + (450, 569), + f'{raw_rogue_data.basic_info.unlocked_miracle_num}', + white_color, + sr_font_42, + 'mm', + ) + img_draw.text( + (450, 615), + '已解锁奇物', + gray_color, + sr_font_28, + 'mm', + ) + + # 祝福解锁 + img_draw.text( + (730, 569), + f'{raw_rogue_data.basic_info.unlocked_buff_num}', + white_color, + sr_font_42, + 'mm', + ) + img_draw.text( + (730, 615), + '已解锁祝福', + gray_color, + sr_font_28, + 'mm', + ) + + for index_floor, detail in enumerate(rogue_detail): + if floor: + if floor == detail.progress: + index_floor = 0 # noqa: PLW2901 + else: + continue + + if detail_h_list[index_floor] is None: + continue + + floor_pic = Image.open(TEXT_PATH / 'detail_bg.png').convert('RGBA') + floor_pic = floor_pic.resize((900, detail_h_list[index_floor])) + + floor_top_pic = Image.open(TEXT_PATH / 'floor_bg_top.png').convert( + 'RGBA' + ) + floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic) + + floor_center_pic = Image.open( + TEXT_PATH / 'floor_bg_center.png' + ).convert('RGBA') + floor_center_pic = floor_center_pic.resize( + (900, detail_h_list[index_floor] - 170) + ) + floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic) + + floor_bot_pic = Image.open(TEXT_PATH / 'floor_bg_bot.png').convert( + 'RGBA' + ) + floor_pic.paste( + floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic + ) + + floor_name = progresslist[detail.progress] + difficulty_name = difficultylist[detail.difficulty] + + time_array = detail.finish_time + time_str = f'{time_array.year}-{time_array.month}' + time_str = f'{time_str}-{time_array.day}' + time_str = f'{time_str} {time_array.hour}:{time_array.minute}' + floor_pic_draw = ImageDraw.Draw(floor_pic) + floor_pic_draw.text( + (450, 60), + f'{floor_name} {difficulty_name}', + white_color, + sr_font_42, + 'mm', + ) + floor_pic_draw.text( + (93, 120), + f'挑战时间:{time_str}', + gray_color, + sr_font_22, + 'lm', + ) + floor_pic_draw.text( + (800, 120), + f'当前积分:{detail.score}', + gray_color, + sr_font_22, + 'rm', + ) + + # 角色 + for index_char, char in enumerate(detail.final_lineup): + # 获取命座 + # if char["id"] in char_temp: + # talent_num = char_temp[char["id"]] + # else: + # for i in char_data: + # if i["id"] == char["id"]: + # talent_num = str( + # i["actived_constellation_num"] + # ) + # char_temp[char["id"]] = talent_num + # break + await _draw_rogue_card( + char, + 0, # type: ignore + floor_pic, + index_char, + ) + + # 祝福 + buff_height = 0 + if len(detail.base_type_list) > 0: + floor_pic_draw.text( + (93, 370), + '获得祝福', + white_color, + sr_font_34, + 'lm', + ) + floor_pic.paste(content_center, (0, 390), content_center) + for buff in detail.buffs: + buff_icon = bufflist[buff.base_type.id] + buff_name = buff.base_type.name + buffs = buff.items + draw_height = await _draw_rogue_buff( + buffs, + buff_icon, + buff_name, + floor_pic, + buff_height, + ) + buff_height = buff_height + draw_height + + # 奇物 + if len(detail.miracles) > 0: + floor_pic_draw.text( + (93, 370 + buff_height + 60), + '获得奇物', + white_color, + sr_font_34, + 'lm', + ) + floor_pic.paste( + content_center, (0, 370 + buff_height + 80), content_center + ) + await _draw_rogue_miracles( + detail.miracles, + floor_pic, + buff_height, + ) + + if based_h_list[index_floor] is None: + continue + + img.paste(floor_pic, (0, based_h_list[index_floor]), floor_pic) + # await _draw_floor_card( + # level_star, + # floor_pic, + # img, + # index_floor, + # floor_name, + # round_num, + # ) + + res = await convert_img(img) + logger.info('[查询模拟宇宙]绘图已完成,等待发送!') + return res + + +async def draw_rogue_locust_img( + qid: Union[str, int], + uid: str, +) -> Union[bytes, str]: + raw_rogue_data = await mys_api.get_rogue_locust_info(uid, '3') + + if isinstance(raw_rogue_data, int): + return get_error(raw_rogue_data) + + # 获取数据 + # if raw_data: + # char_data = raw_data['avatars'] + # else: + # return '没有获取到角色数据' + # char_temp = {} + + # 计算背景图尺寸 + rogue_detail = raw_rogue_data.detail.records + + # 记录打的宇宙列表 + # detail_list = [] + based_h = 700 + detail_h_list = [] + based_h_list = [] + for detail in rogue_detail: + # 100+70+170 + # 头+底+角色 + detail_h = 340 + + # 祝福 + if len(detail.base_type_list) > 0: + buff_h = 60 + for buff in detail.buffs: + buff_h = buff_h + 50 + buff_num = len(buff.items) + buff_h = buff_h + math.ceil(buff_num / 3) * 55 + else: + buff_h = 0 + detail_h = detail_h + buff_h + + # 奇物 + if len(detail.miracles) > 0: + miracles_h = 60 + miracles_num = len(detail.miracles) + miracles_h = miracles_h + math.ceil(miracles_num / 8) * 90 + else: + miracles_h = 0 + detail_h = detail_h + miracles_h + + # 事件 + blocks_h = 0 + if len(detail.blocks) > 0: + blocks_h = 60 + blocks_num = len(detail.blocks) + blocks_h = blocks_h + math.ceil(blocks_num / 2) * 80 + else: + blocks_num = 0 + detail_h = detail_h + blocks_h + detail_h_list.append(detail_h) + based_h_list.append(based_h) + based_h = based_h + detail_h + + # 获取查询者数据 + if len(rogue_detail) == 0: + return '你还没有挑战寰宇蝗灾~' + + # 获取背景图片各项参数 + based_w = 900 + img = Image.new('RGB', (based_w, based_h), (10, 18, 49)) + img.paste(img_bg, (0, 0)) + # img = img.crop((0, 0, based_w, based_h)) + rogue_title = Image.open(TEXT_PATH / 'head.png') + img.paste(rogue_title, (0, 0), rogue_title) + + # 获取头像 + _id = str(qid) + if _id.startswith('http'): + char_pic = await get_qq_avatar(avatar_url=_id) + else: + char_pic = await get_qq_avatar(qid=qid) + char_pic = await draw_pic_with_ring(char_pic, 250, None, False) + + img.paste(char_pic, (325, 132), char_pic) + + # 绘制抬头 + img_draw = ImageDraw.Draw(img) + img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') + + # 总体数据 + rogue_data = Image.open(TEXT_PATH / 'data.png') + img.paste(rogue_data, (0, 500), rogue_data) + + # 行者之道激活 + img_draw.text( + (165, 569), + f'{raw_rogue_data.basic.cnt.narrow}', + white_color, + sr_font_42, + 'mm', + ) + img_draw.text( + (165, 615), + '行者之道', + gray_color, + sr_font_28, + 'mm', + ) + + # 奇物解锁 + img_draw.text( + (450, 569), + f'{raw_rogue_data.basic.cnt.miracle}', + white_color, + sr_font_42, + 'mm', + ) + img_draw.text( + (450, 615), + '已解锁奇物', + gray_color, + sr_font_28, + 'mm', + ) + + # 事件解锁 + img_draw.text( + (730, 569), + f'{raw_rogue_data.basic.cnt.event}', + white_color, + sr_font_42, + 'mm', + ) + img_draw.text( + (730, 615), + '已解锁事件', + gray_color, + sr_font_28, + 'mm', + ) + + for index_floor, detail in enumerate(rogue_detail): + if detail_h_list[index_floor] is None: + continue + + floor_pic = Image.open(TEXT_PATH / 'detail_bg.png').convert('RGBA') + floor_pic = floor_pic.resize((900, detail_h_list[index_floor])) + + floor_top_pic = Image.open(TEXT_PATH / 'floor_bg_top.png').convert( + 'RGBA' + ) + floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic) + + floor_center_pic = Image.open( + TEXT_PATH / 'floor_bg_center.png' + ).convert('RGBA') + floor_center_pic = floor_center_pic.resize( + (900, detail_h_list[index_floor] - 170) + ) + floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic) + + floor_bot_pic = Image.open(TEXT_PATH / 'floor_bg_bot.png').convert( + 'RGBA' + ) + floor_pic.paste( + floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic + ) + + floor_name = detail.name + difficulty_name = difficultylist[detail.difficulty] + + time_array = detail.finish_time + time_str = f'{time_array.year}-{time_array.month}' + time_str = f'{time_str}-{time_array.day}' + time_str = f'{time_str} {time_array.hour}:{time_array.minute}' + floor_pic_draw = ImageDraw.Draw(floor_pic) + floor_pic_draw.text( + (450, 60), + f'{floor_name} {difficulty_name}', + white_color, + sr_font_42, + 'mm', + ) + floor_pic_draw.text( + (93, 120), + f'挑战时间:{time_str}', + gray_color, + sr_font_22, + 'lm', + ) + if detail.fury.type == 1: + floor_pic_draw.text( + (800, 120), + f'扰动等级:{detail.fury.point}', + gray_color, + sr_font_22, + 'rm', + ) + else: + floor_pic_draw.text( + (800, 120), + f'位面紊乱倒计时:{detail.fury.point}', + gray_color, + sr_font_22, + 'rm', + ) + + # 角色 + for index_char, char in enumerate(detail.final_lineup): + # 获取命座 + # if char["id"] in char_temp: + # talent_num = char_temp[char["id"]] + # else: + # for i in char_data: + # if i["id"] == char["id"]: + # talent_num = str( + # i["actived_constellation_num"] + # ) + # char_temp[char["id"]] = talent_num + # break + await _draw_rogue_card( + char, + 0, # type: ignore + floor_pic, + index_char, + ) + + # 祝福 + buff_height = 0 + if len(detail.base_type_list) > 0: + floor_pic_draw.text( + (93, 370), + '获得祝福', + white_color, + sr_font_34, + 'lm', + ) + floor_pic.paste(content_center, (0, 390), content_center) + for buff in detail.buffs: + buff_icon = bufflist[buff.base_type.id] + buff_name = buff.base_type.name + buffs = buff.items + draw_height = await _draw_rogue_buff( + buffs, + buff_icon, + buff_name, + floor_pic, + buff_height, + ) + buff_height = buff_height + draw_height + + # 奇物 + miracles_height = buff_height + if len(detail.miracles) > 0: + floor_pic_draw.text( + (93, 370 + miracles_height + 60), + '获得奇物', + white_color, + sr_font_34, + 'lm', + ) + floor_pic.paste( + content_center, (0, 370 + miracles_height + 80), content_center + ) + draw_height = await _draw_rogue_miracles( + detail.miracles, + floor_pic, + miracles_height, + ) + miracles_height = miracles_height + 80 + miracles_height = miracles_height + draw_height + + # 事件 + blocks_height = miracles_height + if len(detail.blocks) > 0: + floor_pic_draw.text( + (93, 370 + blocks_height + 60), + '通过区域类型', + white_color, + sr_font_34, + 'lm', + ) + floor_pic.paste( + content_center, (0, 370 + blocks_height + 80), content_center + ) + draw_height = await _draw_rogue_blocks( + detail.blocks, + floor_pic, + blocks_height, + ) + blocks_height = blocks_height + 80 + blocks_height = blocks_height + draw_height + + if based_h_list[index_floor] is None: + continue + + img.paste(floor_pic, (0, based_h_list[index_floor]), floor_pic) + # await _draw_floor_card( + # level_star, + # floor_pic, + # img, + # index_floor, + # floor_name, + # round_num, + # ) + + res = await convert_img(img) + logger.info('[查询寰宇蝗灾]绘图已完成,等待发送!') + return res