From f0348841a34f56128410ca2e108d1186f047d9e9 Mon Sep 17 00:00:00 2001 From: Kokomi <102026640+yoimiya-kokomi@users.noreply.github.com> Date: Wed, 22 Feb 2023 03:49:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E8=B0=83=E9=9D=A2=E6=9D=BF=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/profile.js | 8 +- apps/profile/ProfileDetail.js | 388 +++++++++++++----------- apps/profile/ProfileRank.js | 6 +- models/Artifact.js | 5 +- models/ProfileData.js | 4 + models/ProfileDmg.js | 5 +- models/ProfileReq.js | 11 +- models/Weapon.js | 87 +++++- models/profile/ArtisMark.js | 8 +- models/profile/AttrCalc.js | 32 +- resources/character/profile-detail.css | 6 +- resources/character/profile-detail.html | 337 ++++++++++---------- resources/character/profile-detail.less | 29 +- 13 files changed, 512 insertions(+), 414 deletions(-) diff --git a/apps/profile.js b/apps/profile.js index 72fbd79b..85f0c361 100644 --- a/apps/profile.js +++ b/apps/profile.js @@ -1,7 +1,7 @@ import { App, Cfg } from '../components/index.js' import { profileHelp } from './profile/ProfileCommon.js' import { profileArtisList } from './profile/ProfileArtis.js' -import { profileDetail } from './profile/ProfileDetail.js' +import ProfileDetail from './profile/ProfileDetail.js' import ProfileStat from './profile/ProfileStat.js' import ProfileList from './profile/ProfileList.js' import { uploadCharacterImg, delProfileImg, profileImgList } from './character/ImgUpload.js' @@ -16,13 +16,13 @@ let app = App.init({ app.reg({ profileDetail: { name: '角色面板', - fn: profileDetail, - rule: /^#*([^#]+)\s*(详细|详情|面板|面版|圣遗物|伤害[1-7]?)\s*(\d{9})*(.*[换变改].*)?$/ + fn: ProfileDetail.detail, + rule: /^#*([^#]+)\s*(详细|详情|面板|面版|圣遗物|武器[1-7]?|伤害[1-7]?)\s*(\d{9})*(.*[换变改].*)?$/ }, profileChange: { name: '角色面板计算', - fn: profileDetail, + fn: ProfileDetail.detail, rule: /^#.+换.+$/ }, diff --git a/apps/profile/ProfileDetail.js b/apps/profile/ProfileDetail.js index 9caa3ee6..e1607820 100644 --- a/apps/profile/ProfileDetail.js +++ b/apps/profile/ProfileDetail.js @@ -2,210 +2,228 @@ import lodash from 'lodash' import { getTargetUid, getProfileRefresh } from './ProfileCommon.js' import ProfileList from './ProfileList.js' import { Cfg, Common, Format } from '../../components/index.js' -import { MysApi, ProfileRank, ProfileArtis, Player, Character } from '../../models/index.js' +import { MysApi, ProfileRank, ProfileArtis, Character, Weapon } from '../../models/index.js' import ProfileChange from './ProfileChange.js' import { profileArtis } from './ProfileArtis.js' // 查看当前角色 -export async function profileDetail (e) { - let msg = e.original_msg || e.msg - if (!msg) { - return false - } - if (!/详细|详情|面板|面版|圣遗物|伤害|换/.test(msg)) { - return false - } - let mode = 'profile' - let profileChange = false - let changeMsg = msg - let pc = ProfileChange.matchMsg(msg) - if (pc && pc.char && pc.change) { - if (!Cfg.get('profileChange')) { - e.reply('面板替换功能已禁用...') +let ProfileDetail = { + async detail (e) { + let msg = e.original_msg || e.msg + if (!msg) { + return false + } + if (!/详细|详情|面板|面版|圣遗物|伤害|武器|换/.test(msg)) { + return false + } + let mode = 'profile' + let profileChange = false + let changeMsg = msg + let pc = ProfileChange.matchMsg(msg) + if (pc && pc.char && pc.change) { + if (!Cfg.get('profileChange')) { + e.reply('面板替换功能已禁用...') + return true + } + e.uid = pc.uid || e.runtime.uid + profileChange = ProfileChange.getProfile(e.uid, pc.char, pc.change) + if (profileChange && profileChange.char) { + msg = `#${profileChange.char?.name}${pc.mode || '面板'}` + e._profile = profileChange + e._profileMsg = changeMsg + } + } + let uidRet = /[0-9]{9}/.exec(msg) + if (uidRet) { + e.uid = uidRet[0] + msg = msg.replace(uidRet[0], '') + } + + let name = msg.replace(/#|老婆|老公/g, '').trim() + msg = msg.replace('面版', '面板') + let dmgRet = /(?:伤害|武器)(\d?)$/.exec(name) + let dmgIdx = 0 + if (/(最强|最高|最高分|最牛|第一)/.test(msg)) { + mode = /(分|圣遗物|评分|ACE)/.test(msg) ? 'rank-mark' : 'rank-dmg' + name = name.replace(/(最强|最高分|第一|最高|最牛|圣遗物|评分|群)/g, '') + } + if (/(详情|详细|面板|面版)\s*$/.test(msg) && !/更新|录入|输入/.test(msg)) { + mode = 'profile' + name = name.replace(/(详情|详细|面板)/, '').trim() + } else if (dmgRet) { + // mode = /武器/.test(msg) ? 'weapon' : 'dmg' + mode = 'dmg' + name = name.replace(/(伤害|武器)+[0-7]?/, '').trim() + if (dmgRet[1]) { + dmgIdx = dmgRet[1] * 1 + } + } else if (/(详情|详细|面板)更新$/.test(msg) || (/更新/.test(msg) && /(详情|详细|面板)$/.test(msg))) { + mode = 'refresh' + name = name.replace(/详情|详细|面板|更新/g, '').trim() + } else if (/圣遗物/.test(msg)) { + mode = 'artis' + name = name.replace('圣遗物', '').trim() + } + if (!Common.cfg('avatarProfile')) { + return false // 面板开关关闭 + } + let char = Character.get(name.trim()) + if (!char) { + return false + } + + let uid = e.uid || await getTargetUid(e) + if (!uid) { return true } - e.uid = pc.uid || e.runtime.uid - profileChange = ProfileChange.getProfile(e.uid, pc.char, pc.change) - if (profileChange && profileChange.char) { - msg = `#${profileChange.char?.name}${pc.mode || '面板'}` - e._profile = profileChange - e._profileMsg = changeMsg - } - } - let uidRet = /[0-9]{9}/.exec(msg) - if (uidRet) { - e.uid = uidRet[0] - msg = msg.replace(uidRet[0], '') - } + e.uid = uid + e.avatar = char.id - let name = msg.replace(/#|老婆|老公/g, '').trim() - msg = msg.replace('面版', '面板') - let dmgRet = /伤害(\d?)$/.exec(name) - let dmgIdx = 0 - if (/(最强|最高|最高分|最牛|第一)/.test(msg)) { - mode = /(分|圣遗物|评分|ACE)/.test(msg) ? 'rank-mark' : 'rank-dmg' - name = name.replace(/(最强|最高分|第一|最高|最牛|圣遗物|评分|群)/g, '') - } - if (/(详情|详细|面板|面版)\s*$/.test(msg) && !/更新|录入|输入/.test(msg)) { - mode = 'profile' - name = name.replace(/(详情|详细|面板)/, '').trim() - } else if (dmgRet) { - mode = 'dmg' - name = name.replace(/伤害[0-5]?/, '').trim() - if (dmgRet[1]) { - dmgIdx = dmgRet[1] * 1 - } - } else if (/(详情|详细|面板)更新$/.test(msg) || (/更新/.test(msg) && /(详情|详细|面板)$/.test(msg))) { - mode = 'refresh' - name = name.replace(/详情|详细|面板|更新/g, '').trim() - } else if (/圣遗物/.test(msg)) { - mode = 'artis' - name = name.replace('圣遗物', '').trim() - } - if (!Common.cfg('avatarProfile')) { - return false // 面板开关关闭 - } - let char = Character.get(name.trim()) - if (!char) { - return false - } - - let uid = e.uid || await getTargetUid(e) - if (!uid) { - return true - } - e.uid = uid - e.avatar = char.id - - if (char.isCustom) { - e.reply('自定义角色暂不支持此功能') - return true - } - if (!char.isRelease) { - if (!profileChange) { - e.reply('角色尚未实装') - return true - } else if (Cfg.get('notReleasedData') === false) { - e.reply('未实装角色面板已禁用...') + if (char.isCustom) { + e.reply('自定义角色暂不支持此功能') return true } - } + if (!char.isRelease) { + if (!profileChange) { + e.reply('角色尚未实装') + return true + } else if (Cfg.get('notReleasedData') === false) { + e.reply('未实装角色面板已禁用...') + return true + } + } - if (mode === 'profile' || mode === 'dmg') { - return renderProfile(e, char, mode, { dmgIdx }) - } else if (mode === 'refresh') { - await ProfileList.refresh(e) + if (mode === 'profile' || mode === 'dmg' || mode === 'weapon') { + return ProfileDetail.render(e, char, mode, { dmgIdx }) + } else if (mode === 'refresh') { + await ProfileList.refresh(e) + return true + } else if (mode === 'artis') { + return profileArtis(e) + } return true - } else if (mode === 'artis') { - return profileArtis(e) - } - return true -} + }, -export async function renderProfile (e, char, mode = 'profile', params = {}) { - let selfUser = await MysApi.initUser(e) + async render (e, char, mode = 'profile', params = {}) { + let selfUser = await MysApi.initUser(e) - if (!selfUser) { - e.reply('尚未绑定UID') + if (!selfUser) { + e.reply('尚未绑定UID') + return true + } + + let { uid } = e + + if (char.isCustom) { + e.reply(`暂不支持自定义角色${char.name}的面板信息查看`) + return true + } + + let profile = e._profile || await getProfileRefresh(e, char.id) + if (!profile) { + return true + } + char = profile.char || char + let a = profile.attr + let c = Format.comma + let p = Format.pct + let attr = { + hp: c(a.hp), + hpPlus: c(a.hp - a.hpBase), + atk: c(a.atk), + atkPlus: c(a.atk - a.atkBase), + def: c(a.def), + defPlus: c(a.def - a.defBase), + cpct: p(a.cpct), + cdmg: p(a.cdmg), + mastery: c(a.mastery), + recharge: p(a.recharge), + dmg: p(Math.max(a.dmg * 1 || 0, a.phy * 1 || 0)) + } + + let weapon = Weapon.get(profile.weapon.name) + let w = profile.weapon + let wCfg = {} + if (mode === 'weapon') { + wCfg = weapon.calcAttr(w.level, w.promote) + wCfg.info = weapon.getAffixInfo(weapon.affix) + } + + let enemyLv = await selfUser.getCfg('char.enemyLv', 91) + let dmgCalc = await ProfileDetail.getProfileDmgCalc({ profile, enemyLv, mode, params }) + + let rank = false + if (e.group_id && !e._profile) { + rank = await ProfileRank.create({ group: e.group_id, uid, qq: e.user_id }) + await rank.getRank(profile, true) + } + + let artisDetail = profile.getArtisMark() + let artisKeyTitle = ProfileArtis.getArtisKeyTitle() + let costumeSplash = profile.costumeSplash + // 渲染图像 + let msgRes = await Common.render('character/profile-detail', { + save_id: uid, + uid, + data: profile.getData('name,abbr,cons,level,weapon,talent,dataSource,updateTime,imgs,costumeSplash'), + attr, + elem: char.elem, + dmgCalc, + artisDetail, + artisKeyTitle, + bodyClass: `char-${char.name}`, + mode, + wCfg, + changeProfile: e._profileMsg + }, { e, scale: 1.6, retMsgId: true }) + if (msgRes && msgRes.message_id) { + // 如果消息发送成功,就将message_id和图片路径存起来,3小时过期 + await redis.set(`miao:original-picture:${msgRes.message_id}`, JSON.stringify({ + type: 'profile', + img: costumeSplash + }), { EX: 3600 * 3 }) + } return true - } + }, - let { uid } = e - - if (char.isCustom) { - e.reply(`暂不支持自定义角色${char.name}的面板信息查看`) - return true - } - - let profile = e._profile || await getProfileRefresh(e, char.id) - if (!profile) { - return true - } - char = profile.char || char - let a = profile.attr - let c = Format.comma - let p = Format.pct - let attr = { - hp: c(a.hp), - hpPlus: c(a.hp - a.hpBase), - atk: c(a.atk), - atkPlus: c(a.atk - a.atkBase), - def: c(a.def), - defPlus: c(a.def - a.defBase), - cpct: p(a.cpct), - cdmg: p(a.cdmg), - mastery: c(a.mastery), - recharge: p(a.recharge), - dmg: p(Math.max(a.dmg * 1 || 0, a.phy * 1 || 0)) - } - - let enemyLv = await selfUser.getCfg('char.enemyLv', 91) - let dmgMsg = [] - let dmgData = [] - let dmgCalc = await profile.calcDmg({ - enemyLv, - mode, - ...params - }) - if (dmgCalc && dmgCalc.ret) { - lodash.forEach(dmgCalc.ret, (ds) => { - ds.dmg = Format.comma(ds.dmg, 0) - ds.avg = Format.comma(ds.avg, 0) - dmgData.push(ds) + async getProfileDmgCalc ({ profile, enemyLv, mode, params }) { + let dmgMsg = [] + let dmgData = [] + let dmgCalc = await profile.calcDmg({ + enemyLv, + mode, + ...params }) - lodash.forEach(dmgCalc.msg, (msg) => { - msg.replace(':', ':') - dmgMsg.push(msg.split(':')) - }) - } - - if (mode === 'dmg' && dmgCalc.dmgRet) { - let basic = dmgCalc?.dmgCfg?.basicRet - lodash.forEach(dmgCalc.dmgRet, (row) => { - lodash.forEach(row, (ds) => { - ds.val = (ds.avg > basic.avg ? '+' : '') + Format.comma(ds.avg - basic.avg) + if (dmgCalc && dmgCalc.ret) { + lodash.forEach(dmgCalc.ret, (ds) => { ds.dmg = Format.comma(ds.dmg, 0) ds.avg = Format.comma(ds.avg, 0) + dmgData.push(ds) + }) + lodash.forEach(dmgCalc.msg, (msg) => { + msg.replace(':', ':') + dmgMsg.push(msg.split(':')) }) - }) - basic.dmg = Format.comma(basic.dmg) - basic.avg = Format.comma(basic.avg) - } - let rank = false - if (e.group_id && !e._profile) { - rank = await ProfileRank.create({ group: e.group_id, uid, qq: e.user_id }) - await rank.getRank(profile, true) - } - let artisDetail = profile.getArtisMark() - let artisKeyTitle = ProfileArtis.getArtisKeyTitle() - let imgs = char.getImgs(profile.costume) - let costumeSplash = profile.costumeSplash - // 渲染图像 - let msgRes = await Common.render('character/profile-detail', { - save_id: uid, - uid, - data: profile.getData('name,abbr,cons,level,weapon,talent,dataSource,updateTime'), - attr, - elem: char.elem, - dmgData, - dmgMsg, - dmgRet: dmgCalc.dmgRet || false, - dmgCfg: dmgCalc.dmgCfg || false, - artisDetail, - artisKeyTitle, - enemyLv, - imgs, - costumeSplash, - enemyName: dmgCalc.enemyName || '小宝', - talentMap: { a: '普攻', e: '战技', q: '爆发' }, - bodyClass: `char-${char.name}`, - mode, - changeProfile: e._profileMsg - }, { e, scale: 1.6, retMsgId: true }) - if (msgRes && msgRes.message_id) { - // 如果消息发送成功,就将message_id和图片路径存起来,3小时过期 - await redis.set(`miao:original-picture:${msgRes.message_id}`, JSON.stringify({ type: 'profile', img: costumeSplash }), { EX: 3600 * 3 }) + dmgCalc.dmgMsg = dmgMsg + dmgCalc.dmgData = dmgData + } + + if (mode === 'dmg' && dmgCalc.dmgRet) { + let basic = dmgCalc?.dmgCfg?.basicRet + lodash.forEach(dmgCalc.dmgRet, (row) => { + lodash.forEach(row, (ds) => { + ds.val = (ds.avg > basic.avg ? '+' : '') + Format.comma(ds.avg - basic.avg) + ds.dmg = Format.comma(ds.dmg, 0) + ds.avg = Format.comma(ds.avg, 0) + }) + }) + basic.dmg = Format.comma(basic.dmg) + basic.avg = Format.comma(basic.avg) + } + + return dmgCalc } - return true } + +export default ProfileDetail diff --git a/apps/profile/ProfileRank.js b/apps/profile/ProfileRank.js index 26ffcd53..b2ffbdd2 100644 --- a/apps/profile/ProfileRank.js +++ b/apps/profile/ProfileRank.js @@ -1,5 +1,5 @@ import { Character, ProfileRank, ProfileDmg, Player } from '../../models/index.js' -import { renderProfile } from './ProfileDetail.js' +import ProfileDetail from './ProfileDetail.js' import { Data, Common, Format } from '../../components/index.js' import lodash from 'lodash' @@ -32,7 +32,7 @@ export async function groupRank (e) { let player = Player.create(100000000) if (player.getProfile(char.id)) { e.uid = 100000000 - return await renderProfile(e, char) + return await ProfileDetail.render(e, char) } else { return true } @@ -51,7 +51,7 @@ export async function groupRank (e) { let uid = await ProfileRank.getGroupMaxUid(groupId, char.id, mode) if (uid) { e.uid = uid - return await renderProfile(e, char) + return await ProfileDetail.render(e, char) } else { if (mode === 'dmg' && !ProfileDmg.dmgRulePath(char.name)) { e.reply(`暂无排名:${char.name}暂不支持伤害计算,无法进行排名..`) diff --git a/models/Artifact.js b/models/Artifact.js index 3e4097bf..d2dfe700 100644 --- a/models/Artifact.js +++ b/models/Artifact.js @@ -75,7 +75,6 @@ class Artifact extends Base { static getAttrsByIds (ids, star = 5) { let ret = [] let tmp = {} - let starEff = { 1: 0.21, 2: 0.36, 3: 0.6, 4: 0.8, 5: 1 } lodash.forEach(ids, (id) => { let cfg = attrIdMap[id] if (!cfg) { @@ -85,14 +84,12 @@ class Artifact extends Base { if (!tmp[key]) { tmp[key] = { key, - eff: 0, upNum: 0, value: 0 } ret.push(tmp[key]) } - tmp[key].eff += value / attrMap[key].value * starEff[star] - tmp[key].value += value * (attrMap[key].format === 'pct' ? 100 : 1) * starEff[star] + tmp[key].value += value * (attrMap[key].format === 'pct' ? 100 : 1) tmp[key].upNum++ }) return ret diff --git a/models/ProfileData.js b/models/ProfileData.js index b20ff8af..1a7020be 100644 --- a/models/ProfileData.js +++ b/models/ProfileData.js @@ -18,6 +18,10 @@ export default class ProfileData extends AvatarData { return this.isProfile } + get imgs(){ + return this.char.getImgs(this.costume) + } + get costumeSplash () { let costume = this._costume costume = this.char.checkCostume(costume) ? '2' : '' diff --git a/models/ProfileDmg.js b/models/ProfileDmg.js index 02e0d410..6882c811 100644 --- a/models/ProfileDmg.js +++ b/models/ProfileDmg.js @@ -21,7 +21,7 @@ export default class ProfileDmg extends Base { static dmgRulePath (name) { const _path = process.cwd() let path = `${_path}/plugins/miao-plugin/resources/meta/character/${name}/calc_auto.js` - if (fs.existsSync(path)&&Common.cfg('teamCalc')) { + if (fs.existsSync(path) && Common.cfg('teamCalc')) { return path } path = `${_path}/plugins/miao-plugin/resources/meta/character/${name}/calc.js` @@ -243,7 +243,8 @@ export default class ProfileDmg extends Base { msg, dmgRet, enemyName, - dmgCfg: dmgDetail + dmgCfg: dmgDetail, + enemyLv } } } diff --git a/models/ProfileReq.js b/models/ProfileReq.js index 29701290..80917581 100644 --- a/models/ProfileReq.js +++ b/models/ProfileReq.js @@ -56,7 +56,12 @@ export default class ProfileReq extends Base { } } + log (msg) { + logger.mark(`${logger.cyan(`【面板】${this.uid}`)} :${msg}`) + } + async requestProfile (player, serv) { + let self = this this.serv = serv let uid = this.uid let reqParam = await serv.getReqParam(uid) @@ -65,7 +70,6 @@ export default class ProfileReq extends Base { return this.err(`请求过快,请${cdTime}秒后重试..`) } await this.setCd(20) - let self = this // 若3秒后还未响应则返回提示 setTimeout(() => { if (self._isReq) { @@ -73,7 +77,8 @@ export default class ProfileReq extends Base { } }, 3000) // 发起请求 - logger.mark(`面板请求UID:${uid},面板服务:${serv.name}...`) + this.log(`${logger.yellow('开始请求数据')},面板服务:${serv.name}...`) + const startTime = new Date() * 1 let data = {} try { let params = reqParam.params || {} @@ -82,6 +87,8 @@ export default class ProfileReq extends Base { let req = await fetch(reqParam.url, params) data = await req.text() self._isReq = false + const reqTime = new Date() * 1 - startTime + this.log(`${logger.green(`请求结束,请求用时${reqTime}ms`)},面板服务:${serv.name}...`) if (data[0] === '<') { let titleRet = /(.+)<\/title>/.exec(data) if (titleRet && titleRet[1]) { diff --git a/models/Weapon.js b/models/Weapon.js index 90780540..6c75e85a 100644 --- a/models/Weapon.js +++ b/models/Weapon.js @@ -33,6 +33,14 @@ class Weapon extends Base { return `meta/weapon/${this.type}/${this.name}/icon.webp` } + get imgs () { + return { + icon: `meta/weapon/${this.type}/${this.name}/icon.webp`, + icon2: `meta/weapon/${this.type}/${this.name}/awaken.webp`, + gacha: `meta/weapon/${this.type}/${this.name}/gacha.webp` + } + } + get icon () { return this.img } @@ -50,19 +58,6 @@ class Weapon extends Base { return (datas['0'] && datas['0'][4]) ? 5 : 1 } - getDetail () { - if (this._detail) { - return this._detail - } - const path = 'resources/meta/weapon' - try { - this._detail = Data.readJSON(`${path}/${this.type}/${this.name}/data.json`) - } catch (e) { - console.log(e) - } - return this._detail - } - static isWeaponSet (name) { return weaponSet.includes(name) } @@ -80,6 +75,72 @@ class Weapon extends Base { } return false } + + getDetail () { + if (this._detail) { + return this._detail + } + const path = 'resources/meta/weapon' + try { + this._detail = Data.readJSON(`${path}/${this.type}/${this.name}/data.json`) + } catch (e) { + console.log(e) + } + return this._detail + } + + calcAttr (level, promote = -1) { + let lvLeft = 1 + let lvRight = 20 + let lvStep = [1, 20, 40, 50, 60, 70, 80, 90] + let currPromote = 0 + for (let idx = 0; idx < lvStep.length - 1; idx++) { + if (promote === -1 || (currPromote === promote)) { + if (level >= lvStep[idx] && level <= lvStep[idx + 1]) { + lvLeft = lvStep[idx] + lvRight = lvStep[idx + 1] + break + } + } + currPromote++ + } + let wAttr = this?.detail?.attr || {} + let wAtk = wAttr.atk || {} + let valueLeft = wAtk[lvLeft + '+'] || wAtk[lvLeft] || {} + let valueRight = wAtk[lvRight] || {} + let atkBase = valueLeft * 1 + ((valueRight - valueLeft) * (level - lvLeft) / (lvRight - lvLeft)) + let wBonus = wAttr.bonusData || {} + valueLeft = wBonus[lvLeft + '+'] || wBonus[lvLeft] + valueRight = wBonus[lvRight] + let stepCount = Math.ceil((lvRight - lvLeft) / 5) + let valueStep = (valueRight - valueLeft) / stepCount + let value = valueLeft + (stepCount - Math.ceil((lvRight - level) / 5)) * valueStep + return { + atkBase, + attr: { + key: wAttr.bonusKey, + value + } + } + } + + getAffixInfo (affix) { + let d = this.getDetail() + let ad = this.detail.affixData + let txt = ad.text + lodash.forEach(ad.datas, (ds, idx) => { + txt = txt.replace(`$[${idx}]`, ds[affix - 1]) + }) + return { + name: d.name, + star: d.star, + desc: d.desc, + imgs: this.imgs, + affix, + affixTitle: d.affixTitle, + affixDetail: txt + } + } } export default Weapon diff --git a/models/profile/ArtisMark.js b/models/profile/ArtisMark.js index 3afc9a99..470bf9e2 100644 --- a/models/profile/ArtisMark.js +++ b/models/profile/ArtisMark.js @@ -70,7 +70,7 @@ let ArtisMark = { let isIdAttr = false lodash.forEach(ds, (d) => { - isIdAttr = !!d.eff + isIdAttr = !d.isCalcNum let arti = ArtisMark.formatArti(d, charAttrCfg) ret.push(arti) if (isIdAttr) { @@ -115,13 +115,15 @@ let ArtisMark = { val = Format[arrCfg.format](val, 1) let ret = { key, - value: val + value: val, + upNum: ds.upNum || 0 } - if (!isMain && !ret.eff) { + if (!isMain && !ret.upNum) { let incRet = ArtisMark.getIncNum(key, value) ret.upNum = incRet.num ret.hasGt = incRet.hasGt ret.hasLt = incRet.hasLt + ret.isCalcNum = true } if (charAttrCfg) { diff --git a/models/profile/AttrCalc.js b/models/profile/AttrCalc.js index 6fb38904..d053124e 100644 --- a/models/profile/AttrCalc.js +++ b/models/profile/AttrCalc.js @@ -120,34 +120,12 @@ class AttrCalc { setWeaponAttr () { let wData = this.profile?.weapon || {} let weapon = Weapon.get(wData?.name) - let level = wData.level - let promote = lodash.isUndefined(wData.promote) ? -1 : wData.promote - let lvLeft = 1 - let lvRight = 20 - let lvStep = [1, 20, 40, 50, 60, 70, 80, 90] - let currPromote = 0 - for (let idx = 0; idx < lvStep.length - 1; idx++) { - if (promote === -1 || (currPromote === promote)) { - if (level >= lvStep[idx] && level <= lvStep[idx + 1]) { - lvLeft = lvStep[idx] - lvRight = lvStep[idx + 1] - break - } - } - currPromote++ + let wCalcRet = weapon.calcAttr(wData.level, wData.promote) + + if (wCalcRet) { + this.addAttr('atkBase', wCalcRet.atkBase) + this.addAttr(wCalcRet.key, wCalcRet.value) } - let wAttr = weapon?.detail?.attr || {} - let wAtk = wAttr.atk || {} - let valueLeft = wAtk[lvLeft + '+'] || wAtk[lvLeft] || {} - let valueRight = wAtk[lvRight] || {} - this.addAttr('atkBase', valueLeft * 1 + ((valueRight - valueLeft) * (level - lvLeft) / (lvRight - lvLeft))) - let wBonus = wAttr.bonusData || {} - valueLeft = wBonus[lvLeft + '+'] || wBonus[lvLeft] - valueRight = wBonus[lvRight] - let stepCount = Math.ceil((lvRight - lvLeft) / 5) - let valueStep = (valueRight - valueLeft) / stepCount - let add = valueLeft + (stepCount - Math.ceil((lvRight - level) / 5)) * valueStep - this.addAttr(wAttr.bonusKey, add) let wBuffs = weaponBuffs[weapon.name] || [] if (lodash.isPlainObject(wBuffs)) { diff --git a/resources/character/profile-detail.css b/resources/character/profile-detail.css index 10d3d5f3..6b547506 100644 --- a/resources/character/profile-detail.css +++ b/resources/character/profile-detail.css @@ -359,14 +359,16 @@ body { .profile-mode .dmg-title { width: 33.3333%; } -.dmg-mode .dmg-idx { +.dmg-mode .dmg-idx, +.weapon-mode .dmg-idx { display: table-cell; width: 5%; min-width: initial; padding-right: 0; text-align: center; } -.dmg-mode .dmg-title { +.dmg-mode .dmg-title, +.weapon-mode .dmg-title { width: 31%; min-width: initial; text-align: left; diff --git a/resources/character/profile-detail.html b/resources/character/profile-detail.html index ac2736c8..e3c0b1f8 100644 --- a/resources/character/profile-detail.html +++ b/resources/character/profile-detail.html @@ -5,43 +5,58 @@ {{/block}} {{set weapon = data.weapon}} -{{set dataSource = data.dataSource}} +{{set dataSource = data.dataSource}} +{{set talentMap = {a: '普攻', e: '战技', q: '爆发'} }} +{{set {imgs,costumeSplash} = data }} {{block 'main'}} <div class="basic"> <div class="main-pic" - style="background-image:url({{_res_path}}{{costumeSplash || imgs?.splash}})"></div> + style="background-image:url({{_res_path}}{{costumeSplash||imgs?.splash}})"></div> <div class="detail"> <div class="char-name">{{data.name}}</div> <div class="char-lv">UID {{uid}} - Lv.{{data.level}} <span class="cons cons-{{data.cons}}">{{data.cons}}命</span></div> - <div class="char-talents"> - {{each talentMap tName key}} - {{set talent = data.talent[key] || {} }} - <div class="talent-item"> - <div class="talent-icon + <div> + {{if mode !== 'weapon'}} + <div class="char-talents"> + {{each talentMap tName key}} + {{set talent = data.talent[key] || {} }} + <div class="talent-item"> + <div class="talent-icon {{talent.level > talent.original ? `talent-plus`:``}} {{talent.original >= 10 ? `talent-crown`:``}}"> - <div class="talent-icon-img" - style="background-image:url({{_res_path}}{{imgs[key]}})"></div> - <span>{{talent.level}}</span> + <div class="talent-icon-img" + style="background-image:url({{_res_path}}{{imgs[key]}})"></div> + <span>{{talent.level}}</span> + </div> + </div> + {{/each}} + </div> + <ul class="attr"> + <li><i class="i-hp"></i>生命值<strong>{{attr.hp}}</strong><span>(+{{attr.hpPlus}})</span></li> + <li><i class="i-atk"></i>攻击力<strong>{{attr.atk}}</strong><span>(+{{attr.atkPlus}})</span></li> + <li><i class="i-def"></i>防御力<strong>{{attr.def}}</strong><span>(+{{attr.defPlus}})</span></li> + <li><i class="i-mastery"></i>元素精通<strong>{{attr.mastery}}</strong></li> + <li><i class="i-cr"></i>暴击率<strong>{{attr.cpct}}</strong></li> + <li><i class="i-cd"></i>暴击伤害<strong>{{attr.cdmg}}</strong></li> + <li><i class="i-re"></i>元素充能<strong>{{attr.recharge}}</strong></li> + <li><i class="i-dmg"></i>伤害加成<strong>{{attr.dmg}}</strong></li> + </ul> + {{else}} + <div class="char-weapon"> + <div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div> + <div class="head"> + <strong>{{weapon.name}}</strong> + <div class="star star-{{weapon.star}}"></div> + <span>Lv.{{weapon.leve || weapon.level}} <span + class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span></span> </div> </div> - {{/each}} + {{/if}} </div> - <ul class="attr"> - <li><i class="i-hp"></i>生命值<strong>{{attr.hp}}</strong><span>(+{{attr.hpPlus}})</span></li> - <li><i class="i-atk"></i>攻击力<strong>{{attr.atk}}</strong><span>(+{{attr.atkPlus}})</span></li> - <li><i class="i-def"></i>防御力<strong>{{attr.def}}</strong><span>(+{{attr.defPlus}})</span></li> - <li><i class="i-mastery"></i>元素精通<strong>{{attr.mastery}}</strong></li> - <li><i class="i-cr"></i>暴击率<strong>{{attr.cpct}}</strong></li> - <li><i class="i-cd"></i>暴击伤害<strong>{{attr.cdmg}}</strong></li> - <li><i class="i-re"></i>元素充能<strong>{{attr.recharge}}</strong></li> - <li><i class="i-dmg"></i>伤害加成<strong>{{attr.dmg}}</strong></li> - </ul> </div> - <div class="char-cons"> {{set cons = [1,2,3,4,5,6]}} {{each cons idx}} @@ -72,158 +87,168 @@ </div> {{/if}} -{{if mode === "profile"}} -{{set ad = artisDetail}} -<div class="artis"> - <div> - <div class="item weapon"> - <div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div> +<!-- 【 武器+圣遗物列表】 --> +<div> + {{if mode === "profile"}} + {{set ad = artisDetail}} + <div class="artis"> + <div> + <div class="item weapon"> + <div class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></div> + <div class="head"> + <strong>{{weapon.name}}</strong> + <div class="star star-{{weapon.star}}"></div> + <span>Lv.{{weapon.leve || weapon.level}} <span + class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span></span> + </div> + </div> + <div class="item arti-stat"> + <div class="arti-class-title">评分规则:{{ad.classTitle}}</div> + <div class="arti-stat-ret"> + <div><strong class="mark-{{ad.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div> + <div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div> + </div> + </div> + </div> + {{each ad.artis ds idx}} + <div class="item arti"> + {{if ds && ds.name && ds.main && ds.main.key && ds.main.key!="undefined"}} + <div class="arti-icon"> + <div class="img" style="background-image:url({{_res_path}}{{ds.img}})"></div> + <span>+{{ds.level}}</span> + </div> <div class="head"> - <strong>{{weapon.name}}</strong> - <div class="star star-{{weapon.star}}"></div> - <span>Lv.{{weapon.leve || weapon.level}} <span - class="affix affix-{{weapon.affix}}">精{{weapon.affix}}</span></span> + <strong>{{ds.name}}</strong> + <span class="mark mark-{{ds.markClass}}"><span>{{ds.mark}}分</span> - {{ds.markClass}}</span> </div> - </div> - <div class="item arti-stat"> - <div class="arti-class-title">评分规则:{{ad.classTitle}}</div> - <div class="arti-stat-ret"> - <div><strong class="mark-{{ad.markClass}}">{{ad.markClass}}</strong><span>圣遗物评级</span></div> - <div><strong>{{ad.mark}}</strong><span>圣遗物总分</span></div> - </div> - </div> - </div> - {{each ad.artis ds idx}} - <div class="item arti"> - {{if ds && ds.name && ds.main && ds.main.key && ds.main.key!="undefined"}} - <div class="arti-icon"> - <div class="img" style="background-image:url({{_res_path}}{{ds.img}})"></div> - <span>+{{ds.level}}</span> - </div> - <div class="head"> - <strong>{{ds.name}}</strong> - <span class="mark mark-{{ds.markClass}}"><span>{{ds.mark}}分</span> - {{ds.markClass}}</span> - </div> - <ul class="detail attr"> - <li class="arti-main"><span class="title">{{artisKeyTitle[ds.main?.key]}}</span><span class="val">+{{ds.main.value}}</span> - </li> - {{each ds.attrs attr}} - {{if attr && attr.key}} - <li class="{{ad.charWeight[attr.key]*1 > 79.9 ?`great`:(ad.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}"> - <span class="title"> {{if attr.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key]}}</span> - <span class="val">+{{attr.value}}</span> - </li> - {{/if}} - {{/each}} - </ul> - {{/if}} - </div> - {{/each}} -</div> -{{/if}} - -{{if mode === "profile"}} -<div class="cont"> - <div class="cont-footer dmg-desc"> - 当前评分为<strong>喵喵版评分规则</strong>,分值仅供参考与娱乐。可使用<strong>#{{data.abbr}}圣遗物</strong>来查看评分详情 - </div> -</div> -{{/if}} - -{{if dmgData.length > 0}} -<div class="dmg-cont dmg-list cont"> - <div class="cont-title"> - 伤害计算<span>目标为{{enemyLv}}级{{enemyName}},如需调整等级可使用 #敌人等级{{enemyLv}} 来进行设置</span> - </div> - <div class="cont-table"> - <div class="tr thead"> - <div class="title dmg-idx">#</div> - <div class="title dmg-title">伤害类型</div> - <div>暴击伤害</div> - <div>平均伤害(计算暴击率)</div> - </div> - {{each dmgData dmg idx}} - <div class="dmg tr"> - <div class="title dmg-idx">{{idx+1}}</div> - <div class="title dmg-title">{{dmg.title}}</div> - {{if dmg.dmg === "NaN"}} - <div class="value value-full">{{dmg.avg}}{{dmg.unit}}</div> - <div class="value value-none"></div> - {{else}} - <div class="value">{{dmg.dmg}}{{dmg.unit}}</div> - <div class="value">{{dmg.avg}}{{dmg.unit}}</div> + <ul class="detail attr"> + <li class="arti-main"><span class="title">{{artisKeyTitle[ds.main?.key]}}</span><span class="val">+{{ds.main.value}}</span> + </li> + {{each ds.attrs attr}} + {{if attr && attr.key}} + <li class="{{ad.charWeight[attr.key]*1 > 79.9 ?`great`:(ad.charWeight[attr.key]*1>0 ? `useful`:`nouse`)}}"> + <span class="title"> {{if attr.upNum}}<i class="up-num up-{{attr.upNum}}"></i>{{/if}}{{artisKeyTitle[attr.key]}}</span> + <span class="val">+{{attr.value}}</span> + </li> + {{/if}} + {{/each}} + </ul> {{/if}} </div> {{/each}} </div> - <div class="cont-footer dmg-desc"> - 使用命令<strong>#{{data.abbr}}伤害</strong>可以查看伤害详情,使用命令<strong>#角色面板帮助</strong>可查看帮助说明 - </div> + {{/if}} </div> -{{/if}} -{{if mode === "dmg"}} - -{{if dmgCfg && dmgCfg.attr && dmgCfg.attr.length>0 && dmgRet}} -<div class="dmg-calc dmg-cont cont"> - <div class="cont-title"> - 词条伤害计算<span>#{{data.abbr}}伤害{{dmgCfg.userIdx+1}}: 当前计算为[{{dmgCfg.title}}]</span> +<!-- 【 伤害表格 】 --> +{{ set {dmgRet, dmgCfg, enemyName, dmgMsg, dmgData} = dmgCalc }} +<div> + {{if mode === "profile"}} + <div class="cont"> + <div class="cont-footer dmg-desc"> + 当前评分为<strong>喵喵版评分规则</strong>,分值仅供参考与娱乐。可使用<strong>#{{data.abbr}}圣遗物</strong>来查看评分详情 + </div> </div> - <div class="cont-table"> - <div class="tr thead "> - <div class="td">词条变化</div> - {{each dmgCfg.attr attr}} - <div class="td"> - <strong>{{attr.title}}</strong> - <span>+{{attr.text}}</span> + {{/if}} + + {{if dmgData.length > 0}} + <div class="dmg-cont dmg-list cont"> + <div class="cont-title"> + 伤害计算<span>目标为{{enemyLv}}级{{enemyName||'小宝'}},如需调整等级可使用 #敌人等级{{enemyLv}} 来进行设置</span> + </div> + <div class="cont-table"> + <div class="tr thead"> + <div class="title dmg-idx">#</div> + <div class="title dmg-title">伤害类型</div> + <div>暴击伤害</div> + <div>平均伤害(计算暴击率)</div> + </div> + {{each dmgData dmg idx}} + <div class="dmg tr"> + <div class="title dmg-idx">{{idx+1}}</div> + <div class="title dmg-title">{{dmg.title}}</div> + {{if dmg.dmg === "NaN"}} + <div class="value value-full">{{dmg.avg}}{{dmg.unit}}</div> + <div class="value value-none"></div> + {{else}} + <div class="value">{{dmg.dmg}}{{dmg.unit}}</div> + <div class="value">{{dmg.avg}}{{dmg.unit}}</div> + {{/if}} </div> {{/each}} </div> - {{each dmgRet row rowIdx}} - <div class="tr"> - <div class="title"> - <strong>{{dmgCfg.attr[rowIdx].title}}</strong> - <span>-{{dmgCfg.attr[rowIdx].text}}</span> - </div> - {{each row cell colIdx}} - {{if cell.type === "na"}} - <div class="td na"> - <strong>-</strong> - <span>{{dmgCfg.basicRet.avg}}{{dmgCfg.basicRet.dmg!="NaN"?`/${dmgCfg.basicRet.dmg}`:''}}</span> - </div> - {{else}} - <div class="td {{cell.type}}"> - <strong>{{cell.val}}</strong> + <div class="cont-footer dmg-desc"> + 使用命令<strong>#{{data.abbr}}伤害</strong>可以查看伤害详情,使用命令<strong>#角色面板帮助</strong>可查看帮助说明 + </div> + </div> + {{/if}} +</div> - <span>{{cell.avg}}{{cell.dmg!="NaN"?`/${cell.dmg}`:''}}</span> +<!-- 【 伤害变化详情 】 --> +<div> + {{if mode === "dmg"}} + {{if dmgCfg && dmgCfg.attr && dmgCfg.attr.length>0 && dmgRet && dmgRet.length >3}} + <div class="dmg-calc dmg-cont cont"> + <div class="cont-title"> + 词条伤害计算<span>#{{data.abbr}}伤害{{dmgCfg.userIdx+1}}: 当前计算为[{{dmgCfg.title}}]</span> + </div> + <div class="cont-table"> + <div class="tr thead "> + <div class="td">词条变化</div> + {{each dmgCfg.attr attr}} + <div class="td"> + <strong>{{attr.title}}</strong> + <span>+{{attr.text}}</span> + </div> + {{/each}} + </div> + {{each dmgRet row rowIdx}} + <div class="tr"> + <div class="title"> + <strong>{{dmgCfg.attr[rowIdx].title}}</strong> + <span>-{{dmgCfg.attr[rowIdx].text}}</span> + </div> + {{each row cell colIdx}} + {{if cell.type === "na"}} + <div class="td na"> + <strong>-</strong> + <span>{{dmgCfg.basicRet.avg}}{{dmgCfg.basicRet.dmg!="NaN"?`/${dmgCfg.basicRet.dmg}`:''}}</span> + </div> + {{else}} + <div class="td {{cell.type}}"> + <strong>{{cell.val}}</strong> + + <span>{{cell.avg}}{{cell.dmg!="NaN"?`/${cell.dmg}`:''}}</span> + </div> + {{/if}} + {{/each}} </div> - {{/if}} {{/each}} </div> - {{/each}} - </div> - <div class="cont-footer dmg-desc"> - <ul> - <li>大数字的含义为圣遗物副词条置换后<strong>平均伤害</strong>的变化,下方的详情数字为<strong>平均伤害</strong>/<strong>暴击伤害</strong>。</li> - <li>关于<strong>平均伤害</strong>:是将暴击率计算在内的伤害期望,能反映综合的输出能力,不等于实际伤害数字。</li> - <li>可用于评估当前面板下圣遗物副词条的侧重方向。实际游戏情况更加复杂,结果供参考~</li> - <li>如需更换计算的伤害类型,可使用命令 <strong>#{{data.abbr}}伤害+序号</strong>来切换,序号参见伤害计算板块</li> - </ul> - </div> -</div> -{{/if}} - -<div class="dmg-cont dmg-msg cont"> - <div class="cont-title">Buff列表<span>部分Buff的触发条件以及层数可能影响实际伤害结果</span></div> - <div class="cont-table"> - {{each dmgMsg msg}} - <div class="tr"> - <div class="th">{{msg[0]}}</div> - <div class="td">{{msg[1]}}</div> + <div class="cont-footer dmg-desc"> + <ul> + <li>大数字的含义为圣遗物副词条置换后<strong>平均伤害</strong>的变化,下方的详情数字为<strong>平均伤害</strong>/<strong>暴击伤害</strong>。</li> + <li>关于<strong>平均伤害</strong>:是将暴击率计算在内的伤害期望,能反映综合的输出能力,不等于实际伤害数字。</li> + <li>可用于评估当前面板下圣遗物副词条的侧重方向。实际游戏情况更加复杂,结果供参考~</li> + <li>如需更换计算的伤害类型,可使用命令 <strong>#{{data.abbr}}伤害+序号</strong>来切换,序号参见伤害计算板块</li> + </ul> </div> - {{/each}} </div> + {{/if}} + + <div class="dmg-cont dmg-msg cont"> + <div class="cont-title">Buff列表<span>部分Buff的触发条件以及层数可能影响实际伤害结果</span></div> + <div class="cont-table"> + {{each dmgMsg msg}} + <div class="tr"> + <div class="th">{{msg[0]}}</div> + <div class="td">{{msg[1]}}</div> + </div> + {{/each}} + </div> + </div> + {{/if}} </div> -{{/if}} + {{/block}} \ No newline at end of file diff --git a/resources/character/profile-detail.less b/resources/character/profile-detail.less index 88fe847d..72b2ef64 100644 --- a/resources/character/profile-detail.less +++ b/resources/character/profile-detail.less @@ -433,20 +433,23 @@ body { width: 33.3333%; } -.dmg-mode .dmg-idx { - display: table-cell; - width: 5%; - min-width: initial; - padding-right: 0; - text-align: center; -} +.dmg-mode, +.weapon-mode { + .dmg-idx { + display: table-cell; + width: 5%; + min-width: initial; + padding-right: 0; + text-align: center; + } -.dmg-mode .dmg-title { - width: 31%; - min-width: initial; - text-align: left; - padding-left: 10px; - padding-right: 0; + .dmg-title { + width: 31%; + min-width: initial; + text-align: left; + padding-left: 10px; + padding-right: 0; + } }