diff --git a/apps/card.js b/apps/card.js index 95d2ede..62e7cb3 100644 --- a/apps/card.js +++ b/apps/card.js @@ -36,7 +36,6 @@ export class Card extends ZZZPlugin { }); if (!zzzBuddyList) return false; indexData.buddy_list = zzzBuddyList.list; - const finalIndexData = new ZZZIndexResp(indexData); this.e.playerCard.player.region_name = finalIndexData.stats.world_level_name; diff --git a/apps/gachalog.js b/apps/gachalog.js index 67f0ed0..56b27a3 100644 --- a/apps/gachalog.js +++ b/apps/gachalog.js @@ -103,10 +103,12 @@ export class GachaLog extends ZZZPlugin { } await redis.set(`ZZZ:GACHA:${uid}:LASTTIME`, Date.now()); this.reply('正在更新抽卡记录,可能需要一段时间,请耐心等待'); - const data = await updateGachaLog(key, uid); + const { data, count } = await updateGachaLog(key, uid); let msg = `抽卡记录更新成功,共${Object.keys(data).length}个卡池`; for (const name in data) { - msg += `\n${name}一共${data[name].length}条记录`; + msg += `\n${name}一共${data[name].length}条记录,新增${ + count[name] || 0 + }条记录`; } await this.reply(msg); return false; diff --git a/apps/panel.js b/apps/panel.js index 004e09c..b419bef 100644 --- a/apps/panel.js +++ b/apps/panel.js @@ -17,11 +17,11 @@ export class Panel extends ZZZPlugin { }, { reg: `${rulePrefix}面板列表$`, - fnc: 'getPanelList', + fnc: 'getCharPanelList', }, { reg: `${rulePrefix}(.+)面板$`, - fnc: 'getPanel', + fnc: 'getCharPanel', }, ], }); @@ -32,10 +32,11 @@ export class Panel extends ZZZPlugin { await this.getPlayerInfo(); const result = await refreshPanel(this.e, api, uid, deviceFp); const newChar = result.filter(item => item.isNew); - let str = '面板列表获取成功,本次共刷新了' + newChar.length + '个角色:'; + let str = '面板列表获取成功,本次共刷新了' + newChar.length + '个角色:\n'; for (const item of result) { - str += '\n' + item.name_mi18n; + str += item.name_mi18n + (item.isNew ? '(新)' : '') + '、'; } + str = str.slice(0, -1); str += '\n总计' + result.length + '个角色'; await this.reply(str); // const finalData = { @@ -43,7 +44,7 @@ export class Panel extends ZZZPlugin { // }; // await render(this.e, 'panel/refresh.html', finalData); } - async getPanelList() { + async getCharPanelList() { const uid = await this.getUID(); if (!uid) return false; const noteData = getPanelList(uid); @@ -59,16 +60,20 @@ export class Panel extends ZZZPlugin { // }; // await render(this.e, 'panel/list.html', finalData); } - async getPanel() { + async getCharPanel() { const uid = await this.getUID(); if (!uid) return false; const reg = new RegExp(`${rulePrefix}(.+)面板$`); const name = this.e.msg.match(reg)[4]; const data = getPanel(uid, name); - await this.reply(JSON.stringify(data, null, 2)); - // const finalData = { - // list: noteData, - // }; - // await render(this.e, 'panel/list.html', finalData); + if (!data) { + await this.reply(`未找到角色${name}的面板信息`); + return false; + } + await data.get_detail_assets(); + const finalData = { + charData: data, + }; + await render(this.e, 'panel/card.html', finalData); } } diff --git a/lib/avatar.js b/lib/avatar.js index 228c367..6e65a82 100644 --- a/lib/avatar.js +++ b/lib/avatar.js @@ -96,10 +96,11 @@ export function getPanelList(uid) { * @returns {ZZZAvatarInfo | null} */ export function getPanel(uid, name) { - logger.debug('获取面板数据', uid, name); - const data = getPanelData(uid).map(item => new ZZZAvatarInfo(item)); + const _data = getPanelData(uid); + const data = _data.map(item => new ZZZAvatarInfo(item)); const id = char.atlasToID(name); - logger.debug('获取角色ID', id); if (!id) return null; - return data.find(item => item.id === id) || null; + const result = data.find(item => item.id === id); + if (!result) return null; + return result; } diff --git a/lib/convert.js b/lib/convert.js index acd8188..5929cd9 100644 --- a/lib/convert.js +++ b/lib/convert.js @@ -3,3 +3,9 @@ export * as element from './convert/element.js'; export * as char from './convert/char.js'; export * as weapon from './convert/weapon.js'; + +export * as equip from './convert/equip.js'; + +export * as rank from './convert/rank.js'; + +export * as property from './convert/property.js'; diff --git a/lib/convert/char.js b/lib/convert/char.js index 4f86fba..21dbaa0 100644 --- a/lib/convert/char.js +++ b/lib/convert/char.js @@ -27,7 +27,7 @@ export const IDToCharName = (id, full = true, en = false) => { export const IDToCharSprite = id => { const data = PartnerId2SpriteId?.[id]; if (!data) return null; - return data?.['sprite']; + return data?.['sprite_id']; }; /** diff --git a/lib/convert/equip.js b/lib/convert/equip.js new file mode 100644 index 0000000..c3334c5 --- /dev/null +++ b/lib/convert/equip.js @@ -0,0 +1,19 @@ +import { getMapData } from '../../utils/file.js'; + +const equipData = getMapData('EquipId2Data'); + +/** + * 获取驱动盘装备的图片 + * @param {string | number} equipId + * @returns {string | null} + */ +export function equipIdToSprite(equipId) { + equipId = equipId.toString(); + if (equipId.length === 5) { + const suitId = equipId.slice(0, 3) + '00'; + if (equipData.hasOwnProperty(suitId)) { + return equipData[suitId]['sprite_file'].replace('3D', ''); + } + } + return null; +} diff --git a/lib/convert/property.js b/lib/convert/property.js new file mode 100644 index 0000000..2336d84 --- /dev/null +++ b/lib/convert/property.js @@ -0,0 +1,41 @@ +const prop_id = { + 111: 'hpmax', + 121: 'attack', + 131: 'def', + 122: 'breakstun', + 201: 'crit', + 211: 'critdam', + 314: 'elementabnormalpower', + 312: 'elementmystery', + 231: 'penratio', + 232: 'penvalue', + 305: 'sprecover', + 310: 'spgetratio', + 115: 'spmax', + 315: 'physdmg', + 316: 'fire', + 317: 'ice', + 318: 'thunder', + 319: 'dungeonbuffether', +}; + +const pro_id = { + 1: 'attack', + 2: 'stun', + 3: 'anomaly', + 4: 'support', + 5: 'defense', +}; + +/** + * 获取属性css类名 + * @param {string} _id 属性id + * @returns {string | null} + */ +export function idToClassName(_id) { + let propId = _id.toString(); + propId = propId.slice(0, 3); + const propIcon = prop_id[propId]; + if (!propIcon) return null; + return propIcon; +} diff --git a/lib/convert/rank.js b/lib/convert/rank.js new file mode 100644 index 0000000..cba0479 --- /dev/null +++ b/lib/convert/rank.js @@ -0,0 +1,14 @@ +const RANK_MAP = { + 4: 'S', + 3: 'A', + 2: 'B', +}; + +/** + * 获取星级对应的字母 + * @param {string | number} id + * @returns {string} + */ +export function getRankChar(id) { + return RANK_MAP[id] || ''; +} diff --git a/lib/download.js b/lib/download.js index a1a201d..85a989d 100644 --- a/lib/download.js +++ b/lib/download.js @@ -2,7 +2,7 @@ import path from 'path'; import fs from 'fs'; import { ZZZ_SQUARE_AVATAR, ZZZ_SQUARE_BANGBOO } from './mysapi/api.js'; import { imageResourcesPath } from './path.js'; -import { weapon } from './convert.js'; +import { char, equip, weapon } from './convert.js'; import { getResourceRemotePath } from './assets.js'; const ZZZ_SQUARE_AVATAR_PATH = path.join(imageResourcesPath, 'square_avatar'); @@ -11,9 +11,18 @@ const ZZZ_SQUARE_BANGBOO_PATH = path.join( 'bangboo_square_avatar' ); const ZZZ_WEAPON_PATH = path.join(imageResourcesPath, 'weapon'); -const ZZZ_GUIDES_PATH = path.join(imageResourcesPath, 'guides'); +const ZZZ_ROLE_PATH = path.join(imageResourcesPath, 'role'); +const ZZZ_ROLE_CIRCLE_PATH = path.join(imageResourcesPath, 'role_circle'); +const ZZZ_SUIT_3D_PATH = path.join(imageResourcesPath, 'suit_3d'); +const ZZZ_SUIT_PATH = path.join(imageResourcesPath, 'suit'); +// const ZZZ_GUIDES_PATH = path.join(imageResourcesPath, 'guides'); -// 将下面的下载封装起来,支持错误重试5次 +/** + * 下载文件 + * @param {string} url 下载地址 + * @param {string} savePath 保存路径 + * @returns + */ const downloadFile = async (url, savePath) => { const _download = async (url, savePath, retry = 0) => { if (retry > 5) { @@ -36,7 +45,7 @@ const downloadFile = async (url, savePath) => { }; /** - * + * 获取角色头像(方形) * @param {string | number} charID * @returns Promise */ @@ -51,7 +60,7 @@ export const getSquareAvatar = async charID => { }; /** - * + * 获取邦布头像(方形) * @param {string | number} bangbooId * @returns Promise */ @@ -66,7 +75,7 @@ export const getSquareBangboo = async bangbooId => { }; /** - * Get weapon image path + * 获取武器图片 * @param {string} id * @returns Promise */ @@ -80,6 +89,72 @@ export const getWeaponImage = async id => { const url = await getResourceRemotePath('weapon', filename); const savePath = weaponPath; const download = await downloadFile(url, savePath); - logger.mark('getWeaponImage', download); + logger.debug('getWeaponImage', download); + return download; +}; + +/** + * 获取角色图片 + * @param {string | number} id + * @returns Promise + */ +export const getRoleImage = async id => { + const sprite = char.IDToCharSprite(id); + if (sprite === null) return null; + const filename = `IconRole${sprite}.png`; + const rolePath = path.join(ZZZ_ROLE_PATH, filename); + if (fs.existsSync(rolePath)) return rolePath; + const url = await getResourceRemotePath('role', filename); + const savePath = rolePath; + const download = await downloadFile(url, savePath); + return download; +}; + +/** + * 获取角色圆形图片 + * @param {string | number} id + * @returns Promise + */ +export const getRoleCircleImage = async id => { + const sprite = char.IDToCharSprite(id); + if (sprite === null) return null; + const filename = `IconRoleCircle${sprite}.png`; + const roleCirclePath = path.join(ZZZ_ROLE_CIRCLE_PATH, filename); + if (fs.existsSync(roleCirclePath)) return roleCirclePath; + const url = await getResourceRemotePath('role_circle', filename); + const savePath = roleCirclePath; + const download = await downloadFile(url, savePath); + return download; +}; + +/** + * 获取套装图片 + * @param {string | number} suitId + * @returns Promise + */ +export const getSuitImage = async suitId => { + const suitName = equip.equipIdToSprite(suitId); + const filename = `${suitName}.png`; + const suitPath = path.join(ZZZ_SUIT_PATH, filename); + if (fs.existsSync(suitPath)) return suitPath; + const url = await getResourceRemotePath('suit', filename); + const savePath = suitPath; + const download = await downloadFile(url, savePath); + return download; +}; + +/** + * 获取3D套装图片 + * @param {string | number} suitId + * @returns Promise + */ +export const getSuit3DImage = async suitId => { + const suitName = equip.equipIdToSprite(suitId); + const filename = `${suitName}_3d.png`; + const suitPath = path.join(ZZZ_SUIT_3D_PATH, filename); + if (fs.existsSync(suitPath)) return suitPath; + const url = await getResourceRemotePath('suit_3d', filename); + const savePath = suitPath; + const download = await downloadFile(url, savePath); return download; }; diff --git a/lib/gacha.js b/lib/gacha.js index 6a1a952..00a2bee 100644 --- a/lib/gacha.js +++ b/lib/gacha.js @@ -1,5 +1,6 @@ import { SingleGachaLog, ZZZGachaLogResp } from '../model/gacha.js'; import { sleep } from '../utils/time.js'; +import { rank } from './convert.js'; import { getGachaLog, saveGachaLog } from './db.js'; import { ZZZ_GET_GACHA_LOG_API } from './mysapi/api.js'; @@ -96,7 +97,12 @@ export async function getZZZGachaLogByAuthkey( * @param {string} authKey * @param {string} uid * @returns {Promise<{ - * [x: string]: SingleGachaLog[]; + * data: { + * [x: string]: SingleGachaLog[]; + * }, + * count: { + * [x: string]: number; + * } * }>} */ export async function updateGachaLog(authKey, uid) { @@ -104,26 +110,13 @@ export async function updateGachaLog(authKey, uid) { if (!previousLog) { previousLog = {}; } + let newCount = {}; for (const name in gacha_type_meta_data) { if (!previousLog[name]) { previousLog[name] = []; } - previousLog[name] = previousLog[name].map( - i => - new SingleGachaLog( - i.uid, - i.gacha_id, - i.gacha_type, - i.item_id, - i.count, - i.time, - i.name, - i.lang, - i.item_type, - i.rank_type, - i.id - ) - ); + newCount[name] = 0; + previousLog[name] = previousLog[name].map(i => new SingleGachaLog(i)); const lastSaved = previousLog[name]?.[0]; let page = 1; let endId = '0'; @@ -145,6 +138,7 @@ export async function updateGachaLog(authKey, uid) { break queryLabel; } newData.push(item); + newCount[name]++; } endId = log.list[log.list.length - 1]?.id || endId; page++; @@ -154,14 +148,12 @@ export async function updateGachaLog(authKey, uid) { previousLog[name] = [...newData, ...previousLog[name]]; } saveGachaLog(uid, previousLog); - return previousLog; + return { + data: previousLog, + count: newCount, + }; } -const RANK_MAP = { - 4: 'S', - 3: 'A', - 2: 'B', -}; const HOMO_TAG = ['非到极致', '运气不好', '平稳保底', '小欧一把', '欧狗在此']; const EMOJI = [ [4, 8, 13], @@ -186,10 +178,10 @@ const NORMAL_LIST = [ ]; const FLOORS_MAP = { - '邦布频段': [50, 70], - '音擎频段': [50, 70], - '独家频段': [60, 80], - '常驻频段': [60, 80], + 邦布频段: [50, 70], + 音擎频段: [50, 70], + 独家频段: [60, 80], + 常驻频段: [60, 80], }; function getLevelFromList(ast, lst) { @@ -214,22 +206,7 @@ export async function anaylizeGachaLog(uid) { } const result = []; for (const name in savedData) { - const data = savedData[name].map( - item => - new SingleGachaLog( - item.uid, - item.gacha_id, - item.gacha_type, - item.item_id, - item.count, - item.time, - item.name, - item.lang, - item.item_type, - item.rank_type, - item.id - ) - ); + const data = savedData[name].map(item => new SingleGachaLog(item)); const earliest = data[data.length - 1]; const latest = data[0]; const list = []; @@ -256,7 +233,7 @@ export async function anaylizeGachaLog(uid) { } list.push({ ...item, - rank_type_label: RANK_MAP[item.rank_type], + rank_type_label: rank.getRankChar(item.rank_type), isUp: isUp, totalCount: '-', color: 'white', diff --git a/lib/render.js b/lib/render.js index 7990f8f..7441fa7 100644 --- a/lib/render.js +++ b/lib/render.js @@ -47,6 +47,7 @@ function render(e, renderPath, renderData = {}, cfg = {}) { resourcesPath: resPath, currentPath: renderPathFull, playerInfo: path.join(layoutPathFull, 'playerinfo.html'), + specialTitle: path.join(layoutPathFull, 'specialtitle.html'), copyright: `Created By ${version.name}${version.yunzai} & ${pluginName}${version.version}`, createdby: `Created By ${pluginName} & Powered By ZZZure`, }, diff --git a/model/avatar.js b/model/avatar.js index 46382a9..b4d1222 100644 --- a/model/avatar.js +++ b/model/avatar.js @@ -1,5 +1,5 @@ import { element } from '../lib/convert.js'; -import { getSquareAvatar } from '../lib/download.js'; +import { getRoleImage, getSquareAvatar } from '../lib/download.js'; import { Equip, Weapon } from './equip.js'; import { Property } from './property.js'; import { Skill } from './skill.js'; @@ -114,20 +114,40 @@ export class ZZZAvatarBasic { this.element_str = element.IDToElement(element_type); } + + async get_assets() { + const result = await getSquareAvatar(this.id); + this.square_icon = result; + } } /** * @class */ export class Rank { + // 类型标注 + /** @type {number} */ + id; + /** @type {string} */ + name; + /** @type {string} */ + desc; + /** @type {number} */ + pos; + /** @type {boolean} */ + is_unlocked; + /** - * @param {number} id - * @param {string} name - * @param {string} desc - * @param {number} pos - * @param {boolean} is_unlocked + * @param {{ + * id: number; + * name: string; + * desc: string; + * pos: number; + * is_unlocked: boolean; + * }} data */ - constructor(id, name, desc, pos, is_unlocked) { + constructor(data) { + const { id, name, desc, pos, is_unlocked } = data; this.id = id; this.name = name; this.desc = desc; @@ -158,11 +178,46 @@ export class ZZZAvatarInfo { * skills: Skill[]; * rank: number; * ranks: Rank[]; - * * isNew?: boolean; * }} data */ constructor(data) { + // 类型标注 + /** @type {number} */ + this.id; + /** @type {number} */ + this.level; + /** @type {string} */ + this.name_mi18n; + /** @type {string} */ + this.full_name_mi18n; + /** @type {number} */ + this.element_type; + /** @type {string} */ + this.camp_name_mi18n; + /** @type {number} */ + this.avatar_profession; + /** @type {string} */ + this.rarity; + /** @type {string} */ + this.group_icon_path; + /** @type {string} */ + this.hollow_icon_path; + /** @type {Equip[]} */ + this.equip; + /** @type {Weapon} */ + this.weapon; + /** @type {Property[]} */ + this.properties; + /** @type {Skill[]} */ + this.skills; + /** @type {number} */ + this.rank; + /** @type {Rank[]} */ + this.ranks; + /** @type {boolean} */ + this.isNew; + const { id, level, @@ -192,22 +247,59 @@ export class ZZZAvatarInfo { this.rarity = rarity; this.group_icon_path = group_icon_path; this.hollow_icon_path = hollow_icon_path; - this.equip = equip; - this.weapon = weapon; - this.properties = properties; - this.skills = skills; + this.equip = + equip && + (Array.isArray(equip) + ? equip.map(equip => new Equip(equip)) + : new Equip(equip)); + this.weapon = weapon ? new Weapon(weapon) : null; + this.properties = + properties && properties.map(property => new Property(property)); + this.skills = skills && skills.map(skill => new Skill(skill)); this.rank = rank; - this.ranks = ranks; + this.ranks = ranks && ranks.map(rank => new Rank(rank)); + + this.ranks_num = this.ranks.filter(rank => rank.is_unlocked).length; this.element_str = element.IDToElement(element_type); this.isNew = isNew; } + getProperty(name) { + return this.properties.find(property => property.property_name === name); + } + + get basic_properties() { + const data = { + hpmax: this.getProperty('生命值'), + attack: this.getProperty('攻击力'), + def: this.getProperty('防御力'), + breakstun: this.getProperty('冲击力'), + crit: this.getProperty('暴击率'), + critdam: this.getProperty('暴击伤害'), + elementabnormalpower: this.getProperty('异常掌控'), + elementmystery: this.getProperty('异常精通'), + penratio: this.getProperty('穿透率'), + sprecover: this.getProperty('能量自动回复'), + }; + logger.debug('basic_properties', data); + return data; + } + async get_basic_assets() { const result = await getSquareAvatar(this.id); this.square_icon = result; } + async get_detail_assets() { + const role_icon = await getRoleImage(this.id); + this.role_icon = role_icon; + await this.weapon.get_assets(); + for (const equip of this.equip) { + await equip.get_assets(); + } + } + async get_assets() { await this.get_basic_assets(); } diff --git a/model/equip.js b/model/equip.js index 8597344..0f0fe2e 100644 --- a/model/equip.js +++ b/model/equip.js @@ -1,16 +1,34 @@ +import { property } from '../lib/convert.js'; +import { getSuitImage, getWeaponImage } from '../lib/download.js'; + /** * @class */ export class EquipProperty { + // 类型标注 + /** @type {string} */ + property_name; + /** @type {number} */ + property_id; + /** @type {string} */ + base; + /** @type {string} */ + classname; + /** - * @param {string} property_name - * @param {number} property_id - * @param {string} base + * @param {{ + * property_name: string; + * property_id: number; + * base: string + * }} data */ - constructor(property_name, property_id, base) { + constructor(data) { + const { property_name, property_id, base } = data; this.property_name = property_name; this.property_id = property_id; this.base = base; + + this.classname = property.idToClassName(property_id); } } @@ -18,15 +36,30 @@ export class EquipProperty { * @class */ export class EquipMainProperty { + // 类型标注 + /** @type {string} */ + property_name; + /** @type {number} */ + property_id; + /** @type {string} */ + base; + /** @type {string} */ + classname; + /** - * @param {string} property_name - * @param {number} property_id - * @param {string} base + * @param {{ + * property_name: string; + * property_id: number; + * base: string; + * }} data */ - constructor(property_name, property_id, base) { + constructor(data) { + const { property_name, property_id, base } = data; this.property_name = property_name; this.property_id = property_id; this.base = base; + + this.classname = property.idToClassName(property_id); } } @@ -55,79 +88,143 @@ export class EquipSuit { */ export class Equip { /** - * @param {number} id - * @param {number} level - * @param {string} name - * @param {string} icon - * @param {string} rarity - * @param {EquipProperty[]} properties - * @param {EquipMainProperty[]} main_properties - * @param {EquipSuit} equip_suit - * @param {number} equipment_type + * @param {{ + * id: number; + * level: number; + * name: string; + * icon: string; + * rarity: string; + * properties: EquipProperty[]; + * main_properties: EquipMainProperty[]; + * equip_suit: EquipSuit; + * equipment_type: number; + * }} data */ - constructor( - id, - level, - name, - icon, - rarity, - properties, - main_properties, - equip_suit, - equipment_type - ) { + constructor(data) { + // 类型标注 + /** @type {number} */ + this.id; + /** @type {number} */ + this.level; + /** @type {string} */ + this.name; + /** @type {string} */ + this.icon; + /** @type {string} */ + this.rarity; + /** @type {EquipProperty[]} */ + this.properties; + /** @type {EquipMainProperty[]} */ + this.main_properties; + /** @type {EquipSuit} */ + this.equip_suit; + /** @type {number} */ + this.equipment_type; + + const { + id, + level, + name, + icon, + rarity, + properties, + main_properties, + equip_suit, + equipment_type, + } = data; this.id = id; this.level = level; this.name = name; this.icon = icon; this.rarity = rarity; - this.properties = properties; - this.main_properties = main_properties; + this.properties = properties.map(item => new EquipProperty(item)); + this.main_properties = main_properties.map( + item => new EquipMainProperty(item) + ); this.equip_suit = equip_suit; this.equipment_type = equipment_type; } + + async get_assets() { + const result = await getSuitImage(this.id); + this.suit_icon = result; + } } /** * @class */ export class Weapon { + // 类型标注 + /** @type {number} */ + id; + /** @type {number} */ + level; + /** @type {string} */ + name; + /** @type {number} */ + star; + /** @type {string} */ + icon; + /** @type {string} */ + rarity; + /** @type {EquipProperty[]} */ + properties; + /** @type {EquipMainProperty[]} */ + main_properties; + /** @type {string} */ + talent_title; + /** @type {string} */ + talent_content; + /** @type {number} */ + profession; + /** - * @param {number} id - * @param {number} level - * @param {string} name - * @param {number} star - * @param {string} icon - * @param {string} rarity - * @param {EquipProperty[]} properties - * @param {EquipMainProperty[]} main_properties - * @param {string} talent_title - * @param {string} talent_content - * @param {number} profession + * @param {{ + * id: number; + * level: number; + * name: string; + * star: number; + * icon: string; + * rarity: string; + * properties: EquipProperty[]; + * main_properties: EquipMainProperty[]; + * talent_title: string; + * talent_content: string; + * profession: number; + * }} data */ - constructor( - id, - level, - name, - star, - icon, - rarity, - properties, - main_properties, - talent_title, - talent_content, - profession - ) { + constructor(data) { + const { + id, + level, + name, + star, + icon, + rarity, + properties, + main_properties, + talent_title, + talent_content, + profession, + } = data; this.id = id; this.level = level; this.name = name; this.star = star; this.icon = icon; this.rarity = rarity; - this.properties = properties; - this.main_properties = main_properties; + this.properties = properties.map(item => new EquipProperty(item)); + this.main_properties = main_properties.map( + item => new EquipMainProperty(item) + ); this.talent_title = talent_title; this.talent_content = talent_content; this.profession = profession; } + + async get_assets() { + const result = await getWeaponImage(this.id); + this.square_icon = result; + } } diff --git a/model/gacha.js b/model/gacha.js index 4811ebd..ba0aaf5 100644 --- a/model/gacha.js +++ b/model/gacha.js @@ -8,32 +8,58 @@ import { * @class */ export class SingleGachaLog { + // 类型标注 + /** @type {string} */ + uid; + /** @type {string} */ + gacha_id; + /** @type {string} */ + gacha_type; + /** @type {string} */ + item_id; + /** @type {string} */ + count; + /** @type {string} */ + time; + /** @type {string} */ + name; + /** @type {string} */ + lang; + /** @type {string} */ + item_type; + /** @type {string} */ + rank_type; + /** @type {string} */ + id; /** - * @param {string} uid - * @param {string} gacha_id - * @param {string} gacha_type - * @param {string} item_id - * @param {string} count - * @param {string} time - * @param {string} name - * @param {string} lang - * @param {string} item_type - * @param {string} rank_type - * @param {string} id + * @param {{ + * uid: string; + * gacha_id: string; + * gacha_type: string; + * item_id: string; + * count: string; + * time: string; + * name: string; + * lang: string; + * item_type: string; + * rank_type: string; + * id: string; + * }} data */ - constructor( - uid, - gacha_id, - gacha_type, - item_id, - count, - time, - name, - lang, - item_type, - rank_type, - id - ) { + constructor(data) { + const { + uid, + gacha_id, + gacha_type, + item_id, + count, + time, + name, + lang, + item_type, + rank_type, + id, + } = data; this.uid = uid; this.gacha_id = gacha_id; this.gacha_type = gacha_type; @@ -93,22 +119,7 @@ export class ZZZGachaLogResp { const { page, size, list, region, region_time_zone } = data; this.page = page; this.size = size; - this.list = list.map( - item => - new SingleGachaLog( - item.uid, - item.gacha_id, - item.gacha_type, - item.item_id, - item.count, - item.time, - item.name, - item.lang, - item.item_type, - item.rank_type, - item.id - ) - ); + this.list = list.map(item => new SingleGachaLog(item)); this.region = region; this.region_time_zone = region_time_zone; } diff --git a/model/index.js b/model/index.js index b38159c..502140d 100644 --- a/model/index.js +++ b/model/index.js @@ -1,4 +1,4 @@ -import { ZZZAvatarInfo } from './avatar.js'; +import { ZZZAvatarBasic } from './avatar.js'; import { Buddy } from './bangboo.js'; /** @@ -34,7 +34,7 @@ export class ZZZIndexResp { /** * @param {{ * stats: Stats; - * avatar_list: ZZZAvatarInfo[]; + * avatar_list: ZZZAvatarBasic[]; * cur_head_icon_url: string; * buddy_list: Buddy[]; * }} data @@ -42,7 +42,7 @@ export class ZZZIndexResp { constructor(data) { const { stats, avatar_list, cur_head_icon_url, buddy_list } = data; this.stats = stats; - this.avatar_list = avatar_list.map(item => new ZZZAvatarInfo(item)); + this.avatar_list = avatar_list.map(item => new ZZZAvatarBasic(item)); this.cur_head_icon_url = cur_head_icon_url; this.buddy_list = buddy_list.map(item => new Buddy(item)); } diff --git a/model/property.js b/model/property.js index 0117285..199c023 100644 --- a/model/property.js +++ b/model/property.js @@ -3,13 +3,21 @@ */ export class Property { /** + * @param {{ + * property_name: string, + * property_id: number, + * base: string, + * add: string, + * final: string + * }} data * @param {string} property_name * @param {number} property_id * @param {string} base * @param {string} add * @param {string} final */ - constructor(property_name, property_id, base, add, final) { + constructor(data) { + const { property_name, property_id, base, add, final } = data; this.property_name = property_name; this.property_id = property_id; this.base = base; diff --git a/model/skill.js b/model/skill.js index 53fff4a..3ac0049 100644 --- a/model/skill.js +++ b/model/skill.js @@ -17,11 +17,14 @@ export class SkillItem { */ export class Skill { /** - * @param {number} level - * @param {number} skill_type - * @param {SkillItem[]} items + * @param {{ + * level: number, + * skill_type: number, + * items: SkillItem[] + * }} data */ - constructor(level, skill_type, items) { + constructor(data) { + const { level, skill_type, items } = data; this.level = level; this.skill_type = skill_type; this.items = items; diff --git a/resources/card/index.css b/resources/card/index.css index 028f4d0..280e549 100644 --- a/resources/card/index.css +++ b/resources/card/index.css @@ -42,7 +42,7 @@ width: 100%; position: relative; } -.card .list .item * { +.card .list .item > * { position: inherit; z-index: 1; } @@ -82,13 +82,44 @@ object-fit: contain; display: block; } -.card .list .item .level { +.card .list .item .c-info { position: absolute; bottom: 0; left: 0; width: 100%; background: rgb(0, 0, 0); color: white; + display: flex; + text-align: center; +} +.card .list .item .c-info .ranks { + background: rgb(117, 117, 117); + padding: 0 0.4em; +} +.card .list .item .c-info .ranks.r1 { + background: rgb(58, 116, 43); +} +.card .list .item .c-info .ranks.r2 { + background: rgb(61, 132, 214); +} +.card .list .item .c-info .ranks.r3 { + background: rgb(223, 118, 118); +} +.card .list .item .c-info .ranks.r4 { + background: rgb(51, 54, 161); +} +.card .list .item .c-info .ranks.r5 { + background: rgb(102, 127, 19); +} +.card .list .item .c-info .ranks.r6 { + background: rgb(218, 48, 32); +} +.card .list .item .c-info .level { + flex-grow: 1; + flex-shrink: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; text-align: center; } .card .list .item .property { diff --git a/resources/card/index.html b/resources/card/index.html index a742962..b89862e 100644 --- a/resources/card/index.html +++ b/resources/card/index.html @@ -25,62 +25,37 @@
式舆防卫战
-
-
- AGENT -
-
- -
-
- 代理人信息 -
-
- -
-
- - -
- {{each card.avatar_list char i}} -
-
-
-
- + <% include(sys.specialTitle, {en: 'AGENT' , cn: '代理人信息' }) %> +
+ {{each card.avatar_list char i}} +
+
+
+
+ +
+
+
{{char.rank}}命
+
等级{{char.level}}
+
-
等级{{char.level}}
+ {{/each}}
- {{/each}} -
- -
-
- BANGBOO -
-
- -
-
- 邦布信息 -
-
- -
-
- - -
- {{each card.buddy_list bangboo i}} -
-
-
- + <% include(sys.specialTitle, {en: 'BANGBOO' , cn: '邦布信息' }) %> +
+ {{each card.buddy_list bangboo i}} +
+
+
+ +
+
+
{{bangboo.star}}命
+
等级{{bangboo.level}}
+
+
+ {{/each}}
-
等级{{bangboo.level}}
-
- {{/each}} -
{{/block}} \ No newline at end of file diff --git a/resources/card/index.scss b/resources/card/index.scss index 8038adf..b4b80a3 100644 --- a/resources/card/index.scss +++ b/resources/card/index.scss @@ -39,7 +39,7 @@ .item { width: 100%; position: relative; - * { + > * { position: inherit; z-index: 1; } @@ -83,14 +83,45 @@ display: block; } } - .level { + .c-info { position: absolute; bottom: 0; left: 0; width: 100%; background: rgb(0, 0, 0); color: white; + display: flex; text-align: center; + .ranks { + background: rgb(117, 117, 117); + padding: 0 0.4em; + &.r1 { + background: rgb(58, 116, 43); + } + &.r2 { + background: rgb(61, 132, 214); + } + &.r3 { + background: rgb(223, 118, 118); + } + &.r4 { + background: rgb(51, 54, 161); + } + &.r5 { + background: rgb(102, 127, 19); + } + &.r6 { + background: rgb(218, 48, 32); + } + } + .level { + flex-grow: 1; + flex-shrink: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; + } } .property { position: absolute; diff --git a/resources/common/images/Rarity_A.png b/resources/common/images/Rarity_A.png new file mode 100644 index 0000000..f8b3f5e Binary files /dev/null and b/resources/common/images/Rarity_A.png differ diff --git a/resources/common/images/Rarity_B.png b/resources/common/images/Rarity_B.png new file mode 100644 index 0000000..f2327f5 Binary files /dev/null and b/resources/common/images/Rarity_B.png differ diff --git a/resources/common/images/Rarity_C.png b/resources/common/images/Rarity_C.png new file mode 100644 index 0000000..8eacada Binary files /dev/null and b/resources/common/images/Rarity_C.png differ diff --git a/resources/common/images/Rarity_S.png b/resources/common/images/Rarity_S.png new file mode 100644 index 0000000..79296cf Binary files /dev/null and b/resources/common/images/Rarity_S.png differ diff --git a/resources/common/images/Rarity_X.png b/resources/common/images/Rarity_X.png new file mode 100644 index 0000000..115641a Binary files /dev/null and b/resources/common/images/Rarity_X.png differ diff --git a/resources/common/images/prop/IconAnomaly.png b/resources/common/images/prop/IconAnomaly.png new file mode 100644 index 0000000..ce0ad08 Binary files /dev/null and b/resources/common/images/prop/IconAnomaly.png differ diff --git a/resources/common/images/prop/IconAttack.png b/resources/common/images/prop/IconAttack.png new file mode 100644 index 0000000..24cdfcc Binary files /dev/null and b/resources/common/images/prop/IconAttack.png differ diff --git a/resources/common/images/prop/IconDefense.png b/resources/common/images/prop/IconDefense.png new file mode 100644 index 0000000..b86a4e1 Binary files /dev/null and b/resources/common/images/prop/IconDefense.png differ diff --git a/resources/common/images/prop/IconStun.png b/resources/common/images/prop/IconStun.png new file mode 100644 index 0000000..1a979a8 Binary files /dev/null and b/resources/common/images/prop/IconStun.png differ diff --git a/resources/common/images/prop/IconSupport.png b/resources/common/images/prop/IconSupport.png new file mode 100644 index 0000000..beda074 Binary files /dev/null and b/resources/common/images/prop/IconSupport.png differ diff --git a/resources/common/images/property/IconAttack.png b/resources/common/images/property/IconAttack.png new file mode 100644 index 0000000..45474fb Binary files /dev/null and b/resources/common/images/property/IconAttack.png differ diff --git a/resources/common/images/property/IconBreakStun.png b/resources/common/images/property/IconBreakStun.png new file mode 100644 index 0000000..05be316 Binary files /dev/null and b/resources/common/images/property/IconBreakStun.png differ diff --git a/resources/common/images/property/IconCrit.png b/resources/common/images/property/IconCrit.png new file mode 100644 index 0000000..1ef093e Binary files /dev/null and b/resources/common/images/property/IconCrit.png differ diff --git a/resources/common/images/property/IconCritDam.png b/resources/common/images/property/IconCritDam.png new file mode 100644 index 0000000..62bfbef Binary files /dev/null and b/resources/common/images/property/IconCritDam.png differ diff --git a/resources/common/images/property/IconDef.png b/resources/common/images/property/IconDef.png new file mode 100644 index 0000000..c3da92f Binary files /dev/null and b/resources/common/images/property/IconDef.png differ diff --git a/resources/common/images/property/IconDungeonBuffEther.png b/resources/common/images/property/IconDungeonBuffEther.png new file mode 100644 index 0000000..445ef76 Binary files /dev/null and b/resources/common/images/property/IconDungeonBuffEther.png differ diff --git a/resources/common/images/property/IconElementAbnormalPower.png b/resources/common/images/property/IconElementAbnormalPower.png new file mode 100644 index 0000000..e6a8777 Binary files /dev/null and b/resources/common/images/property/IconElementAbnormalPower.png differ diff --git a/resources/common/images/property/IconElementMystery.png b/resources/common/images/property/IconElementMystery.png new file mode 100644 index 0000000..83ae249 Binary files /dev/null and b/resources/common/images/property/IconElementMystery.png differ diff --git a/resources/common/images/property/IconFire.png b/resources/common/images/property/IconFire.png new file mode 100644 index 0000000..65ee97a Binary files /dev/null and b/resources/common/images/property/IconFire.png differ diff --git a/resources/common/images/property/IconHpMax.png b/resources/common/images/property/IconHpMax.png new file mode 100644 index 0000000..13b5a11 Binary files /dev/null and b/resources/common/images/property/IconHpMax.png differ diff --git a/resources/common/images/property/IconIce.png b/resources/common/images/property/IconIce.png new file mode 100644 index 0000000..921a74c Binary files /dev/null and b/resources/common/images/property/IconIce.png differ diff --git a/resources/common/images/property/IconPenRatio.png b/resources/common/images/property/IconPenRatio.png new file mode 100644 index 0000000..6daaa45 Binary files /dev/null and b/resources/common/images/property/IconPenRatio.png differ diff --git a/resources/common/images/property/IconPenValue.png b/resources/common/images/property/IconPenValue.png new file mode 100644 index 0000000..d1613fa Binary files /dev/null and b/resources/common/images/property/IconPenValue.png differ diff --git a/resources/common/images/property/IconPhysDmg.png b/resources/common/images/property/IconPhysDmg.png new file mode 100644 index 0000000..a30fff0 Binary files /dev/null and b/resources/common/images/property/IconPhysDmg.png differ diff --git a/resources/common/images/property/IconSpGetRatio.png b/resources/common/images/property/IconSpGetRatio.png new file mode 100644 index 0000000..1efef1f Binary files /dev/null and b/resources/common/images/property/IconSpGetRatio.png differ diff --git a/resources/common/images/property/IconSpMax.png b/resources/common/images/property/IconSpMax.png new file mode 100644 index 0000000..b14dbe9 Binary files /dev/null and b/resources/common/images/property/IconSpMax.png differ diff --git a/resources/common/images/property/IconSpRecover.png b/resources/common/images/property/IconSpRecover.png new file mode 100644 index 0000000..bb5657a Binary files /dev/null and b/resources/common/images/property/IconSpRecover.png differ diff --git a/resources/common/images/property/IconThunder.png b/resources/common/images/property/IconThunder.png new file mode 100644 index 0000000..fe436ce Binary files /dev/null and b/resources/common/images/property/IconThunder.png differ diff --git a/resources/common/layout/specialtitle.html b/resources/common/layout/specialtitle.html new file mode 100644 index 0000000..008cf19 --- /dev/null +++ b/resources/common/layout/specialtitle.html @@ -0,0 +1,18 @@ +
+
+ {{en}} +
+
+ <% for(let i=1 ; i < (count || 9) ; i++) { %> + + <% } %> +
+
+ {{cn}} +
+
+ <% for(let i=1 ; i < (count || 9) ; i++) { %> + + <% } %> +
+
\ No newline at end of file diff --git a/resources/common/style/index.css b/resources/common/style/index.css index 372dea3..027be13 100644 --- a/resources/common/style/index.css +++ b/resources/common/style/index.css @@ -34,6 +34,28 @@ background-image: url("../images/RANK_B.png"); } +.rarity-icon { + aspect-ratio: 1; + background-repeat: no-repeat; + background-position: center; + background-size: contain; +} +.rarity-icon.a, .rarity-icon.A { + background-image: url("../images/Rarity_A.png"); +} +.rarity-icon.b, .rarity-icon.B { + background-image: url("../images/Rarity_B.png"); +} +.rarity-icon.c, .rarity-icon.C { + background-image: url("../images/Rarity_C.png"); +} +.rarity-icon.s, .rarity-icon.S { + background-image: url("../images/Rarity_S.png"); +} +.rarity-icon.x, .rarity-icon.X { + background-image: url("../images/Rarity_X.png"); +} + .property { aspect-ratio: 1; background-size: contain; @@ -56,6 +78,89 @@ background-image: url("../images/IconDungeonBuffEther.png"); } +.prop-icon { + aspect-ratio: 1; + background-size: contain; + background-position: center; + background-repeat: no-repeat; +} +.prop-icon.attack { + background-image: url("../images/property/IconAttack.png"); +} +.prop-icon.breakstun { + background-image: url("../images/property/IconBreakStun.png"); +} +.prop-icon.crit { + background-image: url("../images/property/IconCrit.png"); +} +.prop-icon.critdam { + background-image: url("../images/property/IconCritDam.png"); +} +.prop-icon.def { + background-image: url("../images/property/IconDef.png"); +} +.prop-icon.dungeonbuffether { + background-image: url("../images/property/IconDungeonBuffEther.png"); +} +.prop-icon.elementabnormalpower { + background-image: url("../images/property/IconElementAbnormalPower.png"); +} +.prop-icon.elementmystery { + background-image: url("../images/property/IconElementMystery.png"); +} +.prop-icon.fire { + background-image: url("../images/property/IconFire.png"); +} +.prop-icon.hpmax { + background-image: url("../images/property/IconHpMax.png"); +} +.prop-icon.ice { + background-image: url("../images/property/IconIce.png"); +} +.prop-icon.penratio { + background-image: url("../images/property/IconPenRatio.png"); +} +.prop-icon.penvalue { + background-image: url("../images/property/IconPenValue.png"); +} +.prop-icon.physdmg { + background-image: url("../images/property/IconPhysDmg.png"); +} +.prop-icon.spgetratio { + background-image: url("../images/property/IconSpGetRatio.png"); +} +.prop-icon.spmax { + background-image: url("../images/property/IconSpMax.png"); +} +.prop-icon.sprecover { + background-image: url("../images/property/IconSpRecover.png"); +} +.prop-icon.thunder { + background-image: url("../images/property/IconThunder.png"); +} + +.pro-icon { + aspect-ratio: 1; + background-size: contain; + background-position: center; + background-repeat: no-repeat; +} +.pro-icon.anomaly { + background-image: url("../images/prop/IconAnomaly.png"); +} +.pro-icon.attack { + background-image: url("../images/prop/IconAttack.png"); +} +.pro-icon.defense { + background-image: url("../images/prop/IconDefence.png"); +} +.pro-icon.stun { + background-image: url("../images/prop/IconStun.png"); +} +.pro-icon.support { + background-image: url("../images/prop/IconSupport.png"); +} + .special-title { width: 100%; background-size: contain; diff --git a/resources/common/style/index.scss b/resources/common/style/index.scss index f8c070d..0a09a5d 100644 --- a/resources/common/style/index.scss +++ b/resources/common/style/index.scss @@ -59,6 +59,33 @@ } } +.rarity-icon { + aspect-ratio: 1; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + &.a, + &.A { + background-image: url('../images/Rarity_A.png'); + } + &.b, + &.B { + background-image: url('../images/Rarity_B.png'); + } + &.c, + &.C { + background-image: url('../images/Rarity_C.png'); + } + &.s, + &.S { + background-image: url('../images/Rarity_S.png'); + } + &.x, + &.X { + background-image: url('../images/Rarity_X.png'); + } +} + .property { aspect-ratio: 1; background-size: contain; @@ -81,6 +108,89 @@ } } +.prop-icon { + aspect-ratio: 1; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + &.attack { + background-image: url('../images/property/IconAttack.png'); + } + &.breakstun { + background-image: url('../images/property/IconBreakStun.png'); + } + &.crit { + background-image: url('../images/property/IconCrit.png'); + } + &.critdam { + background-image: url('../images/property/IconCritDam.png'); + } + &.def { + background-image: url('../images/property/IconDef.png'); + } + &.dungeonbuffether { + background-image: url('../images/property/IconDungeonBuffEther.png'); + } + &.elementabnormalpower { + background-image: url('../images/property/IconElementAbnormalPower.png'); + } + &.elementmystery { + background-image: url('../images/property/IconElementMystery.png'); + } + &.fire { + background-image: url('../images/property/IconFire.png'); + } + &.hpmax { + background-image: url('../images/property/IconHpMax.png'); + } + &.ice { + background-image: url('../images/property/IconIce.png'); + } + &.penratio { + background-image: url('../images/property/IconPenRatio.png'); + } + &.penvalue { + background-image: url('../images/property/IconPenValue.png'); + } + &.physdmg { + background-image: url('../images/property/IconPhysDmg.png'); + } + &.spgetratio { + background-image: url('../images/property/IconSpGetRatio.png'); + } + &.spmax { + background-image: url('../images/property/IconSpMax.png'); + } + &.sprecover { + background-image: url('../images/property/IconSpRecover.png'); + } + &.thunder { + background-image: url('../images/property/IconThunder.png'); + } +} + +.pro-icon { + aspect-ratio: 1; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + &.anomaly { + background-image: url('../images/prop/IconAnomaly.png'); + } + &.attack { + background-image: url('../images/prop/IconAttack.png'); + } + &.defense { + background-image: url('../images/prop/IconDefence.png'); + } + &.stun { + background-image: url('../images/prop/IconStun.png'); + } + &.support { + background-image: url('../images/prop/IconSupport.png'); + } +} + .special-title { width: 100%; background-size: contain; diff --git a/resources/map/EquipId2Data_1.0.0.json b/resources/map/EquipId2Data.json similarity index 100% rename from resources/map/EquipId2Data_1.0.0.json rename to resources/map/EquipId2Data.json diff --git a/resources/note/index.html b/resources/note/index.html index 5ad6e9e..b9a4555 100644 --- a/resources/note/index.html +++ b/resources/note/index.html @@ -7,80 +7,54 @@ {{block 'main'}}
{{include sys.playerInfo}} -
-
- STAMINA -
-
- -
-
- 电池电量 -
-
- -
-
- -
-
- -
-
-
-
电量
-
{{note.energy.progress.current}}/{{note.energy.progress.max}}
+ <% include(sys.specialTitle, {en: 'STAMINA' , cn: '电池电量' }) %> +
+
+
-
-
剩余
-
{{note.energy.progress.rest}}
-
-
-
-
+
+
+
电量
+
{{note.energy.progress.current}}/{{note.energy.progress.max}} +
+
+
+
剩余
+
{{note.energy.progress.rest}}
+
+
+
+
+
-
-
-
- ACTIVE -
-
- -
-
- 每日情况 -
-
- -
-
-
-
-
-
今日活跃度
-
- {{note.vitality.current}} - /{{note.vitality.max}} + <% include(sys.specialTitle, {en: 'ACTIVE' , cn: '每日情况' }) %> +
+
+
+
今日活跃度
+
+ {{note.vitality.current}} + /{{note.vitality.max}} +
+
+
+
+
录像店经营
+
+ {{note.vhs_sale.state_label}} +
+
+
+
+
刮刮卡
+
+ {{note.sign_label}} +
+
-
-
-
-
录像店经营
-
- {{note.vhs_sale.state_label}} -
-
-
-
-
刮刮卡
-
- {{note.sign_label}} -
-
-
{{/block}} \ No newline at end of file diff --git a/resources/panel/card.css b/resources/panel/card.css new file mode 100644 index 0000000..24b6b39 --- /dev/null +++ b/resources/panel/card.css @@ -0,0 +1,592 @@ +.card { + padding-top: 0.8em; + overflow: hidden; +} +.card .star { + width: 5.5em; + height: 1.5em; +} +.card .star.star0 { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url("./images/star/0.png"); +} +.card .star.star1 { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url("./images/star/1.png"); +} +.card .star.star2 { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url("./images/star/2.png"); +} +.card .star.star3 { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url("./images/star/3.png"); +} +.card .star.star4 { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url("./images/star/4.png"); +} +.card .star.star5 { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url("./images/star/5.png"); +} +.card .basic { + display: flex; + align-items: stretch; + overflow: hidden; +} +.card .basic .char { + width: 55%; + position: relative; + flex-grow: 1; +} +.card .basic .char .avatar { + height: 100%; + padding-top: 1em; + overflow: hidden; +} +.card .basic .char .avatar img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: top center; + position: absolute; +} +.card .basic .char .skills { + position: absolute; + width: 120%; + height: 3.5em; + background: url("./images/skill_bg.png"); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + bottom: 3em; + right: -1.6em; + display: flex; + align-items: flex-end; + padding-left: 2.5em; + padding-bottom: 0.2em; +} +.card .basic .char .skills .skill { + width: 1.4em; + aspect-ratio: 1; + margin-right: 1.38em; + display: flex; + justify-content: center; + align-items: center; +} +.card .basic .info { + width: 45%; + flex-grow: 0; + flex-shrink: 0; + font-size: 1.2em; + position: relative; + z-index: 2; +} +.card .basic .info .char_info { + width: 140%; + position: relative; + right: 20%; + padding: 0.3em 0.2em; + padding-right: 20%; + padding-left: 8%; + border-image-slice: 0 30 0 40 fill; + border-image-width: 0em 1.5em 0em 2em; + border-image-outset: 0 0 0 0; + border-image-repeat: stretch stretch; + border-image-source: url("./images/CurseBG04.png"); + filter: drop-shadow(0 0 0.1em rgb(0, 0, 0)); +} +.card .basic .info .char_info .base { + display: flex; + align-items: center; + gap: 0.2em; + overflow: hidden; +} +.card .basic .info .char_info .base .rank { + width: 1.2em; + flex-grow: 0; + flex-shrink: 0; +} +.card .basic .info .char_info .base .property { + width: 1em; + flex-grow: 0; + flex-shrink: 0; +} +.card .basic .info .char_info .base .name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.card .basic .info .char_info .addition { + display: flex; + align-items: center; + font-size: 0.7em; + gap: 0.2em; + padding-left: 1em; +} +.card .basic .info .char_info .addition .level { + background-color: #000; + padding: 0em 0.7em; + border-radius: 1em; +} +.card .basic .info .char_info .addition .role_ranks { + display: flex; + gap: 0.1em; +} +.card .basic .info .char_info .addition .role_ranks span { + width: 1.2em; + aspect-ratio: 1; + border-radius: 1em; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + opacity: 0.4; +} +.card .basic .info .char_info .addition .role_ranks span:nth-child(1) { + background-image: url("./images/ranks/1.png"); +} +.card .basic .info .char_info .addition .role_ranks.r1 span:nth-child(1) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks span:nth-child(2) { + background-image: url("./images/ranks/2.png"); +} +.card .basic .info .char_info .addition .role_ranks.r2 span:nth-child(1) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r2 span:nth-child(2) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks span:nth-child(3) { + background-image: url("./images/ranks/3.png"); +} +.card .basic .info .char_info .addition .role_ranks.r3 span:nth-child(1) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r3 span:nth-child(2) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r3 span:nth-child(3) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks span:nth-child(4) { + background-image: url("./images/ranks/4.png"); +} +.card .basic .info .char_info .addition .role_ranks.r4 span:nth-child(1) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r4 span:nth-child(2) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r4 span:nth-child(3) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r4 span:nth-child(4) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks span:nth-child(5) { + background-image: url("./images/ranks/5.png"); +} +.card .basic .info .char_info .addition .role_ranks.r5 span:nth-child(1) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r5 span:nth-child(2) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r5 span:nth-child(3) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r5 span:nth-child(4) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r5 span:nth-child(5) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks span:nth-child(6) { + background-image: url("./images/ranks/6.png"); +} +.card .basic .info .char_info .addition .role_ranks.r6 span:nth-child(1) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r6 span:nth-child(2) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r6 span:nth-child(3) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r6 span:nth-child(4) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r6 span:nth-child(5) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r6 span:nth-child(6) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks span:nth-child(7) { + background-image: url("./images/ranks/7.png"); +} +.card .basic .info .char_info .addition .role_ranks.r7 span:nth-child(1) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r7 span:nth-child(2) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r7 span:nth-child(3) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r7 span:nth-child(4) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r7 span:nth-child(5) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r7 span:nth-child(6) { + opacity: 1 !important; +} +.card .basic .info .char_info .addition .role_ranks.r7 span:nth-child(7) { + opacity: 1 !important; +} +.card .basic .info .property_info { + background-color: rgb(47, 47, 47); + border-left: 0.1em solid rgb(0, 0, 0); + padding-top: 0.2em; + background: url("./images/BgFrame01.png") center/150% no-repeat; +} +.card .basic .info .property_info .title { + font-size: 0.6em; +} +.card .basic .info .property_info .title .special-title { + margin-bottom: 0; + padding-bottom: 0; +} +.card .basic .info .property_info .list { + display: flex; + flex-direction: column; + gap: 0.2em; + padding-bottom: 0.2em; +} +.card .basic .info .property_info .list .properties { + display: flex; + align-items: center; + gap: 0.4em; + padding: 0.05em 1em 0em 0.05em; +} +.card .basic .info .property_info .list .properties:nth-child(odd) { + background-color: rgba(221, 224, 221, 0.25); +} +.card .basic .info .property_info .list .properties .prop-icon { + width: 1em; + flex-grow: 0; + flex-shrink: 0; + margin: 0 0.4em; +} +.card .basic .info .property_info .list .properties .label { + flex-grow: 1; + flex-shrink: 1; + font-size: 0.65em; + color: rgb(166, 166, 166); +} +.card .basic .info .property_info .list .properties .label.yellow { + color: rgb(247, 199, 54); +} +.card .basic .info .property_info .list .properties .label.blue { + color: rgb(65, 147, 237); +} +.card .basic .info .property_info .list .properties .value { + flex-grow: 0; + flex-shrink: 0; + font-size: 0.8em; +} +.card .basic .info .weapon_info { + border-image-slice: 118 0 68 43 fill; + border-image-width: 4.5em 0em 2.7em 1.7em; + border-image-outset: 0em 0em 0em 0em; + border-image-repeat: stretch stretch; + border-image-source: url("./images/weapon_bg.png"); + margin-top: -0.8em; + width: 115%; + margin-left: -15%; + font-size: 0.8em; + padding: 2em 1.2em; + padding-bottom: 3em; + position: relative; + overflow: hidden; +} +.card .basic .info .weapon_info .info { + width: 100%; + position: relative; + z-index: 2; +} +.card .basic .info .weapon_info .info .base { + width: 100%; + display: flex; + align-items: center; + gap: 0.5em; +} +.card .basic .info .weapon_info .info .base .rarity-icon { + width: 2em; +} +.card .basic .info .weapon_info .info .base .name { + text-shadow: 0 0 0.2em rgb(0, 0, 0); +} +.card .basic .info .weapon_info .info .main { + display: flex; + flex-direction: column; + justify-content: stretch; + width: max-content; +} +.card .basic .info .weapon_info .info .main .addition { + font-size: 0.8em; + display: flex; + align-items: center; + gap: 0.4em; +} +.card .basic .info .weapon_info .info .main .addition .level { + -webkit-clip-path: polygon(0.2em 0%, calc(100% - 0.2em) 0%, 100% 0.2em, 100% calc(100% - 0.2em), calc(100% - 0.2em) 100%, 0.2em 100%, 0% calc(100% - 0.2em), 0% 0.2em); + clip-path: polygon(0.2em 0%, calc(100% - 0.2em) 0%, 100% 0.2em, 100% calc(100% - 0.2em), calc(100% - 0.2em) 100%, 0.2em 100%, 0% calc(100% - 0.2em), 0% 0.2em); + padding: 0 0.4em; + font-size: 0.9em; + display: flex; + justify-content: center; + align-items: center; + color: rgb(43, 38, 40); + margin: 0.1em 0; + background-color: rgb(243, 203, 69); +} +.card .basic .info .weapon_info .info .main .properties { + display: flex; + align-items: center; + background-color: rgb(65, 147, 237); + gap: 0.2em; + padding: 0 0.5em; + border-radius: 1em; + margin: 0.2em 0; +} +.card .basic .info .weapon_info .info .main .properties.sub { + background-color: rgb(0, 0, 0); +} +.card .basic .info .weapon_info .info .main .properties .prop-icon { + width: 1em; + flex-grow: 0; + flex-shrink: 0; +} +.card .basic .info .weapon_info .info .main .properties .label { + flex-grow: 1; + flex-shrink: 1; + font-size: 0.7em; + color: rgb(222, 222, 222); +} +.card .basic .info .weapon_info .icon { + position: absolute; + top: 1.2em; + right: 0; + z-index: 1; + height: 70%; + margin-right: -1em; +} +.card .basic .info .weapon_info .icon img { + height: 100%; +} +.card .other { + border-image-source: url("./images/BgFrame01.png"); + border-image-slice: 200 100 70 280 fill; + border-image-width: 2em 1em 0.7em 2.8em; + border-image-outset: 2em 1em 0.7em 2.8em; + border-image-repeat: stretch stretch; + padding-bottom: 3.3em; + margin-top: -1.4em; + position: relative; + z-index: 5; +} +.card .equip-list { + display: grid; + gap: 1em; + grid-template-columns: repeat(3, 1fr); + padding: 0 1.8em; + align-items: stretch; + margin-top: 1em; +} +.card .equip-list .box { + border-image-source: url("./images/equip_bg.png"); + border-image-slice: 190 90 110 170 fill; + border-image-width: 5.7em 2.7em 3.3em 5.1em; + border-image-outset: 1.8em 1.5em 1.8em 1.5em; + border-image-repeat: stretch stretch; + position: relative; + margin-top: 1.3em; + padding-bottom: 1em; + min-height: 10em; +} +.card .equip-list .box.empty::after { + content: ""; + position: absolute; + width: 2.5em; + height: 2.5em; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-image: url("./images/empty_equip_07.png"); + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} +.card .equip-list .box:nth-child(1)::before { + content: "01"; + position: absolute; + font-size: 2em; + left: 50%; + top: -0.85em; + transform: translate(-50%, 0); + z-index: -1; +} +.card .equip-list .box:nth-child(2)::before { + content: "02"; + position: absolute; + font-size: 2em; + left: 50%; + top: -0.85em; + transform: translate(-50%, 0); + z-index: -1; +} +.card .equip-list .box:nth-child(3)::before { + content: "03"; + position: absolute; + font-size: 2em; + left: 50%; + top: -0.85em; + transform: translate(-50%, 0); + z-index: -1; +} +.card .equip-list .box:nth-child(4)::before { + content: "04"; + position: absolute; + font-size: 2em; + left: 50%; + top: -0.85em; + transform: translate(-50%, 0); + z-index: -1; +} +.card .equip-list .box:nth-child(5)::before { + content: "05"; + position: absolute; + font-size: 2em; + left: 50%; + top: -0.85em; + transform: translate(-50%, 0); + z-index: -1; +} +.card .equip-list .box:nth-child(6)::before { + content: "06"; + position: absolute; + font-size: 2em; + left: 50%; + top: -0.85em; + transform: translate(-50%, 0); + z-index: -1; +} +.card .equip-list .box .icon { + width: 2.7em; + aspect-ratio: 1; + position: relative; + left: -0.9em; + top: -1.2em; + background-color: rgb(0, 0, 0); + background-image: url("./images/empty_equip_03.png"); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + border-radius: 50%; +} +.card .equip-list .box .icon img { + width: 100%; + height: 100%; + object-fit: contain; + display: block; +} +.card .equip-list .box .info { + display: flex; + padding-left: 2.2em; + margin-top: -2.5em; + gap: 0.5em; + align-items: center; +} +.card .equip-list .box .info .level { + flex-grow: 1; + flex-shrink: 1; + text-align: center; + font-size: 0.76em; + background-color: #000; + padding: 0.1em 0.5em; + border-radius: 1em; + margin-bottom: 0.3em; +} +.card .equip-list .box .info .rarity-icon { + width: 2.2em; +} +.card .equip-list .box .name { + padding: 0 0.5em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; +} +.card .equip-list .box .property-list { + padding: 0 0.5em; +} +.card .equip-list .box .property-list .properties { + display: flex; + align-items: center; + background-color: rgb(0, 0, 0); + gap: 0.2em; + padding: 0 0.5em; + border-radius: 1em; + margin: 0.2em 0; +} +.card .equip-list .box .property-list .properties .prop-icon { + width: 1em; + flex-grow: 0; + flex-shrink: 0; +} +.card .equip-list .box .property-list .properties .label { + flex-grow: 1; + flex-shrink: 1; + font-size: 0.7em; + color: rgb(222, 222, 222); +} +.card .equip-list .box .property-list .properties .value { + color: rgb(249, 189, 64); + font-size: 0.7em; +} +.card .equip-list .box .property-list .properties.main { + background-color: rgb(65, 147, 237); +} +.card .equip-list .box .property-list .properties.main .prop-icon { + width: 1.2em; + margin-bottom: 0.2em; +} +.card .equip-list .box .property-list .properties.main .value { + color: rgb(255, 255, 255); + font-size: 1em; +} + +.copyright { + margin-top: -3.3em; + position: relative; + z-index: 5; +} + +/*# sourceMappingURL=card.css.map */ diff --git a/resources/panel/card.html b/resources/panel/card.html new file mode 100644 index 0000000..297015c --- /dev/null +++ b/resources/panel/card.html @@ -0,0 +1,178 @@ +{{extend defaultLayout}} + +{{block 'css'}} + +{{/block}} + +{{block 'main'}} +
+
+
+
+ +
+
+ {{each charData.skills skill}} +
{{skill.level}}
+ {{/each}} +
+
+
+
+
+
+
+
{{charData.full_name_mi18n}}
+
+
+
Lv.{{charData.level}}
+
+ +
+
+
+
+
+ <% include(sys.specialTitle, {en: 'PROPERTY' , cn: '属性' , count: 6 }) %> +
+
+
+
+
生命值
+
{{charData.basic_properties.hpmax.final}}
+
+
+
+
攻击力
+
{{charData.basic_properties.attack.final}}
+
+
+
+
防御力
+
{{charData.basic_properties.def.final}}
+
+
+
+
冲击力
+
{{charData.basic_properties.breakstun.final}}
+
+
+
+
暴击率
+
{{charData.basic_properties.crit.final}}
+
+
+
+
暴击伤害
+
{{charData.basic_properties.critdam.final}}
+
+
+
+
异常掌控
+
{{charData.basic_properties.elementabnormalpower.final}}
+
+
+
+
异常精通
+
{{charData.basic_properties.elementmystery.final}}
+
+
+
+
穿透率
+
{{charData.basic_properties.penratio.final}}
+
+
+
+
能量恢复
+
{{charData.basic_properties.sprecover.final}}
+
+
+
+
+ {{if charData.weapon}} +
+
+
+
{{charData.weapon.name}}
+
+
+
+
+
Lv.{{charData.weapon.level}}
+
+ {{each charData.weapon.main_properties prop}} +
+
+
{{prop.property_name}}
+
{{prop.base}}
+
+ {{/each}} + {{each charData.weapon.properties prop}} +
+
+
{{prop.property_name}}
+
{{prop.base}}
+
+ {{/each}} +
+
+
+ +
+ {{else}} +
+
+
+
+
+
+ {{/if}} +
+
+
+
+
+ <% include(sys.specialTitle, {en: 'METAL' , cn: '驱动盘信息' }) %> +
+
+ {{each charData.equip equip}} +
+
+ +
+
+
等级{{equip.level}}
+
+
+
{{equip.name}}
+
+ + {{each equip.main_properties prop}} +
+
+
{{prop.property_name}}
+
{{prop.base}}
+
+ {{/each}} + + {{each equip.properties prop}} +
+
+
{{prop.property_name}}
+
{{prop.base}}
+
+ {{/each}} +
+
+ {{/each}} + <% for(let i=charData.equip.length; i < 6 ; i++) { %> +
+
+
+
+ <% } %> + +
+
+
+{{/block}} \ No newline at end of file diff --git a/resources/panel/card.scss b/resources/panel/card.scss new file mode 100644 index 0000000..3333025 --- /dev/null +++ b/resources/panel/card.scss @@ -0,0 +1,449 @@ +.card { + padding-top: 0.8em; + overflow: hidden; + .star { + width: 5.5em; + height: 1.5em; + @for $i from 0 through 5 { + &.star#{$i} { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url('./images/star/#{$i}.png'); + } + } + } + .basic { + display: flex; + align-items: stretch; + overflow: hidden; + .char { + width: 55%; + position: relative; + flex-grow: 1; + .avatar { + height: 100%; + padding-top: 1em; + overflow: hidden; + img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: top center; + position: absolute; + } + } + .skills { + position: absolute; + width: 120%; + height: 3.5em; + background: url('./images/skill_bg.png'); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + bottom: 3em; + right: -1.6em; + display: flex; + align-items: flex-end; + padding-left: 2.5em; + padding-bottom: 0.2em; + .skill { + width: 1.4em; + aspect-ratio: 1; + margin-right: 1.38em; + display: flex; + justify-content: center; + align-items: center; + } + } + } + .info { + width: 45%; + flex-grow: 0; + flex-shrink: 0; + font-size: 1.2em; + position: relative; + z-index: 2; + .char_info { + width: 140%; + position: relative; + right: 20%; + padding: 0.3em 0.2em; + padding-right: 20%; + padding-left: 8%; + border-image-slice: 0 30 0 40 fill; + border-image-width: 0em 1.5em 0em 2em; + border-image-outset: 0 0 0 0; + border-image-repeat: stretch stretch; + border-image-source: url('./images/CurseBG04.png'); + filter: drop-shadow(0 0 0.1em rgb(0, 0, 0)); + .base { + display: flex; + align-items: center; + gap: 0.2em; + overflow: hidden; + .rank { + width: 1.2em; + flex-grow: 0; + flex-shrink: 0; + } + .property { + width: 1em; + flex-grow: 0; + flex-shrink: 0; + } + .name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + .addition { + display: flex; + align-items: center; + font-size: 0.7em; + gap: 0.2em; + padding-left: 1em; + .level { + background-color: #000; + padding: 0em 0.7em; + border-radius: 1em; + } + .role_ranks { + display: flex; + gap: 0.1em; + span { + width: 1.2em; + aspect-ratio: 1; + border-radius: 1em; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + opacity: 0.4; + } + @for $i from 1 through 7 { + span:nth-child(#{$i}) { + background-image: url('./images/ranks/#{$i}.png'); + } + &.r#{$i} { + @for $j from 1 through $i { + span:nth-child(#{$j}) { + opacity: 1 !important; + } + } + } + } + } + } + } + .property_info { + background-color: rgb(47, 47, 47); + border-left: 0.1em solid rgb(0, 0, 0); + padding-top: 0.2em; + background: url('./images/BgFrame01.png') center / 150% no-repeat; + .title { + font-size: 0.6em; + .special-title { + margin-bottom: 0; + padding-bottom: 0; + } + } + .list { + display: flex; + flex-direction: column; + gap: 0.2em; + padding-bottom: 0.2em; + .properties { + display: flex; + align-items: center; + gap: 0.4em; + padding: 0.05em 1em 0em 0.05em; + &:nth-child(odd) { + background-color: rgba(221, 224, 221, 0.25); + } + .prop-icon { + width: 1em; + flex-grow: 0; + flex-shrink: 0; + margin: 0 0.4em; + } + .label { + flex-grow: 1; + flex-shrink: 1; + font-size: 0.65em; + color: rgb(166, 166, 166); + &.yellow { + color: rgb(247, 199, 54); + } + &.blue { + color: rgb(65, 147, 237); + } + } + .value { + flex-grow: 0; + flex-shrink: 0; + font-size: 0.8em; + } + } + } + } + .weapon_info { + border-image-slice: 118 0 68 43 fill; + border-image-width: 4.5em 0em 2.7em 1.7em; + border-image-outset: 0em 0em 0em 0em; + border-image-repeat: stretch stretch; + border-image-source: url('./images/weapon_bg.png'); + margin-top: -0.8em; + width: 115%; + margin-left: -15%; + font-size: 0.8em; + padding: 2em 1.2em; + padding-bottom: 3em; + position: relative; + overflow: hidden; + .info { + width: 100%; + position: relative; + z-index: 2; + .base { + width: 100%; + display: flex; + align-items: center; + gap: 0.5em; + .rarity-icon { + width: 2em; + } + .name { + text-shadow: 0 0 0.2em rgb(0, 0, 0); + } + } + .main { + display: flex; + flex-direction: column; + justify-content: stretch; + width: max-content; + .addition { + font-size: 0.8em; + display: flex; + align-items: center; + gap: 0.4em; + .level { + $label-width: 0.2em; + -webkit-clip-path: polygon( + $label-width 0%, + calc(100% - $label-width) 0%, + 100% $label-width, + 100% calc(100% - $label-width), + calc(100% - $label-width) 100%, + $label-width 100%, + 0% calc(100% - $label-width), + 0% $label-width + ); + clip-path: polygon( + $label-width 0%, + calc(100% - $label-width) 0%, + 100% $label-width, + 100% calc(100% - $label-width), + calc(100% - $label-width) 100%, + $label-width 100%, + 0% calc(100% - $label-width), + 0% $label-width + ); + padding: 0 0.4em; + font-size: 0.9em; + display: flex; + justify-content: center; + align-items: center; + color: rgb(43, 38, 40); + margin: 0.1em 0; + background-color: rgb(243, 203, 69); + } + } + .properties { + display: flex; + align-items: center; + background-color: rgb(65, 147, 237); + gap: 0.2em; + padding: 0 0.5em; + border-radius: 1em; + margin: 0.2em 0; + &.sub { + background-color: rgb(0, 0, 0); + } + .prop-icon { + width: 1em; + flex-grow: 0; + flex-shrink: 0; + } + .label { + flex-grow: 1; + flex-shrink: 1; + font-size: 0.7em; + color: rgb(222, 222, 222); + } + } + } + } + .icon { + position: absolute; + top: 1.2em; + right: 0; + z-index: 1; + height: 70%; + margin-right: -1em; + img { + height: 100%; + } + } + } + } + } + .other { + border-image-source: url('./images/BgFrame01.png'); + border-image-slice: 200 100 70 280 fill; + border-image-width: 2em 1em 0.7em 2.8em; + border-image-outset: 2em 1em 0.7em 2.8em; + border-image-repeat: stretch stretch; + padding-bottom: 3.3em; + margin-top: -1.4em; + position: relative; + z-index: 5; + } + .equip-list { + display: grid; + gap: 1em; + grid-template-columns: repeat(3, 1fr); + padding: 0 1.8em; + align-items: stretch; + margin-top: 1em; + .box { + $size: 3em; + border-image-source: url('./images/equip_bg.png'); + border-image-slice: 190 90 110 170 fill; + border-image-width: 1.9 * $size 0.9 * $size 1.1 * $size 1.7 * $size; + border-image-outset: 0.6 * $size 0.5 * $size 0.6 * $size 0.5 * $size; + border-image-repeat: stretch stretch; + position: relative; + margin-top: 1.3em; + padding-bottom: 1em; + min-height: 10em; + &.empty { + &::after { + content: ''; + position: absolute; + width: 2.5em; + height: 2.5em; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-image: url('./images/empty_equip_07.png'); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } + } + @for $i from 1 through 6 { + &:nth-child(#{$i}) { + &::before { + content: '0#{$i}'; + position: absolute; + font-size: 2em; + left: 50%; + top: -0.85em; + transform: translate(-50%, 0); + z-index: -1; + } + } + } + .icon { + width: 0.9 * $size; + aspect-ratio: 1; + position: relative; + left: -0.3 * $size; + top: -0.4 * $size; + background-color: rgb(0, 0, 0); + background-image: url('./images/empty_equip_03.png'); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + border-radius: 50%; + img { + width: 100%; + height: 100%; + object-fit: contain; + display: block; + } + } + .info { + display: flex; + padding-left: 2.2em; + margin-top: -2.5em; + gap: 0.5em; + align-items: center; + .level { + flex-grow: 1; + flex-shrink: 1; + text-align: center; + font-size: 0.76em; + background-color: #000; + padding: 0.1em 0.5em; + border-radius: 1em; + margin-bottom: 0.3em; + } + .rarity-icon { + width: 2.2em; + } + } + .name { + padding: 0 0.5em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; + } + .property-list { + padding: 0 0.5em; + .properties { + display: flex; + align-items: center; + background-color: rgb(0, 0, 0); + gap: 0.2em; + padding: 0 0.5em; + border-radius: 1em; + margin: 0.2em 0; + .prop-icon { + width: 1em; + flex-grow: 0; + flex-shrink: 0; + } + .label { + flex-grow: 1; + flex-shrink: 1; + font-size: 0.7em; + color: rgb(222, 222, 222); + } + .value { + color: rgb(249, 189, 64); + font-size: 0.7em; + } + &.main { + background-color: rgb(65, 147, 237); + .prop-icon { + width: 1.2em; + margin-bottom: 0.2em; + } + .value { + color: rgb(255, 255, 255); + font-size: 1em; + } + } + } + } + } + } +} +.copyright { + margin-top: -3.3em; + position: relative; + z-index: 5; +} diff --git a/resources/panel/images/BgFrame01.png b/resources/panel/images/BgFrame01.png new file mode 100644 index 0000000..74ba009 Binary files /dev/null and b/resources/panel/images/BgFrame01.png differ diff --git a/resources/panel/images/CurseBG04.png b/resources/panel/images/CurseBG04.png new file mode 100644 index 0000000..2952753 Binary files /dev/null and b/resources/panel/images/CurseBG04.png differ diff --git a/resources/panel/images/GroceryActivityBtnBg.png b/resources/panel/images/GroceryActivityBtnBg.png new file mode 100644 index 0000000..47c5dae Binary files /dev/null and b/resources/panel/images/GroceryActivityBtnBg.png differ diff --git a/resources/panel/images/empty_equip_03.png b/resources/panel/images/empty_equip_03.png new file mode 100644 index 0000000..dc1c6a3 Binary files /dev/null and b/resources/panel/images/empty_equip_03.png differ diff --git a/resources/panel/images/empty_equip_07.png b/resources/panel/images/empty_equip_07.png new file mode 100644 index 0000000..6e7e1ed Binary files /dev/null and b/resources/panel/images/empty_equip_07.png differ diff --git a/resources/panel/images/equip_bg.png b/resources/panel/images/equip_bg.png new file mode 100644 index 0000000..bf0d569 Binary files /dev/null and b/resources/panel/images/equip_bg.png differ diff --git a/resources/panel/images/ranks/1.png b/resources/panel/images/ranks/1.png new file mode 100644 index 0000000..ded03a6 Binary files /dev/null and b/resources/panel/images/ranks/1.png differ diff --git a/resources/panel/images/ranks/2.png b/resources/panel/images/ranks/2.png new file mode 100644 index 0000000..d5b2c8c Binary files /dev/null and b/resources/panel/images/ranks/2.png differ diff --git a/resources/panel/images/ranks/3.png b/resources/panel/images/ranks/3.png new file mode 100644 index 0000000..c187b8b Binary files /dev/null and b/resources/panel/images/ranks/3.png differ diff --git a/resources/panel/images/ranks/4.png b/resources/panel/images/ranks/4.png new file mode 100644 index 0000000..1493698 Binary files /dev/null and b/resources/panel/images/ranks/4.png differ diff --git a/resources/panel/images/ranks/5.png b/resources/panel/images/ranks/5.png new file mode 100644 index 0000000..4681659 Binary files /dev/null and b/resources/panel/images/ranks/5.png differ diff --git a/resources/panel/images/ranks/6.png b/resources/panel/images/ranks/6.png new file mode 100644 index 0000000..956bb78 Binary files /dev/null and b/resources/panel/images/ranks/6.png differ diff --git a/resources/panel/images/skill_bg.png b/resources/panel/images/skill_bg.png new file mode 100644 index 0000000..b8f2895 Binary files /dev/null and b/resources/panel/images/skill_bg.png differ diff --git a/resources/panel/images/star/0.png b/resources/panel/images/star/0.png new file mode 100644 index 0000000..f32ae82 Binary files /dev/null and b/resources/panel/images/star/0.png differ diff --git a/resources/panel/images/star/1.png b/resources/panel/images/star/1.png new file mode 100644 index 0000000..3acb404 Binary files /dev/null and b/resources/panel/images/star/1.png differ diff --git a/resources/panel/images/star/2.png b/resources/panel/images/star/2.png new file mode 100644 index 0000000..dba6abe Binary files /dev/null and b/resources/panel/images/star/2.png differ diff --git a/resources/panel/images/star/3.png b/resources/panel/images/star/3.png new file mode 100644 index 0000000..8c3f26a Binary files /dev/null and b/resources/panel/images/star/3.png differ diff --git a/resources/panel/images/star/4.png b/resources/panel/images/star/4.png new file mode 100644 index 0000000..2ab7f19 Binary files /dev/null and b/resources/panel/images/star/4.png differ diff --git a/resources/panel/images/star/5.png b/resources/panel/images/star/5.png new file mode 100644 index 0000000..8078185 Binary files /dev/null and b/resources/panel/images/star/5.png differ diff --git a/resources/panel/images/weapon_bg.png b/resources/panel/images/weapon_bg.png new file mode 100644 index 0000000..1616807 Binary files /dev/null and b/resources/panel/images/weapon_bg.png differ