微调面板相关逻辑

This commit is contained in:
Kokomi 2023-02-22 03:49:49 +08:00
parent d0b9d4c175
commit f0348841a3
13 changed files with 512 additions and 414 deletions

View File

@ -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: /^#.+换.+$/
},

View File

@ -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

View File

@ -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}暂不支持伤害计算,无法进行排名..`)

View File

@ -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

View File

@ -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' : ''

View File

@ -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
}
}
}

View File

@ -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>(.+)<\/title>/.exec(data)
if (titleRet && titleRet[1]) {

View File

@ -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

View File

@ -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) {

View File

@ -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)) {

View File

@ -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;

View File

@ -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}}

View File

@ -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;
}
}