Miao-Yunzai/plugins/genshin/model/gachaData.js

532 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import base from './base.js'
import gsCfg from './gsCfg.js'
import lodash from 'lodash'
import moment from 'moment'
import fetch from 'node-fetch'
import fs from 'node:fs'
let imgFile = {}
export default class GachaData extends base {
/**
* @param e icqq 消息e
* @param e.user_id 用户id
*/
constructor (e) {
super(e)
this.model = 'gacha'
/** 卡池 */
this.pool = {}
/** 默认设置 */
this.def = gsCfg.getdefSet('gacha', 'gacha')
this.set = gsCfg.getGachaSet(this.e.group_id)
/** 角色武器类型 */
this.ele = gsCfg.element
/** 默认角色池 */
this.type = 'role'
/** 抽卡结果 */
this.res = []
this.fiveHave = []
this.fourHave = []
}
static async init (e) {
let gacha = new GachaData(e)
gacha.initFile()
/** 抽卡类型 */
gacha.getTpye()
/** 用户抽卡数据 */
await gacha.userData()
/** 卡池 */
await gacha.getPool()
return gacha
}
/** 抽卡 */
async run () {
let list = this.lottery()
/** 截图数据 */
let data = {
name: this.e.sender.card,
quality: 80,
...this.screenData,
...this.lotteryInfo(),
list
}
return data
}
get key () {
/** 群,私聊分开 */
if (this.e.isGroup) {
return `${this.prefix}${this.e.group_id}:${this.userId}`
} else {
return `${this.prefix}private:${this.userId}`
}
}
getTpye () {
if (this.e.msg.includes('2')) this.role2 = true
if (this.e.msg.includes('武器')) this.type = 'weapon'
if (this.e.msg.includes('常驻')) this.type = 'permanent'
}
/** 奖池数据 */
async getPool () {
let poolArr = gsCfg.getdefSet('gacha', 'pool')
poolArr = [...poolArr].reverse()
/** 获取设置卡池 */
let NowPool = poolArr.find((val) => new Date().getTime() <= new Date(val.endTime).getTime()) || poolArr.pop()
this.NowPool = NowPool
if (this.type == 'weapon') {
let weapon4 = lodash.difference(this.def.weapon4, NowPool.weapon4)
let weapon5 = lodash.difference(this.def.weapon5, NowPool.weapon5)
this.pool = {
up4: NowPool.weapon4,
role4: this.def.role4,
weapon4,
up5: NowPool.weapon5,
five: weapon5
}
}
if (this.type == 'role') {
let role4 = lodash.difference(this.def.role4, NowPool.up4)
let role5 = lodash.difference(this.def.role5, NowPool.up5)
let up5 = NowPool.up5
if (this.role2) up5 = NowPool.up5_2
this.pool = {
/** up卡池 */
up4: NowPool.up4,
/** 常驻四星 */
role4,
/** 常驻四星武器 */
weapon4: this.def.weapon4,
/** 五星 */
up5,
/** 常驻五星 */
five: role5
}
}
if (this.type == 'permanent') {
this.pool = {
up4: [],
role4: this.def.role4,
weapon4: this.def.weapon4,
up5: [],
five: this.def.role5,
fiveW: this.def.weapon5
}
}
this.pool.weapon3 = this.def.weapon3
}
/** 用户数据 */
async userData () {
if (this.user) return this.user
let user = await redis.get(this.key)
if (user) {
user = JSON.parse(user)
/** 重置今日数据 */
if (this.getNow() > user.today.expire) {
user.today = { star: [], expire: this.getEnd().end4, num: 0, weaponNum: 0 }
}
/** 重置本周数据 */
if (this.getNow() > user.week.expire) {
user.week = { num: 0, expire: this.getWeekEnd() }
}
} else {
let commom = { num4: 0, isUp4: 0, num5: 0, isUp5: 0 }
user = {
permanent: commom,
role: commom,
weapon: {
...commom,
/** 命定值 */
lifeNum: 0,
/** 定轨 0-取消 1-武器1 2-武器2 */
type: 1
},
today: { star: [], expire: this.getEnd().end4, num: 0, weaponNum: 0 },
week: { num: 0, expire: this.getWeekEnd() }
}
}
this.user = user
return user
}
/**
* 抽奖
*/
lottery (save = true) {
/** 十连抽 */
for (let i = 1; i <= 10; i++) {
this.index = i
if (this.type == 'weapon') {
this.user.today.weaponNum++
} else {
this.user.today.num++
}
if (this.lottery5()) continue
if (this.lottery4()) continue
this.lottery3()
}
if (save) this.saveUser()
/** 排序 星级,角色,武器 */
this.res = lodash.orderBy(this.res, ['star', 'type', 'have', 'index'], ['desc', 'asc', 'asc', 'asc'])
return this.res
}
lottery5 () {
/** 是否大保底 */
let isBigUP = false
let isBing = false
let tmpChance5 = this.probability()
let type = this.type
/** 没有抽中五星 */
if (lodash.random(1, 10000) > tmpChance5) {
/** 五星保底数+1 */
this.user[this.type].num5++
return false
}
let nowCardNum = this.user[this.type].num5 + 1
/** 五星保底清零 */
this.user[this.type].num5 = 0
/** 四星保底数+1 */
this.user[this.type].num4++
let tmpUp = this.def.wai
/** 已经小保底 */
if (this.user[this.type].isUp5 == 1) {
tmpUp = 101
}
if (this.type == 'permanent') tmpUp = 0
let tmpName = ''
if (this.type == 'weapon' && this.user[this.type].lifeNum >= 2) {
/** 定轨 */
tmpName = this.getBingWeapon()
this.user[this.type].lifeNum = 0
isBing = true
} else if (lodash.random(1, 100) <= tmpUp) {
/** 当祈愿获取到5星角色时有50%的概率为本期UP角色 */
if (this.user[this.type].isUp5 == 1) isBigUP = true
/** 大保底清零 */
this.user[this.type].isUp5 = 0
/** 抽取up */
tmpName = lodash.sample(this.pool.up5)
/** 定轨清零 */
if (tmpName == this.getBingWeapon()) {
this.user[this.type].lifeNum = 0
}
} else {
if (this.type == 'permanent') {
if (lodash.random(1, 100) <= 50) {
tmpName = lodash.sample(this.pool.five)
type = 'role'
} else {
tmpName = lodash.sample(this.pool.fiveW)
type = 'weapon'
}
} else {
/** 歪了 大保底+1 */
this.user[this.type].isUp5 = 1
tmpName = lodash.sample(this.pool.five)
}
}
/** 命定值++ */
if (tmpName != this.getBingWeapon()) {
this.user[this.type].lifeNum++
}
/** 记录今天五星 */
this.user.today.star.push({ name: tmpName, num: nowCardNum })
/** 本周五星数 */
this.user.week.num++
let have = false
/** 重复抽中转换星辉 */
if (this.fiveHave.includes(tmpName)) {
have = true
} else {
this.fiveHave.push(tmpName)
}
this.res.push({
name: tmpName,
star: 5,
type,
num: nowCardNum,
element: this.ele[tmpName] || '',
index: this.index,
isBigUP,
isBing,
have,
imgFile: imgFile[tmpName] || `${tmpName}.png`,
rand: lodash.random(1, 7)
})
return true
}
lottery4 () {
let tmpChance4 = this.def.chance4
/** 四星保底 */
if (this.user[this.type].num4 >= 9) {
tmpChance4 += 10000
} else if (this.user[this.type].num4 >= 5) {
tmpChance4 = tmpChance4 + Math.pow(this.user[this.type].num4 - 4, 2) * 500
}
/** 没抽中四星 */
if (lodash.random(1, 10000) > tmpChance4) {
/** 四星保底数+1 */
this.user[this.type].num4++
return false
}
/** 保底四星数清零 */
this.user[this.type].num4 = 0
/** 四星保底 */
let tmpUp = 50
if (this.type == 'weapon') tmpUp = 75
if (this.user[this.type].isUp4 == 1) {
this.user[this.type].isUp4 = 0
tmpUp = 100
}
if (this.type == 'permanent') tmpUp = 0
let type = 'role'
let tmpName = ''
/** 当祈愿获取到4星物品时有50%的概率为本期UP角色 */
if (lodash.random(1, 100) <= tmpUp) {
/** up 4星 */
tmpName = lodash.sample(this.pool.up4)
type = this.type
} else {
this.user[this.type].isUp4 = 1
/** 一半概率武器 一半4星 */
if (lodash.random(1, 100) <= 50) {
tmpName = lodash.sample(this.pool.role4)
type = 'role'
} else {
tmpName = lodash.sample(this.pool.weapon4)
type = 'weapon'
}
}
let have = false
/** 重复抽中转换星辉 */
if (this.fourHave.includes(tmpName)) {
have = true
} else {
this.fourHave.push(tmpName)
}
this.res.push({
name: tmpName,
star: 4,
type,
element: this.ele[tmpName] || '',
index: this.index,
imgFile: imgFile[tmpName] || `${tmpName}.png`,
have
})
return true
}
lottery3 () {
/** 随机三星武器 */
let tmpName = lodash.sample(this.pool.weapon3)
this.res.push({
name: tmpName,
star: 3,
type: 'weapon',
element: this.ele[tmpName] || '',
index: this.index,
imgFile: imgFile[tmpName] || `${tmpName}.png`
})
return true
}
probability () {
let tmpChance5 = this.def.chance5
if (this.type == 'role' || this.type == 'permanent') {
/** 增加双黄概率 */
if (this.user.week.num == 1) {
tmpChance5 *= 2
}
/** 保底 */
if (this.user[this.type].num5 >= 90) {
tmpChance5 = 10000
} else if (this.user[this.type].num5 >= 74) {
/** 74抽之后逐渐增加概率 */
tmpChance5 = 590 + (this.user[this.type].num5 - 74) * 530
} else if (this.user[this.type].num5 >= 60) {
/** 60抽之后逐渐增加概率 */
tmpChance5 = this.def.chance5 + (this.user[this.type].num5 - 50) * 40
}
}
if (this.type == 'weapon') {
tmpChance5 = this.def.chanceW5
/** 增加双黄概率 */
if (this.user.week.num == 1) {
tmpChance5 = tmpChance5 * 3
}
/** 80次都没中五星 */
if (this.user[this.type].num5 >= 80) {
tmpChance5 = 10000
} else if (this.user[this.type].num5 >= 62) {
/** 62抽后逐渐增加概率 */
tmpChance5 = tmpChance5 + (this.user[this.type].num5 - 61) * 700
} else if (this.user[this.type].num5 >= 45) {
/** 50抽后逐渐增加概率 */
tmpChance5 = tmpChance5 + (this.user[this.type].num5 - 45) * 60
} else if (this.user[this.type].num5 >= 10 && this.user[this.type].num5 <= 20) {
tmpChance5 = tmpChance5 + (this.user[this.type].num5 - 10) * 30
}
}
return tmpChance5
}
/** 获取定轨的武器 */
getBingWeapon (sortName = false) {
if (this.type != 'weapon') return false
let name = this.pool.up5[this.user[this.type].type - 1]
if (sortName) name = gsCfg.shortName(name, true)
return name
}
lotteryInfo () {
let info = `累计「${this.user[this.type].num5}抽」`
let nowFive = 0
let nowFour = 0
this.res.forEach((v, i) => {
if (v.star == 5) {
nowFive++
if (v.type == 'role') {
info = gsCfg.shortName(v.name)
} else {
info = gsCfg.shortName(v.name, true)
}
info += `${v.num}抽」`
if (v.isBigUP) info += '大保底'
if (v.isBing) info += '定轨'
}
if (v.star == 4) {
nowFour++
}
})
let poolName = `角色池:${gsCfg.shortName(this.pool.up5[0])}`
if (this.type == 'permanent') poolName = '常驻池'
let res = {
info,
nowFive,
nowFour,
poolName,
isWeapon: this.type == 'weapon',
bingWeapon: this.getBingWeapon(true),
lifeNum: this.user[this.type]?.lifeNum || 0
}
logger.debug(`[${poolName}] [五星数:${nowFive}] [${info}] [定轨:${res.lifeNum}]`)
return res
}
async saveUser () {
this.user.today.expire = this.getEnd().end4
await redis.setEx(this.key, 3600 * 24 * 14, JSON.stringify(this.user))
}
static async getStr () {
global.strr = ''
let res = await fetch('https://gist.githubusercontent.com/Le-niao/10f061fb9fe8fcfc316c10b422ed06d1/raw/Yunzai-Bot').catch(() => {})
if (res && res.text) {
let strr = await res.text() || ''
if (strr.includes('html')) strr = ''
global.strr = strr
}
}
getNow () {
return moment().format('X')
}
getEnd () {
let end = moment().endOf('day').format('X')
let end4 = 3600 * 4
if (moment().format('k') < 4) {
end4 += Number(moment().startOf('day').format('X'))
} else {
end4 += Number(end)
}
return { end, end4 }
}
getWeekEnd () {
return Number(moment().day(7).endOf('day').format('X'))
}
initFile () {
if (imgFile['刻晴']) return imgFile
let path = './plugins/genshin/resources/img/gacha/'
let character = fs.readdirSync(path + 'character/')
let weapon = fs.readdirSync(path + 'weapon/')
let nameSet = (v) => {
let name = v.split('.')
imgFile[name[0]] = v
}
character.forEach(v => nameSet(v))
weapon.forEach(v => nameSet(v))
return imgFile
}
}