mirror of
https://github.com/yoimiya-kokomi/miao-plugin.git
synced 2024-11-21 22:48:13 +00:00
apps目录结构调整,面板自动更新逻辑更新
This commit is contained in:
parent
a54b9c6bd4
commit
f4353fc5ca
@ -12,17 +12,22 @@ let app = App.init({
|
|||||||
|
|
||||||
let sysCfgReg = new RegExp(`^#喵喵设置\\s*(${keys.join('|')})?\\s*(.*)$`)
|
let sysCfgReg = new RegExp(`^#喵喵设置\\s*(${keys.join('|')})?\\s*(.*)$`)
|
||||||
|
|
||||||
app.reg('update-res', updateRes, {
|
app.reg({
|
||||||
rule: /^#喵喵(强制)?(更新图像|图像更新)$/,
|
updateRes: {
|
||||||
desc: '【#管理】更新素材'
|
rule: /^#喵喵(强制)?(更新图像|图像更新)$/,
|
||||||
})
|
fn: updateRes,
|
||||||
app.reg('update', updateMiaoPlugin, {
|
desc: '【#管理】更新素材'
|
||||||
rule: /^#喵喵(强制)?更新/,
|
},
|
||||||
desc: '【#管理】喵喵更新'
|
update: {
|
||||||
})
|
rule: /^#喵喵(强制)?更新/,
|
||||||
app.reg('sys-cfg', sysCfg, {
|
fn: updateMiaoPlugin,
|
||||||
rule: sysCfgReg,
|
desc: '【#管理】喵喵更新'
|
||||||
desc: '【#管理】系统设置'
|
},
|
||||||
|
sysCfg: {
|
||||||
|
rule: sysCfgReg,
|
||||||
|
fn: sysCfg,
|
||||||
|
desc: '【#管理】系统设置'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
@ -1,71 +1,36 @@
|
|||||||
import { Common, App } from '../components/index.js'
|
import { App } from '../components/index.js'
|
||||||
import { Character } from '../models/index.js'
|
|
||||||
import { renderAvatar } from './character/AvatarCard.js'
|
|
||||||
import { uploadCharacterImg } from './character/ImgUpload.js'
|
import { uploadCharacterImg } from './character/ImgUpload.js'
|
||||||
import { wife, wifeReg } from './character/AvatarWife.js'
|
|
||||||
import { getOriginalPicture } from './profile/ProfileUtils.js'
|
import { getOriginalPicture } from './profile/ProfileUtils.js'
|
||||||
|
import Avatar from './character/AvatarCard.js'
|
||||||
|
import Wife from './character/AvatarWife.js'
|
||||||
|
|
||||||
let app = App.init({
|
let app = App.init({
|
||||||
id: 'character',
|
id: 'character',
|
||||||
name: '角色查询'
|
name: '角色查询'
|
||||||
})
|
})
|
||||||
|
|
||||||
app.reg('character', character, {
|
app.reg({
|
||||||
rule: /^#喵喵角色卡片$/,
|
character: {
|
||||||
check: checkCharacter,
|
rule: /^#喵喵角色卡片$/,
|
||||||
name: '角色卡片'
|
fn: Avatar.render,
|
||||||
})
|
check: Avatar.check,
|
||||||
|
name: '角色卡片'
|
||||||
app.reg('upload-img', uploadCharacterImg, {
|
},
|
||||||
rule: /^#*(喵喵)?(上传|添加)(.+)(照片|写真|图片|图像)\s*$/,
|
uploadImg: {
|
||||||
name: '上传角色写真'
|
rule: /^#*(喵喵)?(上传|添加)(.+)(照片|写真|图片|图像)\s*$/,
|
||||||
})
|
fn: uploadCharacterImg,
|
||||||
|
name: '上传角色写真'
|
||||||
app.reg('wife', wife, {
|
},
|
||||||
rule: wifeReg,
|
wife: {
|
||||||
describe: '#老公 #老婆 查询'
|
rule: Wife.reg,
|
||||||
})
|
fn: Wife.render,
|
||||||
|
describe: '#老公 #老婆 查询'
|
||||||
app.reg('original-pic', getOriginalPicture, {
|
},
|
||||||
rule: /^#?(获取|给我|我要|求|发|发下|发个|发一下)?原图(吧|呗)?$/,
|
originalPic: {
|
||||||
describe: '【#原图】 回复角色卡片,可获取原图'
|
rule: /^#?(获取|给我|我要|求|发|发下|发个|发一下)?原图(吧|呗)?$/,
|
||||||
|
fn: getOriginalPicture,
|
||||||
|
describe: '【#原图】 回复角色卡片,可获取原图'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
|
||||||
// 查看当前角色
|
|
||||||
export async function character (e) {
|
|
||||||
if (!e.char) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return renderAvatar(e, e.char?.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkCharacter (e) {
|
|
||||||
let msg = e.original_msg || e.msg
|
|
||||||
if (!msg || !/^#/.exec(msg)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!Common.cfg('avatarCard')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let uidRet = /[0-9]{9}/.exec(msg)
|
|
||||||
if (uidRet) {
|
|
||||||
e.uid = uidRet[0]
|
|
||||||
msg = msg.replace(uidRet[0], '')
|
|
||||||
}
|
|
||||||
let name = msg.replace(/#|老婆|老公|卡片/g, '').trim()
|
|
||||||
|
|
||||||
// cache gsCfg
|
|
||||||
Character.gsCfg = Character.gsCfg || e?.runtime?.gsCfg
|
|
||||||
|
|
||||||
let char = Character.get(name.trim())
|
|
||||||
|
|
||||||
if (!char) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
e.msg = '#喵喵角色卡片'
|
|
||||||
e.char = char
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
@ -4,85 +4,122 @@ import lodash from 'lodash'
|
|||||||
import { segment } from 'oicq'
|
import { segment } from 'oicq'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
export async function renderAvatar (e, avatar, renderType = 'card') {
|
let Avatar = {
|
||||||
// 如果传递的是名字,则获取
|
render (e) {
|
||||||
if (typeof (avatar) === 'string') {
|
if (!e.char) {
|
||||||
// 检查角色
|
return false
|
||||||
let char = Character.get(avatar)
|
}
|
||||||
|
return Avatar.renderAvatar(e, e.char?.name)
|
||||||
|
},
|
||||||
|
async renderAvatar (e, avatar, renderType = 'card') {
|
||||||
|
// 如果传递的是名字,则获取
|
||||||
|
if (typeof (avatar) === 'string') {
|
||||||
|
// 检查角色
|
||||||
|
let char = Character.get(avatar)
|
||||||
|
if (!char) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let mys = await MysApi.init(e)
|
||||||
|
if (!mys) return true
|
||||||
|
if (!char.isRelease) {
|
||||||
|
avatar = { id: char.id, name: char.name, detail: false }
|
||||||
|
} else {
|
||||||
|
let player = Player.create(e)
|
||||||
|
await player.refreshMysDetail()
|
||||||
|
await player.refreshTalent(char.id)
|
||||||
|
avatar = player.getAvatar(char.id)
|
||||||
|
if (!avatar) {
|
||||||
|
avatar = { id: char.id, name: char.name, detail: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await Avatar.renderCard(e, avatar, renderType)
|
||||||
|
},
|
||||||
|
|
||||||
|
async renderCard (e, avatar, renderType = 'card') {
|
||||||
|
let char = Character.get(avatar.id)
|
||||||
if (!char) {
|
if (!char) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
let mys = await MysApi.init(e)
|
let bg = char.getCardImg(Cfg.get('charPicSe', false))
|
||||||
if (!mys) return true
|
if (renderType === 'photo') {
|
||||||
if (!char.isRelease) {
|
e.reply(segment.image(process.cwd() + '/plugins/miao-plugin/resources/' + bg.img))
|
||||||
avatar = { id: char.id, name: char.name, detail: false }
|
return true
|
||||||
} else {
|
}
|
||||||
let player = Player.create(e)
|
let uid = e.uid || (e.targetUser && e.targetUser.uid)
|
||||||
await player.refreshMysDetail()
|
let data = {}
|
||||||
await player.refreshTalent(char.id)
|
let custom = char.isCustom
|
||||||
avatar = player.getAvatar(char.id)
|
let isRelease = char.isRelease
|
||||||
if (!avatar) {
|
if (isRelease) {
|
||||||
avatar = { id: char.id, name: char.name, detail: false }
|
data = avatar.getDetail()
|
||||||
}
|
data.imgs = char.imgs
|
||||||
|
data.source = avatar._source
|
||||||
|
data.artis = avatar.getArtisDetail()
|
||||||
|
data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm')
|
||||||
|
if (data.hasTalent) {
|
||||||
|
data.talent = avatar.talent
|
||||||
|
data.talentMap = ['a', 'e', 'q']
|
||||||
|
// 计算皇冠个数
|
||||||
|
data.crownNum = lodash.filter(lodash.map(data.talent, (d) => d.original), (d) => d >= 10).length
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = char.getData('id,name,sName')
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return await renderCard(e, avatar, renderType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 渲染角色卡片
|
let width = 600
|
||||||
async function renderCard (e, avatar, renderType = 'card') {
|
let imgCss = ''
|
||||||
let char = Character.get(avatar.id)
|
let scale = 1.2
|
||||||
if (!char) {
|
if (bg.mode === 'left') {
|
||||||
return false
|
const height = 480
|
||||||
}
|
width = height * bg.width / bg.height
|
||||||
let bg = char.getCardImg(Cfg.get('charPicSe', false))
|
imgCss = `img.bg{width:auto;height:${height}px;}`
|
||||||
if (renderType === 'photo') {
|
scale = 1.45
|
||||||
e.reply(segment.image(process.cwd() + '/plugins/miao-plugin/resources/' + bg.img))
|
}
|
||||||
|
// 渲染图像
|
||||||
|
let msgRes = await Common.render('character/character-card', {
|
||||||
|
saveId: uid,
|
||||||
|
uid,
|
||||||
|
bg,
|
||||||
|
widthStyle: `<style>html,body,#container{width:${width}px} ${imgCss}</style>`,
|
||||||
|
mode: bg.mode,
|
||||||
|
custom,
|
||||||
|
isRelease,
|
||||||
|
data
|
||||||
|
}, { e, scale, retMsgId: true })
|
||||||
|
if (msgRes && msgRes.message_id) {
|
||||||
|
// 如果消息发送成功,就将message_id和图片路径存起来,3小时过期
|
||||||
|
await redis.set(`miao:original-picture:${msgRes.message_id}`, bg.img, { EX: 3600 * 3 })
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
check (e) {
|
||||||
|
let msg = e.original_msg || e.msg
|
||||||
|
if (!msg || !/^#/.exec(msg)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!Common.cfg('avatarCard')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let uidRet = /[0-9]{9}/.exec(msg)
|
||||||
|
if (uidRet) {
|
||||||
|
e.uid = uidRet[0]
|
||||||
|
msg = msg.replace(uidRet[0], '')
|
||||||
|
}
|
||||||
|
let name = msg.replace(/#|老婆|老公|卡片/g, '').trim()
|
||||||
|
|
||||||
|
// cache gsCfg
|
||||||
|
Character.gsCfg = Character.gsCfg || e?.runtime?.gsCfg
|
||||||
|
|
||||||
|
let char = Character.get(name.trim())
|
||||||
|
|
||||||
|
if (!char) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
e.msg = '#喵喵角色卡片'
|
||||||
|
e.char = char
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let uid = e.uid || (e.targetUser && e.targetUser.uid)
|
|
||||||
let data = {}
|
|
||||||
let custom = char.isCustom
|
|
||||||
let isRelease = char.isRelease
|
|
||||||
if (isRelease) {
|
|
||||||
data = avatar.getDetail()
|
|
||||||
data.imgs = char.imgs
|
|
||||||
data.source = avatar._source
|
|
||||||
data.artis = avatar.getArtisDetail()
|
|
||||||
data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm')
|
|
||||||
if (data.hasTalent) {
|
|
||||||
data.talent = avatar.talent
|
|
||||||
data.talentMap = ['a', 'e', 'q']
|
|
||||||
// 计算皇冠个数
|
|
||||||
data.crownNum = lodash.filter(lodash.map(data.talent, (d) => d.original), (d) => d >= 10).length
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = char.getData('id,name,sName')
|
|
||||||
}
|
|
||||||
|
|
||||||
let width = 600
|
|
||||||
let imgCss = ''
|
|
||||||
let scale = 1.2
|
|
||||||
if (bg.mode === 'left') {
|
|
||||||
const height = 480
|
|
||||||
width = height * bg.width / bg.height
|
|
||||||
imgCss = `img.bg{width:auto;height:${height}px;}`
|
|
||||||
scale = 1.45
|
|
||||||
}
|
|
||||||
// 渲染图像
|
|
||||||
let msgRes = await Common.render('character/character-card', {
|
|
||||||
saveId: uid,
|
|
||||||
uid,
|
|
||||||
bg,
|
|
||||||
widthStyle: `<style>html,body,#container{width:${width}px} ${imgCss}</style>`,
|
|
||||||
mode: bg.mode,
|
|
||||||
custom,
|
|
||||||
isRelease,
|
|
||||||
data
|
|
||||||
}, { e, scale, retMsgId: true })
|
|
||||||
if (msgRes && msgRes.message_id) {
|
|
||||||
// 如果消息发送成功,就将message_id和图片路径存起来,3小时过期
|
|
||||||
await redis.set(`miao:original-picture:${msgRes.message_id}`, bg.img, { EX: 3600 * 3 })
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
export default Avatar
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import { Common } from '../../components/index.js'
|
import { Common } from '../../components/index.js'
|
||||||
import { Character, MysApi, Player } from '../../models/index.js'
|
import { Character, MysApi, Player } from '../../models/index.js'
|
||||||
import { renderAvatar } from './AvatarCard.js'
|
import Avatar from './AvatarCard.js'
|
||||||
|
|
||||||
const relationMap = {
|
const relationMap = {
|
||||||
wife: {
|
wife: {
|
||||||
@ -32,138 +32,9 @@ const relationMap = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const relation = lodash.flatMap(relationMap, (d) => d.keyword)
|
const relation = lodash.flatMap(relationMap, (d) => d.keyword)
|
||||||
export const wifeReg = `^#?\\s*(${relation.join('|')})\\s*(设置|选择|指定|列表|查询|列表|是|是谁|照片|相片|图片|写真|图像)?\\s*([^\\d]*)\\s*(\\d*)$`
|
const wifeReg = `^#?\\s*(${relation.join('|')})\\s*(设置|选择|指定|列表|查询|列表|是|是谁|照片|相片|图片|写真|图像)?\\s*([^\\d]*)\\s*(\\d*)$`
|
||||||
|
|
||||||
export async function wife (e) {
|
async function getAvatarList (player, type) {
|
||||||
let msg = e.msg || ''
|
|
||||||
if (!msg && !e.isPoke) return false
|
|
||||||
|
|
||||||
if (e.isPoke) {
|
|
||||||
if (!Common.cfg('avatarPoke')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else if (!Common.cfg('avatarWife')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let msgRet = (new RegExp(wifeReg)).exec(msg)
|
|
||||||
if (e.isPoke) {
|
|
||||||
msgRet = []
|
|
||||||
} else if (!msgRet) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let target = msgRet[1]
|
|
||||||
let action = msgRet[2] || '卡片'
|
|
||||||
let actionParam = msgRet[3] || ''
|
|
||||||
|
|
||||||
if (!'设置,选择,挑选,指定'.split(',').includes(action) && actionParam) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let targetCfg = lodash.find(relationMap, (cfg, key) => {
|
|
||||||
cfg.key = key
|
|
||||||
return cfg.keyword.includes(target)
|
|
||||||
})
|
|
||||||
if (!targetCfg && !e.isPoke) return true
|
|
||||||
|
|
||||||
let avatarList = []
|
|
||||||
let avatar = {}
|
|
||||||
let wifeList = []
|
|
||||||
|
|
||||||
let mys = await MysApi.init(e)
|
|
||||||
if (!mys || !mys.uid) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
let player = Player.create(e)
|
|
||||||
let selfUser = mys.selfUser
|
|
||||||
let isSelf = true
|
|
||||||
let renderType = (action === '卡片' ? 'card' : 'photo')
|
|
||||||
let addRet = []
|
|
||||||
switch (action) {
|
|
||||||
case '卡片':
|
|
||||||
case '照片':
|
|
||||||
case '相片':
|
|
||||||
case '图片':
|
|
||||||
case '写真':
|
|
||||||
// 展示老婆卡片
|
|
||||||
// 如果选择过,则进行展示
|
|
||||||
if (!e.isPoke) {
|
|
||||||
wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, [])
|
|
||||||
// 存在设置
|
|
||||||
if (wifeList && wifeList.length > 0 && isSelf && !e.isPoke) {
|
|
||||||
if (wifeList[0] === '随机') {
|
|
||||||
// 如果选择为全部,则从列表中随机选择一个
|
|
||||||
avatarList = await getAvatarList(player, targetCfg.type, mys)
|
|
||||||
let avatar = lodash.sample(avatarList)
|
|
||||||
return renderAvatar(e, avatar, renderType)
|
|
||||||
} else {
|
|
||||||
// 如果指定过,则展示指定角色
|
|
||||||
return renderAvatar(e, lodash.sample(wifeList), renderType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果未指定过,则从列表中排序并随机选择
|
|
||||||
avatarList = await getAvatarList(player, e.isPoke ? false : targetCfg.type, mys)
|
|
||||||
if (avatarList && avatarList.length > 0) {
|
|
||||||
avatar = lodash.sample(avatarList)
|
|
||||||
return await renderAvatar(e, avatar, renderType)
|
|
||||||
}
|
|
||||||
e.reply('在当前米游社公开展示的角色中未能找到适合展示的角色..')
|
|
||||||
return true
|
|
||||||
case '设置':
|
|
||||||
case '选择':
|
|
||||||
case '挑选':
|
|
||||||
case '指定':
|
|
||||||
if (!isSelf) {
|
|
||||||
e.reply('只能指定自己的哦~')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 选择老婆
|
|
||||||
actionParam = actionParam.replace(/(,|、|;|;)/g, ',')
|
|
||||||
wifeList = actionParam.split(',')
|
|
||||||
if (lodash.intersection(['全部', '任意', '随机', '全都要'], wifeList).length > 0) {
|
|
||||||
addRet = ['随机']
|
|
||||||
} else {
|
|
||||||
wifeList = lodash.map(wifeList, (name) => {
|
|
||||||
let char = Character.get(name)
|
|
||||||
if (char && char.checkWifeType(targetCfg.type)) {
|
|
||||||
return char.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
wifeList = lodash.filter(lodash.uniq(wifeList), (d) => !!d)
|
|
||||||
addRet = wifeList
|
|
||||||
if (addRet.length === 0) {
|
|
||||||
e.reply(`在可选的${targetCfg.keyword[0]}列表中未能找到 ${actionParam} ~`)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await selfUser.setCfg(`wife.${targetCfg.key}`, addRet)
|
|
||||||
e.reply(`${targetCfg.keyword[0]}已经设置:${addRet.join(',')}`)
|
|
||||||
return true
|
|
||||||
case '列表':
|
|
||||||
case '是':
|
|
||||||
case '是谁':
|
|
||||||
// 查看当前选择老婆
|
|
||||||
if (!isSelf) {
|
|
||||||
e.reply('只能查看自己的哦~')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, [])
|
|
||||||
if (wifeList && wifeList.length > 0) {
|
|
||||||
e.reply(`你的${targetCfg.keyword[0]}是:${wifeList.join(',')}`)
|
|
||||||
} else {
|
|
||||||
e.reply(`尚未设置,回复#${targetCfg.keyword[0]}设置+角色名 来设置,如果设置多位请用逗号间隔`)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function pokeWife (e, components) {
|
|
||||||
return await wife(e, components)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getAvatarList (player, type, mys) {
|
|
||||||
await player.refreshMysDetail()
|
await player.refreshMysDetail()
|
||||||
let list = []
|
let list = []
|
||||||
player.forEachAvatar((avatar) => {
|
player.forEachAvatar((avatar) => {
|
||||||
@ -182,3 +53,136 @@ async function getAvatarList (player, type, mys) {
|
|||||||
list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(','))
|
list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(','))
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Wife = {
|
||||||
|
reg: wifeReg,
|
||||||
|
async render (e) {
|
||||||
|
let msg = e.msg || ''
|
||||||
|
if (!msg && !e.isPoke) return false
|
||||||
|
|
||||||
|
if (e.isPoke) {
|
||||||
|
if (!Common.cfg('avatarPoke')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (!Common.cfg('avatarWife')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let msgRet = (new RegExp(wifeReg)).exec(msg)
|
||||||
|
if (e.isPoke) {
|
||||||
|
msgRet = []
|
||||||
|
} else if (!msgRet) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let target = msgRet[1]
|
||||||
|
let action = msgRet[2] || '卡片'
|
||||||
|
let actionParam = msgRet[3] || ''
|
||||||
|
|
||||||
|
if (!'设置,选择,挑选,指定'.split(',').includes(action) && actionParam) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetCfg = lodash.find(relationMap, (cfg, key) => {
|
||||||
|
cfg.key = key
|
||||||
|
return cfg.keyword.includes(target)
|
||||||
|
})
|
||||||
|
if (!targetCfg && !e.isPoke) return true
|
||||||
|
|
||||||
|
let avatarList = []
|
||||||
|
let avatar = {}
|
||||||
|
let wifeList = []
|
||||||
|
|
||||||
|
let mys = await MysApi.init(e)
|
||||||
|
if (!mys || !mys.uid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
let player = Player.create(e)
|
||||||
|
let selfUser = mys.selfUser
|
||||||
|
let isSelf = true
|
||||||
|
let renderType = (action === '卡片' ? 'card' : 'photo')
|
||||||
|
let addRet = []
|
||||||
|
switch (action) {
|
||||||
|
case '卡片':
|
||||||
|
case '照片':
|
||||||
|
case '相片':
|
||||||
|
case '图片':
|
||||||
|
case '写真':
|
||||||
|
// 展示老婆卡片
|
||||||
|
// 如果选择过,则进行展示
|
||||||
|
if (!e.isPoke) {
|
||||||
|
wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, [])
|
||||||
|
// 存在设置
|
||||||
|
if (wifeList && wifeList.length > 0 && isSelf && !e.isPoke) {
|
||||||
|
if (wifeList[0] === '随机') {
|
||||||
|
// 如果选择为全部,则从列表中随机选择一个
|
||||||
|
avatarList = await getAvatarList(player, targetCfg.type, mys)
|
||||||
|
let avatar = lodash.sample(avatarList)
|
||||||
|
return Avatar.renderAvatar(e, avatar, renderType)
|
||||||
|
} else {
|
||||||
|
// 如果指定过,则展示指定角色
|
||||||
|
return Avatar.renderAvatar(e, lodash.sample(wifeList), renderType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果未指定过,则从列表中排序并随机选择
|
||||||
|
avatarList = await getAvatarList(player, e.isPoke ? false : targetCfg.type, mys)
|
||||||
|
if (avatarList && avatarList.length > 0) {
|
||||||
|
avatar = lodash.sample(avatarList)
|
||||||
|
return await Avatar.renderAvatar(e, avatar, renderType)
|
||||||
|
}
|
||||||
|
e.reply('在当前米游社公开展示的角色中未能找到适合展示的角色..')
|
||||||
|
return true
|
||||||
|
case '设置':
|
||||||
|
case '选择':
|
||||||
|
case '挑选':
|
||||||
|
case '指定':
|
||||||
|
if (!isSelf) {
|
||||||
|
e.reply('只能指定自己的哦~')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 选择老婆
|
||||||
|
actionParam = actionParam.replace(/(,|、|;|;)/g, ',')
|
||||||
|
wifeList = actionParam.split(',')
|
||||||
|
if (lodash.intersection(['全部', '任意', '随机', '全都要'], wifeList).length > 0) {
|
||||||
|
addRet = ['随机']
|
||||||
|
} else {
|
||||||
|
wifeList = lodash.map(wifeList, (name) => {
|
||||||
|
let char = Character.get(name)
|
||||||
|
if (char && char.checkWifeType(targetCfg.type)) {
|
||||||
|
return char.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
wifeList = lodash.filter(lodash.uniq(wifeList), (d) => !!d)
|
||||||
|
addRet = wifeList
|
||||||
|
if (addRet.length === 0) {
|
||||||
|
e.reply(`在可选的${targetCfg.keyword[0]}列表中未能找到 ${actionParam} ~`)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await selfUser.setCfg(`wife.${targetCfg.key}`, addRet)
|
||||||
|
e.reply(`${targetCfg.keyword[0]}已经设置:${addRet.join(',')}`)
|
||||||
|
return true
|
||||||
|
case '列表':
|
||||||
|
case '是':
|
||||||
|
case '是谁':
|
||||||
|
// 查看当前选择老婆
|
||||||
|
if (!isSelf) {
|
||||||
|
e.reply('只能查看自己的哦~')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
wifeList = await selfUser.getCfg(`wife.${targetCfg.key}`, [])
|
||||||
|
if (wifeList && wifeList.length > 0) {
|
||||||
|
e.reply(`你的${targetCfg.keyword[0]}是:${wifeList.join(',')}`)
|
||||||
|
} else {
|
||||||
|
e.reply(`尚未设置,回复#${targetCfg.keyword[0]}设置+角色名 来设置,如果设置多位请用逗号间隔`)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
async poke (e) {
|
||||||
|
return await Wife.render(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Wife
|
||||||
|
95
apps/help.js
95
apps/help.js
@ -1,7 +1,5 @@
|
|||||||
import lodash from 'lodash'
|
import { App } from '../components/index.js'
|
||||||
import fs from 'fs'
|
import Help from './help/Help.js'
|
||||||
import { Cfg, Version, Common, Data, App } from '../components/index.js'
|
|
||||||
import HelpTheme from './help/HelpTheme.js'
|
|
||||||
|
|
||||||
let app = App.init({
|
let app = App.init({
|
||||||
id: 'help',
|
id: 'help',
|
||||||
@ -9,84 +7,17 @@ let app = App.init({
|
|||||||
desc: '喵喵帮助'
|
desc: '喵喵帮助'
|
||||||
})
|
})
|
||||||
|
|
||||||
app.reg('help', help, {
|
app.reg({
|
||||||
rule: /^#?(喵喵)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$/,
|
help: {
|
||||||
desc: '【#帮助】 #喵喵帮助'
|
rule: /^#?(喵喵)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$/,
|
||||||
})
|
fn: Help.render,
|
||||||
|
desc: '【#帮助】 #喵喵帮助'
|
||||||
app.reg('version', versionInfo, {
|
},
|
||||||
rule: /^#?喵喵版本$/,
|
version: {
|
||||||
desc: '【#帮助】 喵喵版本介绍'
|
rule: /^#?喵喵版本$/,
|
||||||
|
fn: Help.version,
|
||||||
|
desc: '【#帮助】 喵喵版本介绍'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
|
||||||
const _path = process.cwd()
|
|
||||||
const helpPath = `${_path}/plugins/miao-plugin/resources/help`
|
|
||||||
|
|
||||||
async function help (e) {
|
|
||||||
if (!/喵喵/.test(e.msg) && !Cfg.get('help', false)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let custom = {}
|
|
||||||
let help = {}
|
|
||||||
if (fs.existsSync(`${helpPath}/help-cfg.js`)) {
|
|
||||||
console.log('miao-plugin: 检测到存在help-cfg.js配置\n建议将help-cfg.js移为config/help.js或重新复制config/help_default.js进行配置~')
|
|
||||||
help = await import(`file://${helpPath}/help-cfg.js?version=${new Date().getTime()}`)
|
|
||||||
} else if (fs.existsSync(`${helpPath}/help-list.js`)) {
|
|
||||||
console.log('miao-plugin: 检测到存在help-list.js配置,建议将help-list.js移为config/help.js或重新复制config/help_default.js进行配置~')
|
|
||||||
help = await import(`file://${helpPath}/help-list.js?version=${new Date().getTime()}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
let { diyCfg, sysCfg } = await Data.importCfg('help')
|
|
||||||
|
|
||||||
// 兼容一下旧字段
|
|
||||||
if (lodash.isArray(help.helpCfg)) {
|
|
||||||
custom = {
|
|
||||||
helpList: help.helpCfg,
|
|
||||||
helpCfg: {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
custom = help
|
|
||||||
}
|
|
||||||
|
|
||||||
let helpConfig = lodash.defaults(diyCfg.helpCfg || {}, custom.helpCfg, sysCfg.helpCfg)
|
|
||||||
let helpList = diyCfg.helpList || custom.helpList || sysCfg.helpList
|
|
||||||
|
|
||||||
let helpGroup = []
|
|
||||||
|
|
||||||
lodash.forEach(helpList, (group) => {
|
|
||||||
if (group.auth && group.auth === 'master' && !e.isMaster) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
lodash.forEach(group.list, (help) => {
|
|
||||||
let icon = help.icon * 1
|
|
||||||
if (!icon) {
|
|
||||||
help.css = 'display:none'
|
|
||||||
} else {
|
|
||||||
let x = (icon - 1) % 10
|
|
||||||
let y = (icon - x - 1) / 10
|
|
||||||
help.css = `background-position:-${x * 50}px -${y * 50}px`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
helpGroup.push(group)
|
|
||||||
})
|
|
||||||
let themeData = await HelpTheme.getThemeData(diyCfg.helpCfg || {}, sysCfg.helpCfg || {})
|
|
||||||
return await Common.render('help/index', {
|
|
||||||
helpCfg: helpConfig,
|
|
||||||
helpGroup,
|
|
||||||
...themeData,
|
|
||||||
element: 'default'
|
|
||||||
}, { e, scale: 1.2 })
|
|
||||||
}
|
|
||||||
|
|
||||||
async function versionInfo (e) {
|
|
||||||
return await Common.render('help/version-info', {
|
|
||||||
currentVersion: Version.version,
|
|
||||||
changelogs: Version.changelogs,
|
|
||||||
elem: 'cryo'
|
|
||||||
}, { e, scale: 1.2 })
|
|
||||||
}
|
|
||||||
|
77
apps/help/Help.js
Normal file
77
apps/help/Help.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { Cfg, Common, Data, Version } from '../../components/index.js'
|
||||||
|
import fs from 'fs'
|
||||||
|
import lodash from 'lodash'
|
||||||
|
import HelpTheme from './HelpTheme.js'
|
||||||
|
|
||||||
|
const _path = process.cwd()
|
||||||
|
const helpPath = `${_path}/plugins/miao-plugin/resources/help`
|
||||||
|
|
||||||
|
const Help = {
|
||||||
|
async render (e) {
|
||||||
|
if (!/喵喵/.test(e.msg) && !Cfg.get('help', false)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let custom = {}
|
||||||
|
let help = {}
|
||||||
|
if (fs.existsSync(`${helpPath}/help-cfg.js`)) {
|
||||||
|
console.log('miao-plugin: 检测到存在help-cfg.js配置\n建议将help-cfg.js移为config/help.js或重新复制config/help_default.js进行配置~')
|
||||||
|
help = await import(`file://${helpPath}/help-cfg.js?version=${new Date().getTime()}`)
|
||||||
|
} else if (fs.existsSync(`${helpPath}/help-list.js`)) {
|
||||||
|
console.log('miao-plugin: 检测到存在help-list.js配置,建议将help-list.js移为config/help.js或重新复制config/help_default.js进行配置~')
|
||||||
|
help = await import(`file://${helpPath}/help-list.js?version=${new Date().getTime()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
let { diyCfg, sysCfg } = await Data.importCfg('help')
|
||||||
|
|
||||||
|
// 兼容一下旧字段
|
||||||
|
if (lodash.isArray(help.helpCfg)) {
|
||||||
|
custom = {
|
||||||
|
helpList: help.helpCfg,
|
||||||
|
helpCfg: {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
custom = help
|
||||||
|
}
|
||||||
|
|
||||||
|
let helpConfig = lodash.defaults(diyCfg.helpCfg || {}, custom.helpCfg, sysCfg.helpCfg)
|
||||||
|
let helpList = diyCfg.helpList || custom.helpList || sysCfg.helpList
|
||||||
|
|
||||||
|
let helpGroup = []
|
||||||
|
|
||||||
|
lodash.forEach(helpList, (group) => {
|
||||||
|
if (group.auth && group.auth === 'master' && !e.isMaster) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
lodash.forEach(group.list, (help) => {
|
||||||
|
let icon = help.icon * 1
|
||||||
|
if (!icon) {
|
||||||
|
help.css = 'display:none'
|
||||||
|
} else {
|
||||||
|
let x = (icon - 1) % 10
|
||||||
|
let y = (icon - x - 1) / 10
|
||||||
|
help.css = `background-position:-${x * 50}px -${y * 50}px`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
helpGroup.push(group)
|
||||||
|
})
|
||||||
|
let themeData = await HelpTheme.getThemeData(diyCfg.helpCfg || {}, sysCfg.helpCfg || {})
|
||||||
|
return await Common.render('help/index', {
|
||||||
|
helpCfg: helpConfig,
|
||||||
|
helpGroup,
|
||||||
|
...themeData,
|
||||||
|
element: 'default'
|
||||||
|
}, { e, scale: 1.2 })
|
||||||
|
},
|
||||||
|
|
||||||
|
async version (e) {
|
||||||
|
return await Common.render('help/version-info', {
|
||||||
|
currentVersion: Version.version,
|
||||||
|
changelogs: Version.changelogs,
|
||||||
|
elem: 'cryo'
|
||||||
|
}, { e, scale: 1.2 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default Help
|
@ -1,5 +1,5 @@
|
|||||||
import { App } from '../components/index.js'
|
import { App } from '../components/index.js'
|
||||||
import { pokeWife } from './character/AvatarWife.js'
|
import Wife from './character/AvatarWife.js'
|
||||||
|
|
||||||
let app = App.init({
|
let app = App.init({
|
||||||
id: 'poke',
|
id: 'poke',
|
||||||
@ -7,8 +7,11 @@ let app = App.init({
|
|||||||
event: 'poke'
|
event: 'poke'
|
||||||
})
|
})
|
||||||
|
|
||||||
app.reg('pock-wife', pokeWife, {
|
app.reg({
|
||||||
describe: '#老公 #老婆 查询'
|
pockWife: {
|
||||||
|
fn: Wife.poke,
|
||||||
|
describe: '#老公 #老婆 查询'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
164
apps/profile.js
164
apps/profile.js
@ -1,9 +1,9 @@
|
|||||||
import { App } from '../components/index.js'
|
import { App } from '../components/index.js'
|
||||||
import { getProfile, profileHelp } from './profile/ProfileCommon.js'
|
import { profileHelp } from './profile/ProfileCommon.js'
|
||||||
import { profileArtisList } from './profile/ProfileArtis.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 { profileStat } from './profile/ProfileStat.js'
|
||||||
import { profileList } from './profile/ProfileList.js'
|
import ProfileList from './profile/ProfileList.js'
|
||||||
import { uploadCharacterImg, delProfileImg, profileImgList } from './character/ImgUpload.js'
|
import { uploadCharacterImg, delProfileImg, profileImgList } from './character/ImgUpload.js'
|
||||||
import { enemyLv } from './profile/ProfileUtils.js'
|
import { enemyLv } from './profile/ProfileUtils.js'
|
||||||
import { groupRank, resetRank, refreshRank, manageRank } from './profile/ProfileRank.js'
|
import { groupRank, resetRank, refreshRank, manageRank } from './profile/ProfileRank.js'
|
||||||
@ -12,86 +12,110 @@ let app = App.init({
|
|||||||
id: 'profile',
|
id: 'profile',
|
||||||
name: '角色面板'
|
name: '角色面板'
|
||||||
})
|
})
|
||||||
app.reg('profile-detail', profileDetail, {
|
|
||||||
rule: /^#*([^#]+)\s*(详细|详情|面板|面版|圣遗物|伤害[1-7]?)\s*(\d{9})*(.*[换变改].*)?$/,
|
|
||||||
name: '角色面板'
|
|
||||||
})
|
|
||||||
app.reg('profile-change', profileDetail, {
|
|
||||||
rule: /^#.+换.+$/,
|
|
||||||
name: '角色面板计算'
|
|
||||||
})
|
|
||||||
|
|
||||||
app.reg('group-profile', groupRank, {
|
app.reg({
|
||||||
rule: /^#(群|群内)?(排名|排行)?(最强|最高|最高分|最牛|第一)+.+/,
|
profileDetail: {
|
||||||
name: '群内最强'
|
rule: /^#*([^#]+)\s*(详细|详情|面板|面版|圣遗物|伤害[1-7]?)\s*(\d{9})*(.*[换变改].*)?$/,
|
||||||
})
|
fn: profileDetail,
|
||||||
|
name: '角色面板'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('reset-rank', resetRank, {
|
profileChange: {
|
||||||
rule: /^#(重置|重设)(.*)(排名|排行)$/,
|
rule: /^#.+换.+$/,
|
||||||
name: '重置排名'
|
fn: profileDetail,
|
||||||
})
|
name: '角色面板计算'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('refresh-rank', refreshRank, {
|
groupProfile: {
|
||||||
rule: /^#(刷新|更新|重新加载)(群内|群|全部)*(排名|排行)$/,
|
rule: /^#(群|群内)?(排名|排行)?(最强|最高|最高分|最牛|第一)+.+/,
|
||||||
name: '重置排名'
|
fn: groupRank,
|
||||||
})
|
name: '群内最强'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('manage-rank', manageRank, {
|
resetRank: {
|
||||||
rule: /^#(开启|打开|启用|关闭|禁用)(群内|群|全部)*(排名|排行)$/,
|
rule: /^#(重置|重设)(.*)(排名|排行)$/,
|
||||||
name: '打开关闭'
|
fn: resetRank,
|
||||||
})
|
name: '重置排名'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('rank-list', groupRank, {
|
refreshRank: {
|
||||||
rule: /^#(群|群内)?.+(排名|排行)(榜)?$/,
|
rule: /^#(刷新|更新|重新加载)(群内|群|全部)*(排名|排行)$/,
|
||||||
name: '面板排名榜'
|
fn: refreshRank,
|
||||||
})
|
name: '重置排名'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('artis-list', profileArtisList, {
|
manageRank: {
|
||||||
rule: /^#圣遗物列表\s*(\d{9})?$/,
|
rule: /^#(开启|打开|启用|关闭|禁用)(群内|群|全部)*(排名|排行)$/,
|
||||||
name: '面板圣遗物列表'
|
fn: manageRank,
|
||||||
})
|
name: '打开关闭'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('profile-list', profileList, {
|
rankList: {
|
||||||
rule: /^#(面板角色|角色面板|面板)(列表)?\s*(\d{9})?$/,
|
rule: /^#(群|群内)?.+(排名|排行)(榜)?$/,
|
||||||
name: '面板角色列表',
|
fn: groupRank,
|
||||||
desc: '查看当前已获取面板数据的角色列表'
|
name: '面板排名榜'
|
||||||
})
|
},
|
||||||
|
|
||||||
app.reg('profile-stat', profileStat, {
|
artisList: {
|
||||||
rule: /^#(面板|喵喵|角色|武器|天赋|技能|圣遗物)?练度统计$/,
|
rule: /^#圣遗物列表\s*(\d{9})?$/,
|
||||||
name: '面板练度统计'
|
fn: profileArtisList,
|
||||||
})
|
name: '面板圣遗物列表'
|
||||||
app.reg('avatar-list', profileStat, {
|
},
|
||||||
rule: /^(#(角色|查询|查询角色|角色查询|人物)[ |0-9]*$)|(^(#*uid|#*UID)\+*[1|2|5-9][0-9]{8}$)|(^#[\+|+]*[1|2|5-9][0-9]{8})/,
|
|
||||||
name: '角色查询'
|
|
||||||
})
|
|
||||||
|
|
||||||
app.reg('profile-help', profileHelp, {
|
profileList: {
|
||||||
rule: /^#(角色|换|更换)?面[板版]帮助$/,
|
rule: /^#(面板角色|角色面板|面板)(列表)?\s*(\d{9})?$/,
|
||||||
name: '角色面板帮助'
|
fn: ProfileList.render,
|
||||||
})
|
name: '面板角色列表',
|
||||||
|
desc: '查看当前已获取面板数据的角色列表'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('enemy-lv', enemyLv, {
|
profileStat: {
|
||||||
rule: /^#(敌人|怪物)等级\s*\d{1,3}\s*$/,
|
rule: /^#(面板|喵喵|角色|武器|天赋|技能|圣遗物)?练度统计$/,
|
||||||
describe: '【#角色】 设置伤害计算中目标敌人的等级'
|
fn: profileStat,
|
||||||
})
|
name: '面板练度统计'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('profile-refresh', getProfile, {
|
avatarList: {
|
||||||
rule: /^#(全部面板更新|更新全部面板|获取游戏角色详情|更新面板|面板更新)\s*(\d{9})?$/,
|
rule: /^(#(角色|查询|查询角色|角色查询|人物)[ |0-9]*$)|(^(#*uid|#*UID)\+*[1|2|5-9][0-9]{8}$)|(^#[\+|+]*[1|2|5-9][0-9]{8})/,
|
||||||
describe: '【#角色】 获取游戏橱窗详情数据'
|
fn: profileStat,
|
||||||
})
|
name: '角色查询'
|
||||||
|
},
|
||||||
|
|
||||||
app.reg('upload-img', uploadCharacterImg, {
|
profileHelp: {
|
||||||
rule: /^#?\s*(?:上传|添加)(.+)(?:面板图)\s*$/,
|
rule: /^#(角色|换|更换)?面[板版]帮助$/,
|
||||||
describe: '【#上传刻晴面板图】 上传角色面板图'
|
fn: profileHelp,
|
||||||
})
|
name: '角色面板帮助'
|
||||||
app.reg('del-profile', delProfileImg, {
|
},
|
||||||
rule: /^#?\s*(?:移除|清除|删除)(.+)(?:面板图)(\d){1,}\s*$/,
|
|
||||||
describe: '【#删除刻晴面板图1】 删除指定角色面板图(序号)'
|
enemyLv: {
|
||||||
})
|
rule: /^#(敌人|怪物)等级\s*\d{1,3}\s*$/,
|
||||||
app.reg('profile-img-list', profileImgList, {
|
fn: enemyLv,
|
||||||
rule: /^#?\s*(.+)(?:面板图列表)\s*$/,
|
describe: '【#角色】 设置伤害计算中目标敌人的等级'
|
||||||
describe: '【#刻晴面板图列表】 删除指定角色面板图(序号)'
|
},
|
||||||
|
|
||||||
|
profileRefresh: {
|
||||||
|
rule: /^#(全部面板更新|更新全部面板|获取游戏角色详情|更新面板|面板更新)\s*(\d{9})?$/,
|
||||||
|
fn: ProfileList.refresh,
|
||||||
|
describe: '【#角色】 获取游戏橱窗详情数据'
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadImg: {
|
||||||
|
rule: /^#?\s*(?:上传|添加)(.+)(?:面板图)\s*$/,
|
||||||
|
fn: uploadCharacterImg,
|
||||||
|
describe: '【#上传刻晴面板图】 上传角色面板图'
|
||||||
|
},
|
||||||
|
|
||||||
|
delProfile: {
|
||||||
|
rule: /^#?\s*(?:移除|清除|删除)(.+)(?:面板图)(\d){1,}\s*$/,
|
||||||
|
fn: delProfileImg,
|
||||||
|
describe: '【#删除刻晴面板图1】 删除指定角色面板图(序号)'
|
||||||
|
},
|
||||||
|
|
||||||
|
profileImgList: {
|
||||||
|
rule: /^#?\s*(.+)(?:面板图列表)\s*$/,
|
||||||
|
fn: profileImgList,
|
||||||
|
describe: '【#刻晴面板图列表】 删除指定角色面板图(序号)'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* */
|
* */
|
||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import { Cfg, Common } from '../../components/index.js'
|
import { Cfg, Common } from '../../components/index.js'
|
||||||
import { getTargetUid, profileHelp, autoGetProfile } from './ProfileCommon.js'
|
import { getTargetUid, profileHelp, getProfileRefresh } from './ProfileCommon.js'
|
||||||
import { Artifact, Character, ProfileArtis, Player } from '../../models/index.js'
|
import { Artifact, Character, ProfileArtis, Player } from '../../models/index.js'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -12,26 +12,15 @@ import { Artifact, Character, ProfileArtis, Player } from '../../models/index.js
|
|||||||
* */
|
* */
|
||||||
export async function profileArtis (e) {
|
export async function profileArtis (e) {
|
||||||
let { uid, avatar } = e
|
let { uid, avatar } = e
|
||||||
|
let profile = e._profile || await getProfileRefresh(e, avatar)
|
||||||
let profile
|
if (!profile) {
|
||||||
if (e._profile) {
|
return true
|
||||||
profile = e._profile
|
|
||||||
} else {
|
|
||||||
let autoRet = await autoGetProfile(e, uid, avatar, async () => {
|
|
||||||
await profileArtis(e)
|
|
||||||
})
|
|
||||||
if (autoRet.err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
profile = autoRet.profile
|
|
||||||
}
|
}
|
||||||
let char = profile.char
|
|
||||||
|
|
||||||
if (!profile.hasArtis()) {
|
if (!profile.hasArtis()) {
|
||||||
e.reply('未能获得圣遗物详情,请重新获取面板信息后查看')
|
e.reply('未能获得圣遗物详情,请重新获取面板信息后查看')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
let char = profile.char
|
||||||
let charCfg = profile.artis.getCharCfg()
|
let charCfg = profile.artis.getCharCfg()
|
||||||
|
|
||||||
let { attrMap } = Artifact.getMeta()
|
let { attrMap } = Artifact.getMeta()
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* 面板公共方法及处理
|
* 面板公共方法及处理
|
||||||
* */
|
* */
|
||||||
import lodash from 'lodash'
|
|
||||||
import { segment } from 'oicq'
|
import { segment } from 'oicq'
|
||||||
import { profileList } from './ProfileList.js'
|
|
||||||
import { Version } from '../../components/index.js'
|
import { Version } from '../../components/index.js'
|
||||||
import { Character, MysApi, Player } from '../../models/index.js'
|
import { Character, MysApi, Player } from '../../models/index.js'
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ const _getTargetUid = async function (e) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
uid = user.uid
|
uid = user.uid
|
||||||
if (!uid || !uidReg.test(uid)) {
|
if ((!uid || !uidReg.test(uid)) && !e._replyNeedUid) {
|
||||||
e.reply('请先发送【#绑定+你的UID】来绑定查询目标')
|
e.reply('请先发送【#绑定+你的UID】来绑定查询目标')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -75,114 +73,24 @@ export async function getTargetUid (e) {
|
|||||||
return uid
|
return uid
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
export async function getProfileRefresh (e, avatar) {
|
||||||
* 自动更新面板数据
|
|
||||||
* */
|
|
||||||
export async function autoRefresh (e) {
|
|
||||||
let uid = await getTargetUid(e)
|
|
||||||
if (!uid || e.isRefreshed) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let refreshMark = await redis.get(`miao:profile-refresh-cd:${uid}`)
|
|
||||||
let inCd = await redis.get(`miao:role-all:${uid}`)
|
|
||||||
|
|
||||||
if (refreshMark || inCd) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
await redis.set(`miao:profile-refresh-cd:${uid}`, 'TRUE', { EX: 3600 * 12 })
|
|
||||||
e.isRefreshed = true
|
|
||||||
|
|
||||||
// 数据更新
|
|
||||||
let player = Player.create(e)
|
|
||||||
let data = await player.refreshProfile()
|
|
||||||
if (!data) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.chars) {
|
|
||||||
e.reply('请确认角色已在【游戏内】橱窗展示并开放了查看详情。请在设置完毕5分钟后使用 #面板更新 重新获取')
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
let ret = []
|
|
||||||
lodash.forEach(data.chars, (ds) => {
|
|
||||||
let char = Character.get(ds.id)
|
|
||||||
if (char) {
|
|
||||||
ret.push(char.name)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (ret.length === 0) {
|
|
||||||
e.reply('请确认角色已在【游戏内】橱窗展示并开放了查看详情。请在设置完毕5分钟后使用 #面板更新 重新获取')
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
// e.reply(`本次获取成功角色: ${ret.join(", ")} `)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function autoGetProfile (e, uid, avatar, callback) {
|
|
||||||
let refresh = async () => {
|
|
||||||
let refreshRet = await autoRefresh(e)
|
|
||||||
if (refreshRet) {
|
|
||||||
await callback()
|
|
||||||
}
|
|
||||||
return refreshRet
|
|
||||||
}
|
|
||||||
|
|
||||||
let char = Character.get(avatar)
|
let char = Character.get(avatar)
|
||||||
if (!char) {
|
if (!char) {
|
||||||
return { err: true }
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
let player = Player.create(e)
|
let player = Player.create(e)
|
||||||
let profile = player.getProfile(char.id)
|
let profile = player.getProfile(char.id)
|
||||||
if (!profile || !profile.hasData) {
|
if (!profile || !profile.hasData) {
|
||||||
if (await refresh()) {
|
logger.mark(`本地无UID:${player.uid}的${char.name}面板数据,尝试自动请求...`)
|
||||||
return { err: true }
|
await player.refresh({ profile: true })
|
||||||
} else {
|
profile = player.getProfile(char.id)
|
||||||
e.reply(`请确认${char.name}已展示在【游戏内】的角色展柜中,并打开了“显示角色详情”。然后请使用 #更新面板\n命令来获取${char.name}的面板详情`)
|
|
||||||
}
|
|
||||||
return { err: true }
|
|
||||||
}
|
}
|
||||||
return { profile, char, refresh }
|
if (!profile || !profile.hasData) {
|
||||||
}
|
e.reply(`请确认${char.name}已展示在【游戏内】的角色展柜中,并打开了“显示角色详情”。然后请使用 #更新面板\n命令来获取${char.name}的面板详情`)
|
||||||
|
return false
|
||||||
/*
|
|
||||||
* 面板数据更新
|
|
||||||
* */
|
|
||||||
export async function getProfile (e) {
|
|
||||||
let uid = await getTargetUid(e)
|
|
||||||
if (!uid) {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return profile
|
||||||
// 数据更新
|
|
||||||
let player = Player.create(e)
|
|
||||||
let ret = await player.refreshProfile()
|
|
||||||
if (!ret) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!player._update.length === 0) {
|
|
||||||
e.reply('获取角色面板数据失败,请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~')
|
|
||||||
} else {
|
|
||||||
let ret = {}
|
|
||||||
lodash.forEach(player._update, (id) => {
|
|
||||||
let char = Character.get(id)
|
|
||||||
if (char) {
|
|
||||||
ret[char.name] = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (ret.length === 0) {
|
|
||||||
e.reply('获取角色面板数据失败,未能请求到角色数据。请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~')
|
|
||||||
} else {
|
|
||||||
e.newChar = ret
|
|
||||||
return await profileList(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import { autoRefresh, getProfile, getTargetUid } from './ProfileCommon.js'
|
import { getTargetUid, getProfileRefresh } from './ProfileCommon.js'
|
||||||
|
import ProfileList from './ProfileList.js'
|
||||||
import { Cfg, Common, Format } from '../../components/index.js'
|
import { Cfg, Common, Format } from '../../components/index.js'
|
||||||
import { MysApi, ProfileRank, ProfileArtis, Player, Character } from '../../models/index.js'
|
import { MysApi, ProfileRank, ProfileArtis, Player, Character } from '../../models/index.js'
|
||||||
import ProfileChange from './ProfileChange.js'
|
import ProfileChange from './ProfileChange.js'
|
||||||
@ -93,7 +94,7 @@ export async function profileDetail (e) {
|
|||||||
if (mode === 'profile' || mode === 'dmg') {
|
if (mode === 'profile' || mode === 'dmg') {
|
||||||
return renderProfile(e, char, mode, { dmgIdx })
|
return renderProfile(e, char, mode, { dmgIdx })
|
||||||
} else if (mode === 'refresh') {
|
} else if (mode === 'refresh') {
|
||||||
await getProfile(e)
|
await ProfileList.refresh(e)
|
||||||
return true
|
return true
|
||||||
} else if (mode === 'artis') {
|
} else if (mode === 'artis') {
|
||||||
return profileArtis(e)
|
return profileArtis(e)
|
||||||
@ -116,23 +117,8 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
let player = Player.create(uid)
|
let profile = e._profile || await getProfileRefresh(e, char.id)
|
||||||
let profile = e._profile || player.getProfile(char.id)
|
if (!profile) {
|
||||||
|
|
||||||
let refresh = async () => {
|
|
||||||
let refreshRet = await autoRefresh(e)
|
|
||||||
if (refreshRet) {
|
|
||||||
await renderProfile(e, char, mode, params)
|
|
||||||
}
|
|
||||||
return refreshRet
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!profile || !profile.hasData) {
|
|
||||||
if (await refresh()) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
e.reply(`请确认${char.name}已展示在【游戏内】的角色展柜中,并打开了“显示角色详情”。然后请使用 #更新面板\n命令来获取${char.name}的面板详情`)
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
char = profile.char || char
|
char = profile.char || char
|
||||||
|
@ -1,93 +1,121 @@
|
|||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import { autoRefresh, getTargetUid } from './ProfileCommon.js'
|
import { getTargetUid } from './ProfileCommon.js'
|
||||||
import { ProfileRank, Player } from '../../models/index.js'
|
import { ProfileRank, Player, Character } from '../../models/index.js'
|
||||||
import { Common, Data } from '../../components/index.js'
|
import { Common, Data } from '../../components/index.js'
|
||||||
|
|
||||||
export async function profileList (e) {
|
const ProfileList = {
|
||||||
let uid = await getTargetUid(e)
|
async refresh (e) {
|
||||||
if (!uid) {
|
let uid = await getTargetUid(e)
|
||||||
return true
|
if (!uid) {
|
||||||
}
|
|
||||||
let isSelfUid = false
|
|
||||||
if (e.runtime) {
|
|
||||||
let uids = e.runtime?.user?.ckUids || []
|
|
||||||
isSelfUid = uids.join(',').split(',').includes(uid + '')
|
|
||||||
}
|
|
||||||
let rank = false
|
|
||||||
let servName = Player.getProfileServName(uid)
|
|
||||||
let hasNew = false
|
|
||||||
let newCount = 0
|
|
||||||
|
|
||||||
let chars = []
|
|
||||||
let msg = ''
|
|
||||||
let newChar = {}
|
|
||||||
if (e.newChar) {
|
|
||||||
msg = '获取角色面板数据成功'
|
|
||||||
newChar = e.newChar
|
|
||||||
}
|
|
||||||
const cfg = await Data.importCfg('cfg')
|
|
||||||
// 获取面板数据
|
|
||||||
let player = Player.create(uid)
|
|
||||||
let profiles = player.getProfiles()
|
|
||||||
// 检测标志位
|
|
||||||
let qq = (e.at && !e.atBot) ? e.at : e.qq
|
|
||||||
await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: isSelfUid ? 'ck' : 'bind' })
|
|
||||||
|
|
||||||
let groupId = e.group_id
|
|
||||||
if (groupId) {
|
|
||||||
rank = await ProfileRank.create({ groupId, uid, qq: e.user_id })
|
|
||||||
}
|
|
||||||
const rankCfg = await ProfileRank.getGroupCfg(groupId)
|
|
||||||
const groupRank = rank && (cfg?.diyCfg?.groupRank || false) && rankCfg.status !== 1
|
|
||||||
await player.forEachAvatarAsync(async function (avatar) {
|
|
||||||
let profile = avatar.getProfile()
|
|
||||||
if (!profile) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let char = profile.char
|
|
||||||
let tmp = char.getData('id,face,name,abbr,element,star')
|
|
||||||
tmp.face = char.getImgs(profile.costume).face
|
|
||||||
tmp.level = profile.level || 1
|
|
||||||
tmp.cons = profile.cons
|
|
||||||
tmp.isNew = 0
|
|
||||||
if (newChar[char.name]) {
|
|
||||||
tmp.isNew = 1
|
|
||||||
newCount++
|
|
||||||
}
|
|
||||||
if (rank) {
|
|
||||||
tmp.groupRank = await rank.getRank(profile, !!tmp.isNew)
|
|
||||||
}
|
|
||||||
chars.push(tmp)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (chars.length === 0) {
|
// 数据更新
|
||||||
if (await autoRefresh(e)) {
|
let player = Player.create(e)
|
||||||
await profileList(e)
|
await player.refreshProfile(2)
|
||||||
return true
|
|
||||||
|
if (!player?._update?.length) {
|
||||||
|
e.reply('获取角色面板数据失败,请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~')
|
||||||
} else {
|
} else {
|
||||||
e.reply(`本地暂无uid${uid}的面板数据...`)
|
let ret = {}
|
||||||
|
lodash.forEach(player._update, (id) => {
|
||||||
|
let char = Character.get(id)
|
||||||
|
if (char) {
|
||||||
|
ret[char.name] = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (ret.length === 0) {
|
||||||
|
e.reply('获取角色面板数据失败,未能请求到角色数据。请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~')
|
||||||
|
} else {
|
||||||
|
e.newChar = ret
|
||||||
|
return await ProfileList.render(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
},
|
||||||
|
async render (e) {
|
||||||
|
let uid = await getTargetUid(e)
|
||||||
|
if (!uid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
let isSelfUid = false
|
||||||
|
if (e.runtime) {
|
||||||
|
let uids = e.runtime?.user?.ckUids || []
|
||||||
|
isSelfUid = uids.join(',').split(',').includes(uid + '')
|
||||||
|
}
|
||||||
|
let rank = false
|
||||||
|
let servName = Player.getProfileServName(uid)
|
||||||
|
let hasNew = false
|
||||||
|
let newCount = 0
|
||||||
|
|
||||||
|
let chars = []
|
||||||
|
let msg = ''
|
||||||
|
let newChar = {}
|
||||||
|
if (e.newChar) {
|
||||||
|
msg = '获取角色面板数据成功'
|
||||||
|
newChar = e.newChar
|
||||||
|
}
|
||||||
|
const cfg = await Data.importCfg('cfg')
|
||||||
|
// 获取面板数据
|
||||||
|
let player = Player.create(e)
|
||||||
|
if (!player.hasProfile) {
|
||||||
|
await player.refresh({ profile: true })
|
||||||
|
}
|
||||||
|
if (!player.hasProfile) {
|
||||||
|
e.reply(`本地暂无uid${uid}的面板数据...`)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
let profiles = player.getProfiles()
|
||||||
|
|
||||||
|
// 检测标志位
|
||||||
|
let qq = (e.at && !e.atBot) ? e.at : e.qq
|
||||||
|
await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: isSelfUid ? 'ck' : 'bind' })
|
||||||
|
|
||||||
|
let groupId = e.group_id
|
||||||
|
if (groupId) {
|
||||||
|
rank = await ProfileRank.create({ groupId, uid, qq: e.user_id })
|
||||||
|
}
|
||||||
|
const rankCfg = await ProfileRank.getGroupCfg(groupId)
|
||||||
|
const groupRank = rank && (cfg?.diyCfg?.groupRank || false) && rankCfg.status !== 1
|
||||||
|
for (let id in profiles) {
|
||||||
|
let profile = profiles[id]
|
||||||
|
let char = profile.char
|
||||||
|
let tmp = char.getData('id,face,name,abbr,element,star')
|
||||||
|
tmp.face = char.getImgs(profile.costume).face
|
||||||
|
tmp.level = profile.level || 1
|
||||||
|
tmp.cons = profile.cons
|
||||||
|
tmp.isNew = 0
|
||||||
|
if (newChar[char.name]) {
|
||||||
|
tmp.isNew = 1
|
||||||
|
newCount++
|
||||||
|
}
|
||||||
|
if (rank) {
|
||||||
|
tmp.groupRank = await rank.getRank(profile, !!tmp.isNew)
|
||||||
|
}
|
||||||
|
chars.push(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newCount > 0) {
|
||||||
|
hasNew = newCount <= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
chars = lodash.sortBy(chars, ['isNew', 'star', 'level', 'id'])
|
||||||
|
chars = chars.reverse()
|
||||||
|
|
||||||
|
player.save()
|
||||||
|
// 渲染图像
|
||||||
|
return await Common.render('character/profile-list', {
|
||||||
|
save_id: uid,
|
||||||
|
uid,
|
||||||
|
chars,
|
||||||
|
servName,
|
||||||
|
hasNew,
|
||||||
|
msg,
|
||||||
|
groupRank,
|
||||||
|
allowRank: rank && rank.allowRank,
|
||||||
|
rankCfg
|
||||||
|
}, { e, scale: 1.6 })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCount > 0) {
|
|
||||||
hasNew = newCount <= 8
|
|
||||||
}
|
|
||||||
|
|
||||||
chars = lodash.sortBy(chars, ['isNew', 'star', 'level', 'id'])
|
|
||||||
chars = chars.reverse()
|
|
||||||
|
|
||||||
player.save()
|
|
||||||
// 渲染图像
|
|
||||||
return await Common.render('character/profile-list', {
|
|
||||||
save_id: uid,
|
|
||||||
uid,
|
|
||||||
chars,
|
|
||||||
servName,
|
|
||||||
hasNew,
|
|
||||||
msg,
|
|
||||||
groupRank,
|
|
||||||
allowRank: rank && rank.allowRank,
|
|
||||||
rankCfg
|
|
||||||
}, { e, scale: 1.6 })
|
|
||||||
}
|
}
|
||||||
|
export default ProfileList
|
||||||
|
@ -26,6 +26,8 @@ export async function profileStat (e) {
|
|||||||
await player.refreshMysInfo()
|
await player.refreshMysInfo()
|
||||||
|
|
||||||
let avatarRet = await player.refreshAndGetAvatarData({
|
let avatarRet = await player.refreshAndGetAvatarData({
|
||||||
|
detail: 1,
|
||||||
|
talent: 0,
|
||||||
rank: true,
|
rank: true,
|
||||||
retType: 'array',
|
retType: 'array',
|
||||||
sort: true
|
sort: true
|
||||||
|
522
apps/stat.js
522
apps/stat.js
@ -2,508 +2,36 @@
|
|||||||
* 胡桃数据库的统计
|
* 胡桃数据库的统计
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
import lodash from 'lodash'
|
import { App } from '../components/index.js'
|
||||||
import { Cfg, Common, App, Data } from '../components/index.js'
|
import { ConsStat, AbyssPct } from './stat/AbyssStat.js'
|
||||||
import { Abyss, Character, MysApi, Player } from '../models/index.js'
|
import { AbyssTeam } from './stat/AbyssTeam.js'
|
||||||
import HutaoApi from './wiki/HutaoApi.js'
|
import { AbyssSummary } from './stat/AbyssSummary.js'
|
||||||
|
|
||||||
let app = App.init({
|
let app = App.init({
|
||||||
id: 'stat',
|
id: 'stat',
|
||||||
name: '深渊统计'
|
name: '深渊统计'
|
||||||
})
|
})
|
||||||
|
|
||||||
app.reg('cons-stat', consStat, {
|
app.reg({
|
||||||
rule: /^#(喵喵)?角色(持有|持有率|命座|命之座|.命)(分布|统计|持有|持有率)?$/,
|
consStat: {
|
||||||
desc: '【#统计】 #角色持有率 #角色5命统计'
|
rule: /^#(喵喵)?角色(持有|持有率|命座|命之座|.命)(分布|统计|持有|持有率)?$/,
|
||||||
})
|
fn: ConsStat,
|
||||||
app.reg('abyss-pct', abyssPct, {
|
desc: '【#统计】 #角色持有率 #角色5命统计'
|
||||||
rule: /^#(喵喵)?深渊(第?.{1,2}层)?(角色)?(出场|使用)(率|统计)*$/,
|
},
|
||||||
desc: '【#统计】 #深渊出场率 #深渊12层出场率'
|
abyssPct: {
|
||||||
})
|
rule: /^#(喵喵)?深渊(第?.{1,2}层)?(角色)?(出场|使用)(率|统计)*$/,
|
||||||
app.reg('abyss-team', abyssTeam, {
|
fn: AbyssPct,
|
||||||
rule: /#深渊(组队|配队)/,
|
desc: '【#统计】 #深渊出场率 #深渊12层出场率'
|
||||||
describe: '【#角色】 #深渊组队'
|
},
|
||||||
})
|
abyssTeam: {
|
||||||
app.reg('upload-data', uploadData, {
|
rule: /#深渊(组队|配队)/,
|
||||||
rule: /^#*(喵喵|上传|本期)*(深渊|深境|深境螺旋)[ |0-9]*(数据)?$/,
|
fn: AbyssTeam,
|
||||||
desc: '上传深渊'
|
describe: '【#角色】 #深渊组队'
|
||||||
|
},
|
||||||
|
abyssSummary: {
|
||||||
|
rule: /^#*(喵喵|上传|本期)*(深渊|深境|深境螺旋)[ |0-9]*(数据)?$/,
|
||||||
|
fn: AbyssSummary,
|
||||||
|
desc: '上传深渊'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
export default app
|
export default app
|
||||||
|
|
||||||
async function consStat (e) {
|
|
||||||
let consData = await HutaoApi.getCons()
|
|
||||||
let overview = await HutaoApi.getOverview()
|
|
||||||
|
|
||||||
if (!consData) {
|
|
||||||
e.reply('角色持有数据获取失败,请稍后重试~')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
let msg = e.msg
|
|
||||||
|
|
||||||
let mode = /持有/.test(msg) ? 'char' : 'cons'
|
|
||||||
|
|
||||||
let conNum = -1
|
|
||||||
if (mode === 'cons') {
|
|
||||||
lodash.forEach([/0|零/, /1|一/, /2|二/, /3|三/, /4|四/, /5|五/, /6|六|满/], (reg, idx) => {
|
|
||||||
if (reg.test(msg)) {
|
|
||||||
conNum = idx
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!consData && !consData.data) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = consData.data
|
|
||||||
|
|
||||||
let Lumine = lodash.filter(data, (ds) => ds.avatar === 10000007)[0] || {}
|
|
||||||
let Aether = lodash.filter(data, (ds) => ds.avatar === 10000005)[0] || {}
|
|
||||||
|
|
||||||
Lumine.holdingRate = (1 - Aether.holdingRate) || Lumine.holdingRate
|
|
||||||
|
|
||||||
let ret = []
|
|
||||||
|
|
||||||
lodash.forEach(data, (ds) => {
|
|
||||||
let char = Character.get(ds.avatar)
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
name: char.name || ds.avatar,
|
|
||||||
abbr: char.abbr,
|
|
||||||
star: char.star || 3,
|
|
||||||
side: char.side,
|
|
||||||
hold: ds.holdingRate
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode === 'char') {
|
|
||||||
data.cons = lodash.map(ds.rate, (c) => {
|
|
||||||
c.value = c.value * ds.holdingRate
|
|
||||||
return c
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
data.cons = ds.rate
|
|
||||||
}
|
|
||||||
data.cons = lodash.sortBy(data.cons, ['id'])
|
|
||||||
|
|
||||||
ret.push(data)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (conNum > -1) {
|
|
||||||
ret = lodash.sortBy(ret, [`cons[${conNum}].value`])
|
|
||||||
ret.reverse()
|
|
||||||
} else {
|
|
||||||
ret = lodash.sortBy(ret, ['hold'])
|
|
||||||
}
|
|
||||||
// 渲染图像
|
|
||||||
return await Common.render('stat/character', {
|
|
||||||
chars: ret,
|
|
||||||
mode,
|
|
||||||
conNum,
|
|
||||||
totalCount: overview?.data?.totalPlayerCount || 0,
|
|
||||||
lastUpdate: consData.lastUpdate,
|
|
||||||
pct: function (num) {
|
|
||||||
return (num * 100).toFixed(2)
|
|
||||||
}
|
|
||||||
}, { e, scale: 1.5 })
|
|
||||||
}
|
|
||||||
|
|
||||||
async function abyssPct (e) {
|
|
||||||
let mode = /使用/.test(e.msg) ? 'use' : 'pct'
|
|
||||||
let modeName
|
|
||||||
let abyssData
|
|
||||||
let modeMulti = 1
|
|
||||||
|
|
||||||
if (mode === 'use') {
|
|
||||||
modeName = '使用率'
|
|
||||||
abyssData = await HutaoApi.getAbyssUse()
|
|
||||||
} else {
|
|
||||||
modeName = '出场率'
|
|
||||||
abyssData = await HutaoApi.getAbyssPct()
|
|
||||||
modeMulti = 8
|
|
||||||
}
|
|
||||||
let overview = await HutaoApi.getOverview()
|
|
||||||
|
|
||||||
if (!abyssData) {
|
|
||||||
e.reply(`深渊${modeName}数据获取失败,请稍后重试~`)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret = []
|
|
||||||
let chooseFloor = -1
|
|
||||||
let msg = e.msg
|
|
||||||
|
|
||||||
const floorName = {
|
|
||||||
12: '十二层',
|
|
||||||
11: '十一层',
|
|
||||||
10: '十层',
|
|
||||||
9: '九层'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 匹配深渊楼层信息
|
|
||||||
lodash.forEach(floorName, (cn, num) => {
|
|
||||||
let reg = new RegExp(`${cn}|${num}`)
|
|
||||||
if (reg.test(msg)) {
|
|
||||||
chooseFloor = num
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let data = abyssData.data
|
|
||||||
data = lodash.sortBy(data, 'floor')
|
|
||||||
data = data.reverse()
|
|
||||||
|
|
||||||
lodash.forEach(data, (floorData) => {
|
|
||||||
let avatars = []
|
|
||||||
lodash.forEach(floorData.avatarUsage, (ds) => {
|
|
||||||
let char = Character.get(ds.id)
|
|
||||||
if (char) {
|
|
||||||
avatars.push({
|
|
||||||
name: char.name,
|
|
||||||
star: char.star,
|
|
||||||
value: ds.value * modeMulti,
|
|
||||||
face: char.face
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
avatars = lodash.sortBy(avatars, 'value', ['asc'])
|
|
||||||
avatars.reverse()
|
|
||||||
if (chooseFloor === -1) {
|
|
||||||
avatars = avatars.slice(0, 14)
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.push({
|
|
||||||
floor: floorData.floor,
|
|
||||||
avatars
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return await Common.render('stat/abyss-pct', {
|
|
||||||
abyss: ret,
|
|
||||||
floorName,
|
|
||||||
chooseFloor,
|
|
||||||
mode,
|
|
||||||
modeName,
|
|
||||||
totalCount: overview?.data?.collectedPlayerCount || 0,
|
|
||||||
lastUpdate: abyssData.lastUpdate
|
|
||||||
}, { e, scale: 1.5 })
|
|
||||||
}
|
|
||||||
|
|
||||||
async function abyssTeam (e) {
|
|
||||||
let mys = await MysApi.init(e, 'cookie')
|
|
||||||
if (!mys || !mys.uid || !mys.isSelfCookie) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
let player = Player.create(e)
|
|
||||||
await player.refreshMysDetail()
|
|
||||||
await player.refreshTalent()
|
|
||||||
|
|
||||||
let abyssData = await HutaoApi.getAbyssTeam()
|
|
||||||
if (!abyssData || !abyssData.data) {
|
|
||||||
e.reply('深渊组队数据获取失败,请稍后重试~')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
abyssData = abyssData.data
|
|
||||||
let avatarData = player.getAvatarData()
|
|
||||||
let avatarRet = {}
|
|
||||||
let data = {}
|
|
||||||
let noAvatar = {}
|
|
||||||
lodash.forEach(avatarData, (avatar) => {
|
|
||||||
let t = avatar.originalTalent
|
|
||||||
avatarRet[avatar.id] = Math.min(avatar.level, avatar.weapon?.level || 1) * 100 + Math.max(t?.a, t?.e, t?.q) * 1000
|
|
||||||
})
|
|
||||||
|
|
||||||
let getTeamCfg = (str) => {
|
|
||||||
let teams = str.split(',')
|
|
||||||
teams.sort()
|
|
||||||
let teamMark = 0
|
|
||||||
lodash.forEach(teams, (a) => {
|
|
||||||
if (!avatarRet[a]) {
|
|
||||||
teamMark = -1
|
|
||||||
noAvatar[a] = true
|
|
||||||
}
|
|
||||||
if (teamMark !== -1) {
|
|
||||||
teamMark += avatarRet[a] * 1
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (teamMark === -1) {
|
|
||||||
teamMark = 1
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
key: teams.join(','),
|
|
||||||
mark: teamMark
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let hasSame = function (team1, team2) {
|
|
||||||
for (let idx = 0; idx < team1.length; idx++) {
|
|
||||||
if (team2.includes(team1[idx])) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
lodash.forEach(abyssData, (ds) => {
|
|
||||||
let floor = ds.floor
|
|
||||||
if (!data[floor]) {
|
|
||||||
data[floor] = {
|
|
||||||
up: {},
|
|
||||||
down: {},
|
|
||||||
teams: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lodash.forEach(['up', 'down'], (halfKey) => {
|
|
||||||
lodash.forEach(ds[halfKey], (ds) => {
|
|
||||||
let teamCfg = getTeamCfg(ds.item)
|
|
||||||
if (teamCfg) {
|
|
||||||
if (!data[floor][halfKey][teamCfg.key]) {
|
|
||||||
data[floor][halfKey][teamCfg.key] = {
|
|
||||||
count: 0,
|
|
||||||
mark: 0,
|
|
||||||
hasTeam: teamCfg.mark > 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data[floor][halfKey][teamCfg.key].count += ds.rate
|
|
||||||
data[floor][halfKey][teamCfg.key].mark += ds.rate * teamCfg.mark
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
let temp = []
|
|
||||||
lodash.forEach(['up', 'down'], (halfKey) => {
|
|
||||||
lodash.forEach(data[floor][halfKey], (ds, team) => {
|
|
||||||
temp.push({
|
|
||||||
team,
|
|
||||||
teamArr: team.split(','),
|
|
||||||
half: halfKey,
|
|
||||||
count: ds.count,
|
|
||||||
mark: ds.mark,
|
|
||||||
mark2: 1,
|
|
||||||
hasTeam: ds.hasTeam
|
|
||||||
})
|
|
||||||
})
|
|
||||||
temp = lodash.sortBy(temp, 'mark')
|
|
||||||
data[floor].teams = temp.reverse()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
let ret = {}
|
|
||||||
|
|
||||||
lodash.forEach(data, (floorData, floor) => {
|
|
||||||
ret[floor] = {}
|
|
||||||
let ds = ret[floor]
|
|
||||||
lodash.forEach(floorData.teams, (t1) => {
|
|
||||||
if (t1.mark2 <= 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
lodash.forEach(floorData.teams, (t2) => {
|
|
||||||
if (t1.mark2 <= 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (t1.half === t2.half || t2.mark2 <= 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
let teamKey = t1.half === 'up' ? (t1.team + '+' + t2.team) : (t2.team + '+' + t1.team)
|
|
||||||
if (ds[teamKey]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (hasSame(t1.teamArr, t2.teamArr)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
ds[teamKey] = {
|
|
||||||
up: t1.half === 'up' ? t1 : t2,
|
|
||||||
down: t1.half === 'up' ? t2 : t1,
|
|
||||||
count: Math.min(t1.count, t2.count),
|
|
||||||
mark: t1.hasTeam && t2.hasTeam ? t1.mark + t2.mark : t1.count + t2.count // 如果不存在组队则进行评分惩罚
|
|
||||||
}
|
|
||||||
t1.mark2--
|
|
||||||
t2.mark2--
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
if (lodash.keys(ds).length >= 20) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
lodash.forEach(ret, (ds, floor) => {
|
|
||||||
ds = lodash.sortBy(lodash.values(ds), 'mark')
|
|
||||||
ds = ds.reverse()
|
|
||||||
ds = ds.slice(0, 4)
|
|
||||||
|
|
||||||
lodash.forEach(ds, (team) => {
|
|
||||||
team.up.teamArr = Character.sortIds(team.up.teamArr)
|
|
||||||
team.down.teamArr = Character.sortIds(team.down.teamArr)
|
|
||||||
})
|
|
||||||
|
|
||||||
ret[floor] = ds
|
|
||||||
})
|
|
||||||
|
|
||||||
let avatarMap = {}
|
|
||||||
|
|
||||||
lodash.forEach(avatarData, (ds) => {
|
|
||||||
let char = Character.get(ds.id)
|
|
||||||
avatarMap[ds.id] = {
|
|
||||||
id: ds.id,
|
|
||||||
name: ds.name,
|
|
||||||
star: ds.star,
|
|
||||||
level: ds.level,
|
|
||||||
cons: ds.cons,
|
|
||||||
face: char.face
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
lodash.forEach(noAvatar, (d, id) => {
|
|
||||||
let char = Character.get(id)
|
|
||||||
avatarMap[id] = {
|
|
||||||
id,
|
|
||||||
name: char.name,
|
|
||||||
face: char.face,
|
|
||||||
star: char.star,
|
|
||||||
level: 0,
|
|
||||||
cons: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return await Common.render('stat/abyss-team', {
|
|
||||||
teams: ret,
|
|
||||||
avatars: avatarMap
|
|
||||||
}, { e, scale: 1.5 })
|
|
||||||
}
|
|
||||||
|
|
||||||
async function uploadData (e) {
|
|
||||||
let isMatch = /^#(喵喵|上传)深渊(数据)?$/.test(e.original_msg || e.msg || '')
|
|
||||||
if (!Cfg.get('uploadAbyssData', false) && !isMatch) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let mys = await MysApi.init(e, 'all')
|
|
||||||
if (!mys || !mys.uid) {
|
|
||||||
if (isMatch) {
|
|
||||||
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let ret = {}
|
|
||||||
let uid = mys.uid
|
|
||||||
let player = Player.create(e)
|
|
||||||
let resDetail, resAbyss
|
|
||||||
try {
|
|
||||||
resAbyss = await mys.getSpiralAbyss(1)
|
|
||||||
let lvs = Data.getVal(resAbyss, 'floors.0.levels.0')
|
|
||||||
// 检查是否查询到了深渊信息
|
|
||||||
if (!lvs || !lvs.battles) {
|
|
||||||
e.reply('暂未获得本期深渊挑战数据...')
|
|
||||||
return true
|
|
||||||
} else if (lvs && lvs.battles && lvs.battles.length === 0) {
|
|
||||||
if (!mys.isSelfCookie) {
|
|
||||||
if (isMatch) {
|
|
||||||
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resDetail = await mys.getCharacter()
|
|
||||||
if (!resDetail || !resAbyss || !resDetail.avatars || resDetail.avatars.length <= 3) {
|
|
||||||
e.reply('角色信息获取失败')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
delete resDetail._res
|
|
||||||
delete resAbyss._res
|
|
||||||
ret = await HutaoApi.uploadData({
|
|
||||||
uid,
|
|
||||||
resDetail,
|
|
||||||
resAbyss
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(err);
|
|
||||||
}
|
|
||||||
// 更新player信息
|
|
||||||
player.setMysCharData(resDetail)
|
|
||||||
|
|
||||||
if (ret && ret.retcode === 0) {
|
|
||||||
let stat = []
|
|
||||||
if (ret.data) {
|
|
||||||
if (resAbyss.floors.length === 0) {
|
|
||||||
e.reply('暂未获得本期深渊挑战数据...')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
let abyss = new Abyss(resAbyss)
|
|
||||||
let abyssData = abyss.getData()
|
|
||||||
let avatarIds = abyss.getAvatars()
|
|
||||||
let overview = ret.info || (await HutaoApi.getOverview())?.data || {}
|
|
||||||
let addMsg = function (title, ds) {
|
|
||||||
let tmp = {}
|
|
||||||
if (!ds) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!ds.avatarId && !ds.id) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let char = Character.get(ds.avatarId || ds.id)
|
|
||||||
tmp.title = title
|
|
||||||
tmp.id = char.id
|
|
||||||
tmp.value = `${(ds.value / 10000).toFixed(1)} W`
|
|
||||||
let msg = []
|
|
||||||
tmp.msg = msg
|
|
||||||
let pct = (percent, name) => {
|
|
||||||
if (percent < 0.2) {
|
|
||||||
msg.push({
|
|
||||||
title: '少于',
|
|
||||||
value: (Math.max(0.1, 100 - percent * 100)).toFixed(1),
|
|
||||||
name: name
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
msg.push({
|
|
||||||
title: '超过',
|
|
||||||
value: (Math.min(99.9, percent * 100)).toFixed(1),
|
|
||||||
name: name
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ds.percent) {
|
|
||||||
pct(ds.percent, char.sName)
|
|
||||||
pct(ds.percentTotal, '总记录')
|
|
||||||
} else {
|
|
||||||
msg.push({
|
|
||||||
txt: '暂无统计信息'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
stat.push(tmp)
|
|
||||||
}
|
|
||||||
addMsg('最强一击', ret.data?.damage || abyssData?.stat?.dmg || {})
|
|
||||||
addMsg('最高承伤', ret.data?.takeDamage || abyssData?.stat.takeDmg || {})
|
|
||||||
let abyssStat = abyssData?.stat || {}
|
|
||||||
lodash.forEach({ defeat: '最多击破', e: '元素战技', q: '元素爆发' }, (title, key) => {
|
|
||||||
if (abyssStat[key]) {
|
|
||||||
stat.push({
|
|
||||||
title,
|
|
||||||
id: abyssStat[key]?.id || 0,
|
|
||||||
value: `${abyssStat[key]?.value}次`
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
stat.push({})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await player.refreshTalent(avatarIds)
|
|
||||||
let avatarData = player.getAvatarData(avatarIds)
|
|
||||||
return await Common.render('stat/abyss-summary', {
|
|
||||||
abyss: abyssData,
|
|
||||||
avatars: avatarData,
|
|
||||||
stat,
|
|
||||||
save_id: uid,
|
|
||||||
totalCount: overview?.collectedPlayerCount || 0,
|
|
||||||
uid
|
|
||||||
}, { e, scale: 1.2 })
|
|
||||||
} else {
|
|
||||||
e.reply('暂未获得本期深渊挑战数据...')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
e.reply(`${ret.message || '上传失败'},请稍后重试...`)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
164
apps/stat/AbyssStat.js
Normal file
164
apps/stat/AbyssStat.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import HutaoApi from './HutaoApi.js'
|
||||||
|
import lodash from 'lodash'
|
||||||
|
import { Character } from '../../models/index.js'
|
||||||
|
import { Common } from '../../components/index.js'
|
||||||
|
|
||||||
|
export async function ConsStat (e) {
|
||||||
|
let consData = await HutaoApi.getCons()
|
||||||
|
let overview = await HutaoApi.getOverview()
|
||||||
|
|
||||||
|
if (!consData) {
|
||||||
|
e.reply('角色持有数据获取失败,请稍后重试~')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg = e.msg
|
||||||
|
|
||||||
|
let mode = /持有/.test(msg) ? 'char' : 'cons'
|
||||||
|
|
||||||
|
let conNum = -1
|
||||||
|
if (mode === 'cons') {
|
||||||
|
lodash.forEach([/0|零/, /1|一/, /2|二/, /3|三/, /4|四/, /5|五/, /6|六|满/], (reg, idx) => {
|
||||||
|
if (reg.test(msg)) {
|
||||||
|
conNum = idx
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!consData && !consData.data) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = consData.data
|
||||||
|
|
||||||
|
let Lumine = lodash.filter(data, (ds) => ds.avatar === 10000007)[0] || {}
|
||||||
|
let Aether = lodash.filter(data, (ds) => ds.avatar === 10000005)[0] || {}
|
||||||
|
|
||||||
|
Lumine.holdingRate = (1 - Aether.holdingRate) || Lumine.holdingRate
|
||||||
|
|
||||||
|
let ret = []
|
||||||
|
|
||||||
|
lodash.forEach(data, (ds) => {
|
||||||
|
let char = Character.get(ds.avatar)
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
name: char.name || ds.avatar,
|
||||||
|
abbr: char.abbr,
|
||||||
|
star: char.star || 3,
|
||||||
|
side: char.side,
|
||||||
|
hold: ds.holdingRate
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === 'char') {
|
||||||
|
data.cons = lodash.map(ds.rate, (c) => {
|
||||||
|
c.value = c.value * ds.holdingRate
|
||||||
|
return c
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
data.cons = ds.rate
|
||||||
|
}
|
||||||
|
data.cons = lodash.sortBy(data.cons, ['id'])
|
||||||
|
|
||||||
|
ret.push(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (conNum > -1) {
|
||||||
|
ret = lodash.sortBy(ret, [`cons[${conNum}].value`])
|
||||||
|
ret.reverse()
|
||||||
|
} else {
|
||||||
|
ret = lodash.sortBy(ret, ['hold'])
|
||||||
|
}
|
||||||
|
// 渲染图像
|
||||||
|
return await Common.render('stat/character', {
|
||||||
|
chars: ret,
|
||||||
|
mode,
|
||||||
|
conNum,
|
||||||
|
totalCount: overview?.data?.totalPlayerCount || 0,
|
||||||
|
lastUpdate: consData.lastUpdate,
|
||||||
|
pct: function (num) {
|
||||||
|
return (num * 100).toFixed(2)
|
||||||
|
}
|
||||||
|
}, { e, scale: 1.5 })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function AbyssPct (e) {
|
||||||
|
let mode = /使用/.test(e.msg) ? 'use' : 'pct'
|
||||||
|
let modeName
|
||||||
|
let abyssData
|
||||||
|
let modeMulti = 1
|
||||||
|
|
||||||
|
if (mode === 'use') {
|
||||||
|
modeName = '使用率'
|
||||||
|
abyssData = await HutaoApi.getAbyssUse()
|
||||||
|
} else {
|
||||||
|
modeName = '出场率'
|
||||||
|
abyssData = await HutaoApi.getAbyssPct()
|
||||||
|
modeMulti = 8
|
||||||
|
}
|
||||||
|
let overview = await HutaoApi.getOverview()
|
||||||
|
|
||||||
|
if (!abyssData) {
|
||||||
|
e.reply(`深渊${modeName}数据获取失败,请稍后重试~`)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = []
|
||||||
|
let chooseFloor = -1
|
||||||
|
let msg = e.msg
|
||||||
|
|
||||||
|
const floorName = {
|
||||||
|
12: '十二层',
|
||||||
|
11: '十一层',
|
||||||
|
10: '十层',
|
||||||
|
9: '九层'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配深渊楼层信息
|
||||||
|
lodash.forEach(floorName, (cn, num) => {
|
||||||
|
let reg = new RegExp(`${cn}|${num}`)
|
||||||
|
if (reg.test(msg)) {
|
||||||
|
chooseFloor = num
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let data = abyssData.data
|
||||||
|
data = lodash.sortBy(data, 'floor')
|
||||||
|
data = data.reverse()
|
||||||
|
|
||||||
|
lodash.forEach(data, (floorData) => {
|
||||||
|
let avatars = []
|
||||||
|
lodash.forEach(floorData.avatarUsage, (ds) => {
|
||||||
|
let char = Character.get(ds.id)
|
||||||
|
if (char) {
|
||||||
|
avatars.push({
|
||||||
|
name: char.name,
|
||||||
|
star: char.star,
|
||||||
|
value: ds.value * modeMulti,
|
||||||
|
face: char.face
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
avatars = lodash.sortBy(avatars, 'value', ['asc'])
|
||||||
|
avatars.reverse()
|
||||||
|
if (chooseFloor === -1) {
|
||||||
|
avatars = avatars.slice(0, 14)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.push({
|
||||||
|
floor: floorData.floor,
|
||||||
|
avatars
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return await Common.render('stat/abyss-pct', {
|
||||||
|
abyss: ret,
|
||||||
|
floorName,
|
||||||
|
chooseFloor,
|
||||||
|
mode,
|
||||||
|
modeName,
|
||||||
|
totalCount: overview?.data?.collectedPlayerCount || 0,
|
||||||
|
lastUpdate: abyssData.lastUpdate
|
||||||
|
}, { e, scale: 1.5 })
|
||||||
|
}
|
137
apps/stat/AbyssSummary.js
Normal file
137
apps/stat/AbyssSummary.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import { Cfg, Common, Data } from '../../components/index.js'
|
||||||
|
import { Abyss, Character, MysApi, Player } from '../../models/index.js'
|
||||||
|
import HutaoApi from './HutaoApi.js'
|
||||||
|
import lodash from 'lodash'
|
||||||
|
|
||||||
|
export async function AbyssSummary (e) {
|
||||||
|
let isMatch = /^#(喵喵|上传)深渊(数据)?$/.test(e.original_msg || e.msg || '')
|
||||||
|
if (!Cfg.get('uploadAbyssData', false) && !isMatch) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let mys = await MysApi.init(e, 'all')
|
||||||
|
if (!mys || !mys.uid) {
|
||||||
|
if (isMatch) {
|
||||||
|
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let ret = {}
|
||||||
|
let uid = mys.uid
|
||||||
|
let player = Player.create(e)
|
||||||
|
let resDetail, resAbyss
|
||||||
|
try {
|
||||||
|
resAbyss = await mys.getSpiralAbyss(1)
|
||||||
|
let lvs = Data.getVal(resAbyss, 'floors.0.levels.0')
|
||||||
|
// 检查是否查询到了深渊信息
|
||||||
|
if (!lvs || !lvs.battles) {
|
||||||
|
e.reply('暂未获得本期深渊挑战数据...')
|
||||||
|
return true
|
||||||
|
} else if (lvs && lvs.battles && lvs.battles.length === 0) {
|
||||||
|
if (!mys.isSelfCookie) {
|
||||||
|
if (isMatch) {
|
||||||
|
e.reply(`请绑定ck后再使用${e.original_msg || e.msg}`)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resDetail = await mys.getCharacter()
|
||||||
|
if (!resDetail || !resAbyss || !resDetail.avatars || resDetail.avatars.length <= 3) {
|
||||||
|
e.reply('角色信息获取失败')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
delete resDetail._res
|
||||||
|
delete resAbyss._res
|
||||||
|
ret = await HutaoApi.uploadData({
|
||||||
|
uid,
|
||||||
|
resDetail,
|
||||||
|
resAbyss
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(err);
|
||||||
|
}
|
||||||
|
// 更新player信息
|
||||||
|
player.setMysCharData(resDetail)
|
||||||
|
|
||||||
|
if (ret && ret.retcode === 0) {
|
||||||
|
let stat = []
|
||||||
|
if (ret.data) {
|
||||||
|
if (resAbyss.floors.length === 0) {
|
||||||
|
e.reply('暂未获得本期深渊挑战数据...')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
let abyss = new Abyss(resAbyss)
|
||||||
|
let abyssData = abyss.getData()
|
||||||
|
let avatarIds = abyss.getAvatars()
|
||||||
|
let overview = ret.info || (await HutaoApi.getOverview())?.data || {}
|
||||||
|
let addMsg = function (title, ds) {
|
||||||
|
let tmp = {}
|
||||||
|
if (!ds) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!ds.avatarId && !ds.id) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let char = Character.get(ds.avatarId || ds.id)
|
||||||
|
tmp.title = title
|
||||||
|
tmp.id = char.id
|
||||||
|
tmp.value = `${(ds.value / 10000).toFixed(1)} W`
|
||||||
|
let msg = []
|
||||||
|
tmp.msg = msg
|
||||||
|
let pct = (percent, name) => {
|
||||||
|
if (percent < 0.2) {
|
||||||
|
msg.push({
|
||||||
|
title: '少于',
|
||||||
|
value: (Math.max(0.1, 100 - percent * 100)).toFixed(1),
|
||||||
|
name: name
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
msg.push({
|
||||||
|
title: '超过',
|
||||||
|
value: (Math.min(99.9, percent * 100)).toFixed(1),
|
||||||
|
name: name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ds.percent) {
|
||||||
|
pct(ds.percent, char.abbr)
|
||||||
|
pct(ds.percentTotal, '总记录')
|
||||||
|
} else {
|
||||||
|
msg.push({
|
||||||
|
txt: '暂无统计信息'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
stat.push(tmp)
|
||||||
|
}
|
||||||
|
addMsg('最强一击', ret.data?.damage || abyssData?.stat?.dmg || {})
|
||||||
|
addMsg('最高承伤', ret.data?.takeDamage || abyssData?.stat.takeDmg || {})
|
||||||
|
let abyssStat = abyssData?.stat || {}
|
||||||
|
lodash.forEach({ defeat: '最多击破', e: '元素战技', q: '元素爆发' }, (title, key) => {
|
||||||
|
if (abyssStat[key]) {
|
||||||
|
stat.push({
|
||||||
|
title,
|
||||||
|
id: abyssStat[key]?.id || 0,
|
||||||
|
value: `${abyssStat[key]?.value}次`
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
stat.push({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await player.refreshTalent(avatarIds)
|
||||||
|
let avatarData = player.getAvatarData(avatarIds)
|
||||||
|
return await Common.render('stat/abyss-summary', {
|
||||||
|
abyss: abyssData,
|
||||||
|
avatars: avatarData,
|
||||||
|
stat,
|
||||||
|
save_id: uid,
|
||||||
|
totalCount: overview?.collectedPlayerCount || 0,
|
||||||
|
uid
|
||||||
|
}, { e, scale: 1.2 })
|
||||||
|
} else {
|
||||||
|
e.reply('暂未获得本期深渊挑战数据...')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e.reply(`${ret.message || '上传失败'},请稍后重试...`)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
189
apps/stat/AbyssTeam.js
Normal file
189
apps/stat/AbyssTeam.js
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import { Character, MysApi, Player } from '../../models/index.js'
|
||||||
|
import HutaoApi from './HutaoApi.js'
|
||||||
|
import lodash from 'lodash'
|
||||||
|
import { Common } from '../../components/index.js'
|
||||||
|
|
||||||
|
export async function AbyssTeam (e) {
|
||||||
|
let mys = await MysApi.init(e, 'cookie')
|
||||||
|
if (!mys || !mys.uid || !mys.isSelfCookie) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
let player = Player.create(e)
|
||||||
|
await player.refreshMysDetail()
|
||||||
|
await player.refreshTalent()
|
||||||
|
|
||||||
|
let abyssData = await HutaoApi.getAbyssTeam()
|
||||||
|
if (!abyssData || !abyssData.data) {
|
||||||
|
e.reply('深渊组队数据获取失败,请稍后重试~')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
abyssData = abyssData.data
|
||||||
|
let avatarData = player.getAvatarData()
|
||||||
|
let avatarRet = {}
|
||||||
|
let data = {}
|
||||||
|
let noAvatar = {}
|
||||||
|
lodash.forEach(avatarData, (avatar) => {
|
||||||
|
let t = avatar.originalTalent
|
||||||
|
avatarRet[avatar.id] = Math.min(avatar.level, avatar.weapon?.level || 1) * 100 + Math.max(t?.a, t?.e, t?.q) * 1000
|
||||||
|
})
|
||||||
|
|
||||||
|
let getTeamCfg = (str) => {
|
||||||
|
let teams = str.split(',')
|
||||||
|
teams.sort()
|
||||||
|
let teamMark = 0
|
||||||
|
lodash.forEach(teams, (a) => {
|
||||||
|
if (!avatarRet[a]) {
|
||||||
|
teamMark = -1
|
||||||
|
noAvatar[a] = true
|
||||||
|
}
|
||||||
|
if (teamMark !== -1) {
|
||||||
|
teamMark += avatarRet[a] * 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (teamMark === -1) {
|
||||||
|
teamMark = 1
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
key: teams.join(','),
|
||||||
|
mark: teamMark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasSame = function (team1, team2) {
|
||||||
|
for (let idx = 0; idx < team1.length; idx++) {
|
||||||
|
if (team2.includes(team1[idx])) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
lodash.forEach(abyssData, (ds) => {
|
||||||
|
let floor = ds.floor
|
||||||
|
if (!data[floor]) {
|
||||||
|
data[floor] = {
|
||||||
|
up: {},
|
||||||
|
down: {},
|
||||||
|
teams: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lodash.forEach(['up', 'down'], (halfKey) => {
|
||||||
|
lodash.forEach(ds[halfKey], (ds) => {
|
||||||
|
let teamCfg = getTeamCfg(ds.item)
|
||||||
|
if (teamCfg) {
|
||||||
|
if (!data[floor][halfKey][teamCfg.key]) {
|
||||||
|
data[floor][halfKey][teamCfg.key] = {
|
||||||
|
count: 0,
|
||||||
|
mark: 0,
|
||||||
|
hasTeam: teamCfg.mark > 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data[floor][halfKey][teamCfg.key].count += ds.rate
|
||||||
|
data[floor][halfKey][teamCfg.key].mark += ds.rate * teamCfg.mark
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let temp = []
|
||||||
|
lodash.forEach(['up', 'down'], (halfKey) => {
|
||||||
|
lodash.forEach(data[floor][halfKey], (ds, team) => {
|
||||||
|
temp.push({
|
||||||
|
team,
|
||||||
|
teamArr: team.split(','),
|
||||||
|
half: halfKey,
|
||||||
|
count: ds.count,
|
||||||
|
mark: ds.mark,
|
||||||
|
mark2: 1,
|
||||||
|
hasTeam: ds.hasTeam
|
||||||
|
})
|
||||||
|
})
|
||||||
|
temp = lodash.sortBy(temp, 'mark')
|
||||||
|
data[floor].teams = temp.reverse()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let ret = {}
|
||||||
|
|
||||||
|
lodash.forEach(data, (floorData, floor) => {
|
||||||
|
ret[floor] = {}
|
||||||
|
let ds = ret[floor]
|
||||||
|
lodash.forEach(floorData.teams, (t1) => {
|
||||||
|
if (t1.mark2 <= 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
lodash.forEach(floorData.teams, (t2) => {
|
||||||
|
if (t1.mark2 <= 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (t1.half === t2.half || t2.mark2 <= 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
let teamKey = t1.half === 'up' ? (t1.team + '+' + t2.team) : (t2.team + '+' + t1.team)
|
||||||
|
if (ds[teamKey]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (hasSame(t1.teamArr, t2.teamArr)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
ds[teamKey] = {
|
||||||
|
up: t1.half === 'up' ? t1 : t2,
|
||||||
|
down: t1.half === 'up' ? t2 : t1,
|
||||||
|
count: Math.min(t1.count, t2.count),
|
||||||
|
mark: t1.hasTeam && t2.hasTeam ? t1.mark + t2.mark : t1.count + t2.count // 如果不存在组队则进行评分惩罚
|
||||||
|
}
|
||||||
|
t1.mark2--
|
||||||
|
t2.mark2--
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if (lodash.keys(ds).length >= 20) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
lodash.forEach(ret, (ds, floor) => {
|
||||||
|
ds = lodash.sortBy(lodash.values(ds), 'mark')
|
||||||
|
ds = ds.reverse()
|
||||||
|
ds = ds.slice(0, 4)
|
||||||
|
|
||||||
|
lodash.forEach(ds, (team) => {
|
||||||
|
team.up.teamArr = Character.sortIds(team.up.teamArr)
|
||||||
|
team.down.teamArr = Character.sortIds(team.down.teamArr)
|
||||||
|
})
|
||||||
|
|
||||||
|
ret[floor] = ds
|
||||||
|
})
|
||||||
|
|
||||||
|
let avatarMap = {}
|
||||||
|
|
||||||
|
lodash.forEach(avatarData, (ds) => {
|
||||||
|
let char = Character.get(ds.id)
|
||||||
|
avatarMap[ds.id] = {
|
||||||
|
id: ds.id,
|
||||||
|
name: ds.name,
|
||||||
|
star: ds.star,
|
||||||
|
level: ds.level,
|
||||||
|
cons: ds.cons,
|
||||||
|
face: char.face
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
lodash.forEach(noAvatar, (d, id) => {
|
||||||
|
let char = Character.get(id)
|
||||||
|
avatarMap[id] = {
|
||||||
|
id,
|
||||||
|
name: char.name,
|
||||||
|
face: char.face,
|
||||||
|
star: char.star,
|
||||||
|
level: 0,
|
||||||
|
cons: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return await Common.render('stat/abyss-team', {
|
||||||
|
teams: ret,
|
||||||
|
avatars: avatarMap
|
||||||
|
}, { e, scale: 1.5 })
|
||||||
|
}
|
186
apps/wiki.js
186
apps/wiki.js
@ -1,183 +1,23 @@
|
|||||||
import { segment } from 'oicq'
|
import { App } from '../components/index.js'
|
||||||
import lodash from 'lodash'
|
|
||||||
import Calendar from './wiki/Calendar.js'
|
import Calendar from './wiki/Calendar.js'
|
||||||
import { Format, Cfg, Common, App } from '../components/index.js'
|
|
||||||
import { Character } from '../models/index.js'
|
|
||||||
import CharWiki from './wiki/CharWiki.js'
|
import CharWiki from './wiki/CharWiki.js'
|
||||||
|
|
||||||
let wikiReg = /^(?:#|喵喵)?(.*)(天赋|技能|命座|命之座|资料|图鉴|照片|写真|图片|图像)$/
|
|
||||||
|
|
||||||
let app = App.init({
|
let app = App.init({
|
||||||
id: 'wiki',
|
id: 'wiki',
|
||||||
name: '角色资料'
|
name: '角色资料'
|
||||||
})
|
})
|
||||||
app.reg('wiki', wiki, {
|
app.reg({
|
||||||
rule: '^#喵喵WIKI$',
|
wiki: {
|
||||||
check: checkCharacter,
|
rule: '^#喵喵WIKI$',
|
||||||
desc: '【#资料】 #神里天赋 #夜兰命座'
|
check: CharWiki.check,
|
||||||
})
|
fn: CharWiki.wiki,
|
||||||
app.reg('calendar', calendar, {
|
desc: '【#资料】 #神里天赋 #夜兰命座'
|
||||||
rule: /^(#|喵喵)+(日历|日历列表)$/,
|
},
|
||||||
desc: '【#日历】 活动日历'
|
calendar: {
|
||||||
|
rule: /^(#|喵喵)+(日历|日历列表)$/,
|
||||||
|
fn: Calendar.render,
|
||||||
|
desc: '【#日历】 活动日历'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
|
||||||
function checkCharacter (e) {
|
|
||||||
let msg = e.original_msg || e.msg
|
|
||||||
if (!e.msg) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let ret = wikiReg.exec(msg)
|
|
||||||
if (!ret || !ret[1] || !ret[2]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let mode = 'talent'
|
|
||||||
if (/命/.test(ret[2])) {
|
|
||||||
mode = 'cons'
|
|
||||||
} else if (/(图鉴|资料)/.test(ret[2])) {
|
|
||||||
mode = 'wiki'
|
|
||||||
if (!Common.cfg('charWiki')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else if (/图|画|写真|照片/.test(ret[2])) {
|
|
||||||
mode = 'pic'
|
|
||||||
if (!Common.cfg('charPic')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else if (/(材料|养成|成长)/.test(ret[2])) {
|
|
||||||
mode = 'material'
|
|
||||||
}
|
|
||||||
if (['cons', 'talent'].includes(mode) && !Common.cfg('charWikiTalent')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let char = Character.get(ret[1])
|
|
||||||
if (!char) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
e.wikiMode = mode
|
|
||||||
e.msg = '#喵喵WIKI'
|
|
||||||
e.char = char
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wiki (e) {
|
|
||||||
let mode = e.wikiMode
|
|
||||||
let char = e.char
|
|
||||||
|
|
||||||
if (mode === 'pic') {
|
|
||||||
let img = char.getCardImg(Cfg.get('charPicSe', false), false)
|
|
||||||
if (img && img.img) {
|
|
||||||
e.reply(segment.image(process.cwd() + '/plugins/miao-plugin/resources/' + img.img))
|
|
||||||
} else {
|
|
||||||
e.reply('暂无图片')
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (char.isCustom) {
|
|
||||||
if (mode === 'wiki') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
e.reply('暂不支持自定义角色')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (!char.isRelease && Cfg.get('notReleasedData') === false) {
|
|
||||||
e.reply('未实装角色资料已禁用...')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
let lvs = []
|
|
||||||
for (let i = 1; i <= 15; i++) {
|
|
||||||
lvs.push('Lv' + i)
|
|
||||||
}
|
|
||||||
if (mode === 'wiki') {
|
|
||||||
if (char.source === 'amber') {
|
|
||||||
e.reply('暂不支持该角色图鉴展示')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return await renderWiki({ e, char })
|
|
||||||
} else if (mode === 'material') {
|
|
||||||
return await renderCharMaterial({ e, char })
|
|
||||||
}
|
|
||||||
return await Common.render('wiki/character-talent', {
|
|
||||||
saveId: `${mode}-${char.id}`,
|
|
||||||
...char.getData(),
|
|
||||||
detail: char.getDetail(),
|
|
||||||
imgs: char.getImgs(),
|
|
||||||
mode,
|
|
||||||
lvs,
|
|
||||||
line: getLineData(char)
|
|
||||||
}, { e, scale: 1.1 })
|
|
||||||
}
|
|
||||||
|
|
||||||
async function renderWiki ({ e, char }) {
|
|
||||||
let data = char.getData()
|
|
||||||
lodash.extend(data, char.getData('weaponTypeName,elemName'))
|
|
||||||
// 命座持有
|
|
||||||
let holding = await CharWiki.getHolding(char.id)
|
|
||||||
let usage = await CharWiki.getUsage(char.id)
|
|
||||||
return await Common.render('wiki/character-wiki', {
|
|
||||||
data,
|
|
||||||
attr: char.getAttrList(),
|
|
||||||
detail: char.getDetail(),
|
|
||||||
imgs: char.getImgs(),
|
|
||||||
holding,
|
|
||||||
usage,
|
|
||||||
materials: char.getMaterials(),
|
|
||||||
elem: char.elem
|
|
||||||
}, { e, scale: 1.4 })
|
|
||||||
}
|
|
||||||
|
|
||||||
async function renderCharMaterial ({ e, char }) {
|
|
||||||
let data = char.getData()
|
|
||||||
return await Common.render('wiki/character-material', {
|
|
||||||
// saveId: `info-${char.id}`,
|
|
||||||
data,
|
|
||||||
attr: char.getAttrList(),
|
|
||||||
detail: char.getDetail(),
|
|
||||||
imgs: char.getImgs(),
|
|
||||||
materials: char.getMaterials(),
|
|
||||||
elem: char.elem
|
|
||||||
}, { e, scale: 1.4 })
|
|
||||||
}
|
|
||||||
|
|
||||||
const getLineData = function (char) {
|
|
||||||
let ret = []
|
|
||||||
const attrMap = {
|
|
||||||
atkPct: '大攻击',
|
|
||||||
hpPct: '大生命',
|
|
||||||
defPct: '大防御',
|
|
||||||
cpct: '暴击',
|
|
||||||
cdmg: '爆伤',
|
|
||||||
recharge: '充能',
|
|
||||||
mastery: '精通',
|
|
||||||
heal: '治疗',
|
|
||||||
dmg: char.elemName + '伤',
|
|
||||||
phy: '物伤'
|
|
||||||
}
|
|
||||||
lodash.forEach({ hp: '基础生命', atk: '基础攻击', def: '基础防御' }, (label, key) => {
|
|
||||||
ret.push({
|
|
||||||
num: Format.comma(char.baseAttr[key], 1),
|
|
||||||
label
|
|
||||||
})
|
|
||||||
})
|
|
||||||
let ga = char.growAttr
|
|
||||||
ret.push({
|
|
||||||
num: ga.key === 'mastery' ? Format.comma(ga.value, 1) : ga.value,
|
|
||||||
label: `成长·${attrMap[ga.key]}`
|
|
||||||
})
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
async function calendar (e) {
|
|
||||||
let calData = await Calendar.get()
|
|
||||||
let mode = 'calendar'
|
|
||||||
if (/(日历列表|活动)$/.test(e.msg)) {
|
|
||||||
mode = 'list'
|
|
||||||
}
|
|
||||||
|
|
||||||
return await Common.render('wiki/calendar', {
|
|
||||||
...calData,
|
|
||||||
displayMode: mode
|
|
||||||
}, { e, scale: 1.1 })
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { Character, Material } from '../../models/index.js'
|
import { Character, Material } from '../../models/index.js'
|
||||||
import { Data } from '../../components/index.js'
|
import { Common, Data } from '../../components/index.js'
|
||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
|
|
||||||
const ignoreIds = [495, // 有奖问卷调查开启!
|
const ignoreIds = [495, // 有奖问卷调查开启!
|
||||||
@ -397,6 +397,19 @@ let Cal = {
|
|||||||
nowTime: now.format('YYYY-MM-DD HH:mm'),
|
nowTime: now.format('YYYY-MM-DD HH:mm'),
|
||||||
nowDate: now.date()
|
nowDate: now.date()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async render (e) {
|
||||||
|
let calData = await Cal.get()
|
||||||
|
let mode = 'calendar'
|
||||||
|
if (/(日历列表|活动)$/.test(e.msg)) {
|
||||||
|
mode = 'list'
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Common.render('wiki/calendar', {
|
||||||
|
...calData,
|
||||||
|
displayMode: mode
|
||||||
|
}, { e, scale: 1.1 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
apps/wiki/CharMaterial.js
Normal file
18
apps/wiki/CharMaterial.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Common } from '../../components/index.js'
|
||||||
|
|
||||||
|
const CharMaterial = {
|
||||||
|
async render ({ e, char }) {
|
||||||
|
let data = char.getData()
|
||||||
|
return await Common.render('wiki/character-material', {
|
||||||
|
// saveId: `info-${char.id}`,
|
||||||
|
data,
|
||||||
|
attr: char.getAttrList(),
|
||||||
|
detail: char.getDetail(),
|
||||||
|
imgs: char.getImgs(),
|
||||||
|
materials: char.getMaterials(),
|
||||||
|
elem: char.elem
|
||||||
|
}, { e, scale: 1.4 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CharMaterial
|
49
apps/wiki/CharTalent.js
Normal file
49
apps/wiki/CharTalent.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Common, Format } from '../../components/index.js'
|
||||||
|
import lodash from 'lodash'
|
||||||
|
|
||||||
|
const CharTalent = {
|
||||||
|
async render (e, mode, char) {
|
||||||
|
let lvs = []
|
||||||
|
for (let i = 1; i <= 15; i++) {
|
||||||
|
lvs.push('Lv' + i)
|
||||||
|
}
|
||||||
|
return await Common.render('wiki/character-talent', {
|
||||||
|
saveId: `${mode}-${char.id}`,
|
||||||
|
...char.getData(),
|
||||||
|
detail: char.getDetail(),
|
||||||
|
imgs: char.getImgs(),
|
||||||
|
mode,
|
||||||
|
lvs,
|
||||||
|
line: CharTalent.getLineData(char)
|
||||||
|
}, { e, scale: 1.1 })
|
||||||
|
},
|
||||||
|
getLineData (char) {
|
||||||
|
let ret = []
|
||||||
|
const attrMap = {
|
||||||
|
atkPct: '大攻击',
|
||||||
|
hpPct: '大生命',
|
||||||
|
defPct: '大防御',
|
||||||
|
cpct: '暴击',
|
||||||
|
cdmg: '爆伤',
|
||||||
|
recharge: '充能',
|
||||||
|
mastery: '精通',
|
||||||
|
heal: '治疗',
|
||||||
|
dmg: char.elemName + '伤',
|
||||||
|
phy: '物伤'
|
||||||
|
}
|
||||||
|
lodash.forEach({ hp: '基础生命', atk: '基础攻击', def: '基础防御' }, (label, key) => {
|
||||||
|
ret.push({
|
||||||
|
num: Format.comma(char.baseAttr[key], 1),
|
||||||
|
label
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let ga = char.growAttr
|
||||||
|
ret.push({
|
||||||
|
num: ga.key === 'mastery' ? Format.comma(ga.value, 1) : ga.value,
|
||||||
|
label: `成长·${attrMap[ga.key]}`
|
||||||
|
})
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CharTalent
|
@ -1,108 +1,107 @@
|
|||||||
import HutaoApi from './HutaoApi.js'
|
import { Cfg, Common } from '../../components/index.js'
|
||||||
|
import { Character } from '../../models/index.js'
|
||||||
|
import { segment } from 'oicq'
|
||||||
|
import CharTalent from './CharTalent.js'
|
||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import { Format } from '../../components/index.js'
|
import CharWikiData from './CharWikiData.js'
|
||||||
import { ArtifactSet, Weapon } from '../../models/index.js'
|
import CharMaterial from './CharMaterial.js'
|
||||||
|
|
||||||
let CharWiki = {
|
const wikiReg = /^(?:#|喵喵)?(.*)(天赋|技能|命座|命之座|资料|图鉴|照片|写真|图片|图像)$/
|
||||||
/**
|
|
||||||
* 角色命座持有
|
const CharWiki = {
|
||||||
* @param id
|
check (e) {
|
||||||
* @returns {Promise<{}>}
|
let msg = e.original_msg || e.msg
|
||||||
*/
|
if (!e.msg) {
|
||||||
async getHolding (id) {
|
return false
|
||||||
let consData = (await HutaoApi.getCons()).data || {}
|
|
||||||
consData = lodash.find(consData, (ds) => ds.avatar === id)
|
|
||||||
let holding = {}
|
|
||||||
if (consData) {
|
|
||||||
let { holdingRate, rate } = consData
|
|
||||||
rate = lodash.sortBy(rate, 'id')
|
|
||||||
holding.num = Format.percent(holdingRate)
|
|
||||||
holding.cons = []
|
|
||||||
lodash.forEach(rate, (ds) => {
|
|
||||||
holding.cons.push({
|
|
||||||
cons: ds.id,
|
|
||||||
num: Format.percent(ds.value)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return holding
|
let ret = wikiReg.exec(msg)
|
||||||
|
if (!ret || !ret[1] || !ret[2]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let mode = 'talent'
|
||||||
|
if (/命/.test(ret[2])) {
|
||||||
|
mode = 'cons'
|
||||||
|
} else if (/(图鉴|资料)/.test(ret[2])) {
|
||||||
|
mode = 'wiki'
|
||||||
|
if (!Common.cfg('charWiki')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (/图|画|写真|照片/.test(ret[2])) {
|
||||||
|
mode = 'pic'
|
||||||
|
if (!Common.cfg('charPic')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if (/(材料|养成|成长)/.test(ret[2])) {
|
||||||
|
mode = 'material'
|
||||||
|
}
|
||||||
|
if (['cons', 'talent'].includes(mode) && !Common.cfg('charWikiTalent')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let char = Character.get(ret[1])
|
||||||
|
if (!char) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
e.wikiMode = mode
|
||||||
|
e.msg = '#喵喵WIKI'
|
||||||
|
e.char = char
|
||||||
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
async wiki (e) {
|
||||||
* 角色武器、圣遗物使用
|
let mode = e.wikiMode
|
||||||
* @param id
|
let char = e.char
|
||||||
* @returns {Promise<{}|{artis: *[], weapons: *[]}>}
|
|
||||||
*/
|
if (mode === 'pic') {
|
||||||
async getUsage (id) {
|
let img = char.getCardImg(Cfg.get('charPicSe', false), false)
|
||||||
let ud = (await HutaoApi.getUsage()).data || {}
|
if (img && img.img) {
|
||||||
if (!ud[id]) {
|
e.reply(segment.image(process.cwd() + '/plugins/miao-plugin/resources/' + img.img))
|
||||||
return {}
|
} else {
|
||||||
|
e.reply('暂无图片')
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
ud = ud[id]
|
if (char.isCustom) {
|
||||||
return {
|
if (mode === 'wiki') {
|
||||||
weapons: CharWiki.getWeaponsData(ud.weapons),
|
return false
|
||||||
artis: CharWiki.getArtisData(ud.artis)
|
}
|
||||||
|
e.reply('暂不支持自定义角色')
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
if (!char.isRelease && Cfg.get('notReleasedData') === false) {
|
||||||
|
e.reply('未实装角色资料已禁用...')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === 'wiki') {
|
||||||
|
if (char.source === 'amber') {
|
||||||
|
e.reply('暂不支持该角色图鉴展示')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return await CharWiki.render({ e, char })
|
||||||
|
} else if (mode === 'material') {
|
||||||
|
return CharMaterial.render({ e, char })
|
||||||
|
}
|
||||||
|
return await CharTalent.render(e, mode, char)
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
async render ({ e, char }) {
|
||||||
* 武器使用
|
let data = char.getData()
|
||||||
* @param data
|
lodash.extend(data, char.getData('weaponTypeName,elemName'))
|
||||||
* @returns {*[]}
|
// 命座持有
|
||||||
*/
|
let holding = await CharWikiData.getHolding(char.id)
|
||||||
getWeaponsData (data = []) {
|
let usage = await CharWikiData.getUsage(char.id)
|
||||||
let weapons = []
|
return await Common.render('wiki/character-wiki', {
|
||||||
|
data,
|
||||||
lodash.forEach(data, (ds) => {
|
attr: char.getAttrList(),
|
||||||
let weapon = Weapon.get(ds.item) || {}
|
detail: char.getDetail(),
|
||||||
weapons.push({
|
imgs: char.getImgs(),
|
||||||
...weapon.getData('name,abbr,img,star'),
|
holding,
|
||||||
value: ds.rate
|
usage,
|
||||||
})
|
materials: char.getMaterials(),
|
||||||
})
|
elem: char.elem
|
||||||
|
}, { e, scale: 1.4 })
|
||||||
weapons = lodash.sortBy(weapons, 'value')
|
|
||||||
weapons = weapons.reverse()
|
|
||||||
lodash.forEach(weapons, (ds) => {
|
|
||||||
ds.value = Format.percent(ds.value, 1)
|
|
||||||
})
|
|
||||||
return weapons
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 圣遗物使用
|
|
||||||
* @param data
|
|
||||||
* @returns {*[]}
|
|
||||||
*/
|
|
||||||
getArtisData (data = []) {
|
|
||||||
let artis = []
|
|
||||||
|
|
||||||
lodash.forEach(data, (ds) => {
|
|
||||||
let imgs = []
|
|
||||||
let abbrs = []
|
|
||||||
let ss = ds.item.split(',')
|
|
||||||
lodash.forEach(ss, (t) => {
|
|
||||||
t = t.split(':')
|
|
||||||
let artiSet = ArtifactSet.get(t[0])
|
|
||||||
if (artiSet) {
|
|
||||||
imgs.push(artiSet.img)
|
|
||||||
abbrs.push(artiSet.abbr + (ss.length === 1 ? t[1] : ''))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
artis.push({
|
|
||||||
imgs,
|
|
||||||
title: abbrs.join('+'),
|
|
||||||
value: ds.rate
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
artis = lodash.sortBy(artis, 'value')
|
|
||||||
artis = artis.reverse()
|
|
||||||
artis.forEach((ds) => {
|
|
||||||
ds.value = Format.percent(ds.value)
|
|
||||||
})
|
|
||||||
return artis
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CharWiki
|
export default CharWiki
|
||||||
|
108
apps/wiki/CharWikiData.js
Normal file
108
apps/wiki/CharWikiData.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import HutaoApi from '../stat/HutaoApi.js'
|
||||||
|
import lodash from 'lodash'
|
||||||
|
import { Format } from '../../components/index.js'
|
||||||
|
import { ArtifactSet, Weapon } from '../../models/index.js'
|
||||||
|
|
||||||
|
let CharWikiData = {
|
||||||
|
/**
|
||||||
|
* 角色命座持有
|
||||||
|
* @param id
|
||||||
|
* @returns {Promise<{}>}
|
||||||
|
*/
|
||||||
|
async getHolding (id) {
|
||||||
|
let consData = (await HutaoApi.getCons()).data || {}
|
||||||
|
consData = lodash.find(consData, (ds) => ds.avatar === id)
|
||||||
|
let holding = {}
|
||||||
|
if (consData) {
|
||||||
|
let { holdingRate, rate } = consData
|
||||||
|
rate = lodash.sortBy(rate, 'id')
|
||||||
|
holding.num = Format.percent(holdingRate)
|
||||||
|
holding.cons = []
|
||||||
|
lodash.forEach(rate, (ds) => {
|
||||||
|
holding.cons.push({
|
||||||
|
cons: ds.id,
|
||||||
|
num: Format.percent(ds.value)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return holding
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色武器、圣遗物使用
|
||||||
|
* @param id
|
||||||
|
* @returns {Promise<{}|{artis: *[], weapons: *[]}>}
|
||||||
|
*/
|
||||||
|
async getUsage (id) {
|
||||||
|
let ud = (await HutaoApi.getUsage()).data || {}
|
||||||
|
if (!ud[id]) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
ud = ud[id]
|
||||||
|
return {
|
||||||
|
weapons: CharWikiData.getWeaponsData(ud.weapons),
|
||||||
|
artis: CharWikiData.getArtisData(ud.artis)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 武器使用
|
||||||
|
* @param data
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
|
getWeaponsData (data = []) {
|
||||||
|
let weapons = []
|
||||||
|
|
||||||
|
lodash.forEach(data, (ds) => {
|
||||||
|
let weapon = Weapon.get(ds.item) || {}
|
||||||
|
weapons.push({
|
||||||
|
...weapon.getData('name,abbr,img,star'),
|
||||||
|
value: ds.rate
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
weapons = lodash.sortBy(weapons, 'value')
|
||||||
|
weapons = weapons.reverse()
|
||||||
|
lodash.forEach(weapons, (ds) => {
|
||||||
|
ds.value = Format.percent(ds.value, 1)
|
||||||
|
})
|
||||||
|
return weapons
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 圣遗物使用
|
||||||
|
* @param data
|
||||||
|
* @returns {*[]}
|
||||||
|
*/
|
||||||
|
getArtisData (data = []) {
|
||||||
|
let artis = []
|
||||||
|
|
||||||
|
lodash.forEach(data, (ds) => {
|
||||||
|
let imgs = []
|
||||||
|
let abbrs = []
|
||||||
|
let ss = ds.item.split(',')
|
||||||
|
lodash.forEach(ss, (t) => {
|
||||||
|
t = t.split(':')
|
||||||
|
let artiSet = ArtifactSet.get(t[0])
|
||||||
|
if (artiSet) {
|
||||||
|
imgs.push(artiSet.img)
|
||||||
|
abbrs.push(artiSet.abbr + (ss.length === 1 ? t[1] : ''))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
artis.push({
|
||||||
|
imgs,
|
||||||
|
title: abbrs.join('+'),
|
||||||
|
value: ds.rate
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
artis = lodash.sortBy(artis, 'value')
|
||||||
|
artis = artis.reverse()
|
||||||
|
artis.forEach((ds) => {
|
||||||
|
ds.value = Format.percent(ds.value)
|
||||||
|
})
|
||||||
|
return artis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default CharWikiData
|
@ -9,9 +9,15 @@ class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reg (key, fn, cfg = {}) {
|
reg (key, fn, cfg = {}) {
|
||||||
this.apps[key] = {
|
if (lodash.isPlainObject(key)) {
|
||||||
fn,
|
lodash.forEach(key, (cfg, k) => {
|
||||||
...cfg
|
this.reg(k, cfg.fn, cfg)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.apps[key] = {
|
||||||
|
fn,
|
||||||
|
...cfg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import lodash from 'lodash'
|
|||||||
import Base from './Base.js'
|
import Base from './Base.js'
|
||||||
import { Artifact, ArtifactSet } from './index.js'
|
import { Artifact, ArtifactSet } from './index.js'
|
||||||
import { Format, Data } from '../components/index.js'
|
import { Format, Data } from '../components/index.js'
|
||||||
import ArtisMark from './profile-lib/ArtisMark.js'
|
import ArtisMark from './profile/ArtisMark.js'
|
||||||
|
|
||||||
export default class AvatarArtis extends Base {
|
export default class AvatarArtis extends Base {
|
||||||
constructor (charid = 0) {
|
constructor (charid = 0) {
|
||||||
|
@ -3,8 +3,8 @@ import Base from './Base.js'
|
|||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { Character, AvatarArtis, ProfileData, Weapon } from './index.js'
|
import { Character, AvatarArtis, ProfileData, Weapon } from './index.js'
|
||||||
import { Data } from '../components/index.js'
|
import { Data } from '../components/index.js'
|
||||||
import AttrCalc from './profile-lib/AttrCalc.js'
|
import AttrCalc from './profile/AttrCalc.js'
|
||||||
import Profile from './player-lib/Profile.js'
|
import Profile from './player/Profile.js'
|
||||||
|
|
||||||
const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',')
|
const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',')
|
||||||
|
|
||||||
@ -29,6 +29,10 @@ export default class AvatarData extends Base {
|
|||||||
return this.char?.name || ''
|
return this.char?.name || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasData () {
|
||||||
|
return !!(this.level > 1 || this?.weapon?.name || this?.talent?.a)
|
||||||
|
}
|
||||||
|
|
||||||
// 是否是合法面板数据
|
// 是否是合法面板数据
|
||||||
get isProfile () {
|
get isProfile () {
|
||||||
return Profile.isProfile(this)
|
return Profile.isProfile(this)
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import Base from './Base.js'
|
import Base from './Base.js'
|
||||||
import { Data, Format } from '../components/index.js'
|
import { Data, Format } from '../components/index.js'
|
||||||
import CharImg from './character-lib/CharImg.js'
|
import CharImg from './character/CharImg.js'
|
||||||
import CharTalent from './character-lib/CharTalent.js'
|
import CharTalent from './character/CharTalent.js'
|
||||||
import CharId from './character-lib/CharId.js'
|
import CharId from './character/CharId.js'
|
||||||
import CharMeta from './character-lib/CharMeta.js'
|
import CharMeta from './character/CharMeta.js'
|
||||||
import CharCfg from './character-lib/CharCfg.js'
|
import CharCfg from './character/CharCfg.js'
|
||||||
|
|
||||||
let { wifeMap, idSort, idMap } = CharId
|
let { wifeMap, idSort, idMap } = CharId
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import Base from './Base.js'
|
import Base from './Base.js'
|
||||||
import { Data } from '../components/index.js'
|
import { Data } from '../components/index.js'
|
||||||
import MaterialMeta from './material-lib/MaterialMeta.js'
|
import MaterialMeta from './material/MaterialMeta.js'
|
||||||
|
|
||||||
let data = Data.readJSON('resources/meta/material/data.json')
|
let data = Data.readJSON('resources/meta/material/data.json')
|
||||||
let abbr = await Data.importDefault('resources/meta/material/abbr.js')
|
let abbr = await Data.importDefault('resources/meta/material/abbr.js')
|
||||||
|
@ -12,6 +12,26 @@ export default class MysApi {
|
|||||||
e.isSelfCookie = this.isSelfCookie
|
e.isSelfCookie = this.isSelfCookie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isSelfCookie () {
|
||||||
|
return this.uid * 1 === this.ckUid * 1 || this?.mysInfo?.isSelf
|
||||||
|
}
|
||||||
|
|
||||||
|
get ckUid () {
|
||||||
|
return this.ckInfo.uid
|
||||||
|
}
|
||||||
|
|
||||||
|
get ck () {
|
||||||
|
return this.ckInfo.ck
|
||||||
|
}
|
||||||
|
|
||||||
|
get selfUser () {
|
||||||
|
return new User({ id: this.e.user_id, uid: this.uid })
|
||||||
|
}
|
||||||
|
|
||||||
|
get targetUser () {
|
||||||
|
return new User({ id: this.e.user_id, uid: this.uid })
|
||||||
|
}
|
||||||
|
|
||||||
static async init (e, auth = 'all') {
|
static async init (e, auth = 'all') {
|
||||||
if (!e.runtime) {
|
if (!e.runtime) {
|
||||||
Version.runtime()
|
Version.runtime()
|
||||||
@ -50,31 +70,12 @@ export default class MysApi {
|
|||||||
if (uid) {
|
if (uid) {
|
||||||
return new User({ id: e.user_id, uid })
|
return new User({ id: e.user_id, uid })
|
||||||
} else {
|
} else {
|
||||||
e.reply('请先#绑定uid')
|
e.reply('请先发送【#绑定+你的UID】来绑定查询目标')
|
||||||
|
e._replyNeedUid = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get isSelfCookie () {
|
|
||||||
return this.uid * 1 === this.ckUid * 1 || this?.mysInfo?.isSelf
|
|
||||||
}
|
|
||||||
|
|
||||||
get ckUid () {
|
|
||||||
return this.ckInfo.uid
|
|
||||||
}
|
|
||||||
|
|
||||||
get ck () {
|
|
||||||
return this.ckInfo.ck
|
|
||||||
}
|
|
||||||
|
|
||||||
get selfUser () {
|
|
||||||
return new User({ id: this.e.user_id, uid: this.uid })
|
|
||||||
}
|
|
||||||
|
|
||||||
get targetUser () {
|
|
||||||
return new User({ id: this.e.user_id, uid: this.uid })
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMysApi (e, targetType = 'all', option = {}) {
|
async getMysApi (e, targetType = 'all', option = {}) {
|
||||||
if (this.mys) {
|
if (this.mys) {
|
||||||
return this.mys
|
return this.mys
|
||||||
|
@ -9,8 +9,8 @@ import Base from './Base.js'
|
|||||||
import { Data } from '../components/index.js'
|
import { Data } from '../components/index.js'
|
||||||
import { AvatarData, ProfileRank, Character } from './index.js'
|
import { AvatarData, ProfileRank, Character } from './index.js'
|
||||||
|
|
||||||
import MysAvatar from './player-lib/MysAvatar.js'
|
import MysAvatar from './player/MysAvatar.js'
|
||||||
import Profile from './player-lib/Profile.js'
|
import Profile from './player/Profile.js'
|
||||||
|
|
||||||
Data.createDir('/data/userData', 'root')
|
Data.createDir('/data/userData', 'root')
|
||||||
|
|
||||||
@ -30,6 +30,17 @@ export default class Player extends Base {
|
|||||||
return this._cache()
|
return this._cache()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasProfile () {
|
||||||
|
let ret = false
|
||||||
|
lodash.forEach(this._avatars, (avatar) => {
|
||||||
|
if (avatar.isProfile) {
|
||||||
|
ret = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
static create (e) {
|
static create (e) {
|
||||||
if (e?._mys?.uid || e.uid) {
|
if (e?._mys?.uid || e.uid) {
|
||||||
// 传入为e
|
// 传入为e
|
||||||
@ -68,8 +79,8 @@ export default class Player extends Base {
|
|||||||
save () {
|
save () {
|
||||||
let ret = Data.getData(this, 'uid,name,level,word,face,card,sign,info,_info,_mys,_profile')
|
let ret = Data.getData(this, 'uid,name,level,word,face,card,sign,info,_info,_mys,_profile')
|
||||||
ret.avatars = {}
|
ret.avatars = {}
|
||||||
lodash.forEach(this._avatars, (ds) => {
|
this.forEachAvatar((avatar) => {
|
||||||
ret.avatars[ds.id] = ds.toJSON()
|
ret.avatars[avatar.id] = avatar.toJSON()
|
||||||
})
|
})
|
||||||
// 暂时保留旧数据,防止异常情况
|
// 暂时保留旧数据,防止异常情况
|
||||||
if (this._chars) {
|
if (this._chars) {
|
||||||
@ -136,9 +147,12 @@ export default class Player extends Base {
|
|||||||
// 循环Avatar
|
// 循环Avatar
|
||||||
forEachAvatar (fn) {
|
forEachAvatar (fn) {
|
||||||
for (let id in this._avatars) {
|
for (let id in this._avatars) {
|
||||||
let ret = fn(this._avatars[id], id)
|
let avatar = this._avatars[id]
|
||||||
if (ret === false) {
|
if (avatar && avatar.hasData) {
|
||||||
return false
|
let ret = fn(this._avatars[id])
|
||||||
|
if (ret === false) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +209,7 @@ export default class Player extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新面板
|
// 更新面板
|
||||||
async refreshProfile (force = 1) {
|
async refreshProfile (force = 2) {
|
||||||
return await Profile.refreshProfile(this, force)
|
return await Profile.refreshProfile(this, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,14 +237,20 @@ export default class Player extends Base {
|
|||||||
return await MysAvatar.refreshTalent(this, ids, force)
|
return await MysAvatar.refreshTalent(this, ids, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshAndGetAvatarData (cfg) {
|
async refresh (cfg) {
|
||||||
// 更新角色信息
|
if (cfg.detail || cfg.detail === 0) {
|
||||||
await this.refreshMysDetail(cfg.force || 0)
|
await this.refreshMysDetail(cfg.detail)
|
||||||
|
|
||||||
// 更新天赋信息
|
|
||||||
if (cfg.refreshTalent !== false) {
|
|
||||||
await this.refreshTalent(cfg.ids, cfg.force || 0)
|
|
||||||
}
|
}
|
||||||
|
if (cfg.talent || cfg.talent === 0) {
|
||||||
|
await this.refreshTalent(cfg.ids, cfg.talent)
|
||||||
|
}
|
||||||
|
if (cfg.profile || cfg.profile === 0) {
|
||||||
|
await this.refreshProfile(cfg.profile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async refreshAndGetAvatarData (cfg) {
|
||||||
|
await this.refresh(cfg)
|
||||||
|
|
||||||
let rank = false
|
let rank = false
|
||||||
let e = this.e
|
let e = this.e
|
||||||
|
@ -5,9 +5,9 @@ import lodash from 'lodash'
|
|||||||
import AvatarArtis from './AvatarArtis.js'
|
import AvatarArtis from './AvatarArtis.js'
|
||||||
import { Artifact, ArtifactSet, Character } from './index.js'
|
import { Artifact, ArtifactSet, Character } from './index.js'
|
||||||
import { Format } from '../components/index.js'
|
import { Format } from '../components/index.js'
|
||||||
import ArtisMark from './profile-lib/ArtisMark.js'
|
import ArtisMark from './profile/ArtisMark.js'
|
||||||
import { attrMap } from '../resources/meta/artifact/index.js'
|
import { attrMap } from '../resources/meta/artifact/index.js'
|
||||||
import CharArtis from './profile-lib/CharArtis.js'
|
import CharArtis from './profile/CharArtis.js'
|
||||||
|
|
||||||
export default class ProfileArtis extends AvatarArtis {
|
export default class ProfileArtis extends AvatarArtis {
|
||||||
constructor (charid = 0, elem = '') {
|
constructor (charid = 0, elem = '') {
|
||||||
|
@ -2,8 +2,8 @@ import lodash from 'lodash'
|
|||||||
import AvatarData from './AvatarData.js'
|
import AvatarData from './AvatarData.js'
|
||||||
import { Data } from '../components/index.js'
|
import { Data } from '../components/index.js'
|
||||||
import { ProfileArtis, ProfileDmg } from './index.js'
|
import { ProfileArtis, ProfileDmg } from './index.js'
|
||||||
import AttrCalc from './profile-lib/AttrCalc.js'
|
import AttrCalc from './profile/AttrCalc.js'
|
||||||
import CharImg from './character-lib/CharImg.js'
|
import CharImg from './character/CharImg.js'
|
||||||
|
|
||||||
export default class ProfileData extends AvatarData {
|
export default class ProfileData extends AvatarData {
|
||||||
constructor (ds = {}, calc = true) {
|
constructor (ds = {}, calc = true) {
|
||||||
|
@ -3,9 +3,9 @@ import lodash from 'lodash'
|
|||||||
import Base from './Base.js'
|
import Base from './Base.js'
|
||||||
import { Character } from './index.js'
|
import { Character } from './index.js'
|
||||||
import { attrMap } from '../resources/meta/artifact/index.js'
|
import { attrMap } from '../resources/meta/artifact/index.js'
|
||||||
import DmgBuffs from './profile-lib/DmgBuffs.js'
|
import DmgBuffs from './profile/DmgBuffs.js'
|
||||||
import DmgAttr from './profile-lib/DmgAttr.js'
|
import DmgAttr from './profile/DmgAttr.js'
|
||||||
import DmgCalc from './profile-lib/DmgCalc.js'
|
import DmgCalc from './profile/DmgCalc.js'
|
||||||
import { Common } from '../components/index.js'
|
import { Common } from '../components/index.js'
|
||||||
|
|
||||||
export default class ProfileDmg extends Base {
|
export default class ProfileDmg extends Base {
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import { Common, Data } from '../../components/index.js'
|
import { Common, Data } from '../../components/index.js'
|
||||||
|
import { chestInfo } from '../../resources/meta/info/index.js'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
const MysAvatar = {
|
const MysAvatar = {
|
||||||
|
|
||||||
needRefresh (time, force = 0, forceMap = {}) {
|
needRefresh (time, force = 0, forceMap = {}) {
|
||||||
if (!time) {
|
if (!time || force === 2) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if (force === true) {
|
||||||
|
force = 0
|
||||||
|
}
|
||||||
let duration = new Date() * 1 - time * 1
|
let duration = new Date() * 1 - time * 1
|
||||||
if (isNaN(duration) || duration < 0) {
|
if (isNaN(duration) || duration < 0) {
|
||||||
return true
|
return true
|
||||||
@ -250,15 +254,16 @@ const MysAvatar = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getInfo (player) {
|
getInfo (player) {
|
||||||
|
let chestMap = []
|
||||||
|
Data.eachStr('common,exquisite,precious,luxurious,magic', (key) => {
|
||||||
|
chestMap.push({
|
||||||
|
key: `${key}Chest`,
|
||||||
|
...chestInfo[key]
|
||||||
|
})
|
||||||
|
})
|
||||||
let ret = {
|
let ret = {
|
||||||
...(player.info || {}),
|
...(player.info || {}),
|
||||||
chestMap: [
|
chestMap
|
||||||
{ key: 'commonChest', title: '普通宝箱', max: 2521 },
|
|
||||||
{ key: 'exquisiteChest', title: '精致宝箱', max: 1585 },
|
|
||||||
{ key: 'preciousChest', title: '珍贵宝箱', max: 482 },
|
|
||||||
{ key: 'luxuriousChest', title: '豪华宝箱', max: 184 },
|
|
||||||
{ key: 'magicChest', title: '奇馈宝箱', max: 140 }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
let stats = ret.stats || {}
|
let stats = ret.stats || {}
|
||||||
if (stats?.activeDay) {
|
if (stats?.activeDay) {
|
@ -1,5 +1,6 @@
|
|||||||
import { ProfileReq, ProfileServ } from '../index.js'
|
import { ProfileReq, ProfileServ } from '../index.js'
|
||||||
import { Cfg, Data } from '../../components/index.js'
|
import { Cfg, Data } from '../../components/index.js'
|
||||||
|
import MysAvatar from './MysAvatar.js'
|
||||||
|
|
||||||
import enkaCfg from './EnkaApi.js'
|
import enkaCfg from './EnkaApi.js'
|
||||||
import MiaoApi from './MiaoApi.js'
|
import MiaoApi from './MiaoApi.js'
|
||||||
@ -34,7 +35,10 @@ const Profile = {
|
|||||||
* @param force
|
* @param force
|
||||||
* @returns {Promise<boolean|number>}
|
* @returns {Promise<boolean|number>}
|
||||||
*/
|
*/
|
||||||
async refreshProfile (player, force = 1) {
|
async refreshProfile (player, force = 2) {
|
||||||
|
if (!MysAvatar.needRefresh(player._profile, force, { 0: 24, 1: 2, 2: 0 })) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
player._update = []
|
player._update = []
|
||||||
let { uid, e } = player
|
let { uid, e } = player
|
||||||
if (uid.toString().length !== 9 || !e) {
|
if (uid.toString().length !== 9 || !e) {
|
@ -159,7 +159,7 @@
|
|||||||
.chest-list .chest .detail {
|
.chest-list .chest .detail {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.chest-list .chest .info {
|
.chest-list .chest .info {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -176,7 +176,6 @@
|
|||||||
vertical-align: center;
|
vertical-align: center;
|
||||||
}
|
}
|
||||||
.chest-list .chest .max {
|
.chest-list .chest .max {
|
||||||
font-size: 12px;
|
|
||||||
padding-left: 3px;
|
padding-left: 3px;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@
|
|||||||
.detail {
|
.detail {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
@ -211,7 +211,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.max {
|
.max {
|
||||||
font-size: 12px;
|
|
||||||
padding-left: 3px;
|
padding-left: 3px;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,11 @@
|
|||||||
padding: 3px 7.5px 3px 4.5px;
|
padding: 3px 7.5px 3px 4.5px;
|
||||||
border-radius: 0 6px 0 0;
|
border-radius: 0 6px 0 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
text-shadow: 0 0 1px #000;
|
||||||
|
}
|
||||||
|
.avatar-card .avatar-face .avatar-level span {
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
.avatar-card .cons {
|
.avatar-card .cons {
|
||||||
border-radius: 0 0 0 7.5px;
|
border-radius: 0 0 0 7.5px;
|
||||||
@ -178,6 +183,11 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
.avatar-card .cons.cons-0 {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
.avatar-card .avatar-talent {
|
.avatar-card .avatar-talent {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
@ -253,15 +263,23 @@
|
|||||||
width: 114px;
|
width: 114px;
|
||||||
border-radius: 10.5px 0 0 10.5px;
|
border-radius: 10.5px 0 0 10.5px;
|
||||||
}
|
}
|
||||||
.avatar-card.card-wide .img {
|
.avatar-card.card-wide .avatar-face .img {
|
||||||
background-size: 100% auto;
|
background-size: 100% auto;
|
||||||
background-position: 0 10%;
|
background-position: 0 10%;
|
||||||
height: 135px;
|
height: 202.5px;
|
||||||
margin-top: -13.5px;
|
margin-top: -13.5px;
|
||||||
}
|
}
|
||||||
.avatar-card.card-wide .avatar-info {
|
.avatar-card.card-wide .avatar-info {
|
||||||
width: 105px;
|
width: 105px;
|
||||||
}
|
}
|
||||||
|
.avatar-card.card-wide .avatar-info strong {
|
||||||
|
display: block;
|
||||||
|
height: 45px;
|
||||||
|
line-height: 45px;
|
||||||
|
}
|
||||||
|
.avatar-card.card-wide .avatar-info .lv-info {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
.avatar-card.card-wide .line {
|
.avatar-card.card-wide .line {
|
||||||
display: block;
|
display: block;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
@ -307,8 +325,12 @@
|
|||||||
.avatar-card .avatar-artis {
|
.avatar-card .avatar-artis {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.avatar-card .avatar-artis.artis0 .item-icon {
|
||||||
|
background: url('./item/artifact-icon.webp') rgba(0, 0, 0, 0.3) center no-repeat;
|
||||||
|
background-size: auto 80%;
|
||||||
|
}
|
||||||
.avatar-card .avatar-artis .artis {
|
.avatar-card .avatar-artis .artis {
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
}
|
}
|
||||||
.avatar-card .avatar-artis.artis2 .img {
|
.avatar-card .avatar-artis.artis2 .img {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -10,21 +10,24 @@
|
|||||||
<div class="img mini" style="background-image:url({{_res_path}}{{avatar.face}})"></div>
|
<div class="img mini" style="background-image:url({{_res_path}}{{avatar.face}})"></div>
|
||||||
<div class="img wide avatar-{{avatar.name}}" style="background-image:url({{_res_path}}{{avatar.gacha}})"></div>
|
<div class="img wide avatar-{{avatar.name}}" style="background-image:url({{_res_path}}{{avatar.gacha}})"></div>
|
||||||
<span class="cons cons-{{avatar.cons}} mini">{{avatar.cons}}</span>
|
<span class="cons cons-{{avatar.cons}} mini">{{avatar.cons}}</span>
|
||||||
<div class="avatar-level">Lv{{avatar.level}}</div>
|
<div class="avatar-level"><span>Lv</span>{{avatar.level}} {{avatar.abbr}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="avatar-info">
|
<div class="avatar-info">
|
||||||
{{set talent = avatar.talent || {} }}
|
{{set talent = avatar.talent || {} }}
|
||||||
{{if talent.a && talent.a.level }}
|
|
||||||
<div class="avatar-name wide">
|
<div class="avatar-name wide">
|
||||||
<strong>{{avatar.abbr}}</strong>
|
<strong>{{avatar.abbr}}</strong>
|
||||||
<span class="cons cons-{{avatar.cons}}">{{avatar.cons}}</span>
|
<div class="lv-info">
|
||||||
<span class="avatar-level">Lv{{avatar.level}}</span>
|
<span class="cons cons-{{avatar.cons}}">{{avatar.cons}}</span>
|
||||||
|
<span class="avatar-level">Lv{{avatar.level}}</span>
|
||||||
|
</div>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
</div>
|
</div>
|
||||||
|
{{if talent.a && talent.a.level }}
|
||||||
<div class="avatar-talent">
|
<div class="avatar-talent">
|
||||||
{{each talentMap k}}
|
{{each talentMap k}}
|
||||||
{{set t = talent[k] || {} }} <span
|
{{set t = talent[k] || {} }}
|
||||||
class="talent-item talent-{{k}} talent-{{t.original===10?'crown':'none'}} talent-{{t.level>t.original?'plus':'none'}}">{{t.level}}</span>
|
<span class="talent-item talent-{{k}} talent-{{t.original===10?'crown':'none'}} talent-{{t.level>t.original?'plus':'none'}}">{{t.level}}</span>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
@ -35,7 +38,7 @@
|
|||||||
<div class="item avatar-weapon">
|
<div class="item avatar-weapon">
|
||||||
<div class="item-icon star{{weapon.star}}">
|
<div class="item-icon star{{weapon.star}}">
|
||||||
<span class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></span>
|
<span class="img" style="background-image:url({{_res_path}}{{weapon.img}})"></span>
|
||||||
<span class="cons cons-{{weapon.affix}}">{{weapon.affix}}</span>
|
<span class="cons cons-{{weapon.affix > 4 ? weapon.affix + 1 : weapon.affix}}">{{weapon.affix}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item avatar-artis artis{{avatar.artisSet?.names?.length}}">
|
<div class="item avatar-artis artis{{avatar.artisSet?.names?.length}}">
|
||||||
|
@ -37,6 +37,12 @@
|
|||||||
padding: @px*2 @px*5 @px*2 @px*3;
|
padding: @px*2 @px*5 @px*2 @px*3;
|
||||||
border-radius: 0 @px*4 0 0;
|
border-radius: 0 @px*4 0 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
text-shadow: 0 0 1px #000;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -47,6 +53,12 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
text-shadow: 0 0 1px #000, 1px 1px 3px rgba(0, 0, 0, .8);
|
||||||
|
|
||||||
|
&.cons-0 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-talent {
|
.avatar-talent {
|
||||||
@ -136,17 +148,27 @@
|
|||||||
height: @px * 126;
|
height: @px * 126;
|
||||||
width: @px*76;
|
width: @px*76;
|
||||||
border-radius: @px*7 0 0 @px*7;
|
border-radius: @px*7 0 0 @px*7;
|
||||||
}
|
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
background-size: 100% auto;
|
background-size: 100% auto;
|
||||||
background-position: 0 10%;
|
background-position: 0 10%;
|
||||||
height: 135px;
|
height: @px*135;
|
||||||
margin-top: @px*-9;
|
margin-top: @px*-9;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-info {
|
.avatar-info {
|
||||||
width: @px*70;
|
width: @px*70;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
display: block;
|
||||||
|
height: @px * 30;
|
||||||
|
line-height: @px*30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lv-info {
|
||||||
|
height: @px*20;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
@ -211,8 +233,15 @@
|
|||||||
.avatar-artis {
|
.avatar-artis {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
&.artis0 {
|
||||||
|
.item-icon {
|
||||||
|
background: url('./item/artifact-icon.webp') rgba(0, 0, 0, .3) center no-repeat;
|
||||||
|
background-size: auto 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.artis {
|
.artis {
|
||||||
background: rgba(0, 0, 0, 0.5)
|
background: rgba(0, 0, 0, 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
&.artis2 {
|
&.artis2 {
|
||||||
|
23
resources/meta/info/index.js
Normal file
23
resources/meta/info/index.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// 报箱数统计
|
||||||
|
export const chestInfo = {
|
||||||
|
common: {
|
||||||
|
title: '普通宝箱',
|
||||||
|
max: 2542
|
||||||
|
},
|
||||||
|
exquisite: {
|
||||||
|
title: '精致宝箱',
|
||||||
|
max: 1594
|
||||||
|
},
|
||||||
|
precious: {
|
||||||
|
title: '珍贵宝箱',
|
||||||
|
max: 488
|
||||||
|
},
|
||||||
|
luxurious: {
|
||||||
|
title: '豪华宝箱',
|
||||||
|
max: 185
|
||||||
|
},
|
||||||
|
magic: {
|
||||||
|
title: '奇馈宝箱',
|
||||||
|
max: 146
|
||||||
|
}
|
||||||
|
}
|
@ -148,13 +148,8 @@ export default function (step, staticStep) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
裁叶萃光: [{
|
裁叶萃光: [staticStep('cpct', 4), {
|
||||||
title: '暴击率提升[cpct]%',
|
title: '普攻与元素战技造成的伤害值提高[aPlus]',
|
||||||
refine: {
|
|
||||||
cpct: step(4)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
title: '暴击率提升4%,普攻与元素战技造成的伤害值提高[aPlus]',
|
|
||||||
data: {
|
data: {
|
||||||
aPlus: ({ attr, calc, refine }) => calc(attr.mastery) * step(120)[refine] / 100,
|
aPlus: ({ attr, calc, refine }) => calc(attr.mastery) * step(120)[refine] / 100,
|
||||||
ePlus: ({ attr, calc, refine }) => calc(attr.mastery) * step(120)[refine] / 100
|
ePlus: ({ attr, calc, refine }) => calc(attr.mastery) * step(120)[refine] / 100
|
||||||
|
@ -84,7 +84,7 @@ body,
|
|||||||
color: #d3bc8e;
|
color: #d3bc8e;
|
||||||
}
|
}
|
||||||
.avatar-banner {
|
.avatar-banner {
|
||||||
height: 265px;
|
height: 300px;
|
||||||
width: 175px;
|
width: 175px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 100% auto;
|
background-size: 100% auto;
|
||||||
|
@ -97,7 +97,7 @@ body, .container {
|
|||||||
|
|
||||||
|
|
||||||
.avatar-banner {
|
.avatar-banner {
|
||||||
height: 265px;
|
height: 300px;
|
||||||
width: 175px;
|
width: 175px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 100% auto;
|
background-size: 100% auto;
|
||||||
|
Loading…
Reference in New Issue
Block a user