UNPKG

koishi-plugin-arknights-card

Version:

明日方舟抽卡模拟插件 - 支持限定池、标准池抽卡模拟,包含完整的干员数据和抽卡统计功能

898 lines (892 loc) 32.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Config = exports.usage = exports.name = void 0; exports.apply = apply; const koishi_1 = require("koishi"); // 定义默认概率 const DEFAULT_LIMITED_RATE = 1; const DEFAULT_SIX_STAR_RATE = 2; const DEFAULT_FIVE_STAR_RATE = 12; const DEFAULT_FOUR_STAR_RATE = 45; const DEFAULT_THREE_STAR_RATE = 40; const DEFAULT_DAILY_DRAWS = 10; // 默认每日签到获得10次抽卡机会 // 预定义干员数据 const LIMITED_OPERATORS = [ '6|武者|黑泠', '6|重射手|白瑾', '6|极寒术师|霜星', '6|怪杰|新约能天使', '6|战术家|缪尔赛思', '6|哨戒铁卫|信仰搅拌机', '6|本源铁卫|余', '6|驭械术师|荒芜拉普兰德', '6|投掷手|维什戴尔', '6|扩散术师|玛露西尔', '6|处决者|弑君者', '6|撼地者|佩佩', '6|吟游者|魔王', '6|陷阱师|艾拉', '6|守护者|黍', '6|巫役|塑心', '6|无畏者|止颂', '6|行医|纯烬艾雅法拉', '6|护佑者|淬羽赫默', '6|处决者|缄默德克萨斯', '6|处决者|麒麟R夜刀', '6|斗士|重岳', '6|扩散术师|夕', '6|战术家|伺夜', '6|强攻手|百炼嘉维尔', '6|傀儡师|归溟幽灵鲨', '6|疗养师|流明', '6|召唤师|令', '6|无畏者|耀骑士临光', '6|散射手|假日威龙陈', '6|吟游者|浊心斯卡蒂', '6|钩索师|歌蕾蒂娅', '6|速射手|灰烬', '6|投掷手|迷迭香', '6|炮手|W', '6|铁卫|年' ]; const SIX_STAR_OPERATORS = [ '6|巫役|酒神', '6|神射手|蕾缪安', '6|链愈师|Mon3tr', '6|塑灵术师|死芒', '6|收割者|隐德来希', '6|本源术师|烛煌', '6|炼金师|引星棘刺', '6|尖兵|忍冬', '6|术战者|维娜维多利亚', '6|回环射手|娜仁图雅', '6|本源术师|妮芙', '6|重剑手|乌尔比安', '6|中坚术师|逻各斯', '6|伏击客|阿斯卡纶', '6|武者|左乐', '6|猎手|莱伊', '6|剑豪|锏', '6|术战者|薇薇安娜', '6|重剑手|赫德雷', '6|哨戒铁卫|涤火杰西卡', '6|行商|琳琅诗怀雅', '6|攻城手|提丰', '6|收割者|圣约送葬人', '6|中坚术师|霍尔海雅', '6|情报官|伊内丝', '6|领主|仇白', '6|阵法术师|林', '6|咒愈师|焰影苇草', '6|不屈者|斥罪', '6|工匠|白铁', '6|武者|赫拉格', '6|扩散术师|莫斯提马', '6|召唤师|麦哲伦', '6|怪杰|阿', '6|攻城手|煌', '6|中坚术师|刻俄柏', '6|处决者|傀影', '6|冲锋手|风笛', '6|推击手|温蒂', '6|攻城手|早露', '6|滞凝师|铃兰', '6|领主|棘刺', '6|术战者|史尔特尔', '6|决战者|森蚺', '6|守护者|瑕光', '6|不屈者|泥岩', '6|斗士|山', '6|速射手|空弦', '6|尖兵|嵯峨', '6|链术师|异客', '6|医师|凯尔希', '6|阵法术师|卡涅利安', '6|教官|帕拉斯', '6|伏击客|水月', '6|执旗手|琴柳', '6|神射手|远牙', '6|尖兵|焰尾', '6|削弱者|灵知', '6|行商|老鲤', '6|驭械术师|澄闪', '6|炮手|菲亚梅塔', '6|要塞|号角', '6|剑豪|艾丽妮', '6|秘术师|黑键', '6|陷阱师|多萝西', '6|重射手|鸿雪', '6|解放者|玛恩纳', '6|速射手|能天使', '6|轰击术师|伊芙利特', '6|中坚术师|艾雅法拉', '6|尖兵|推进之王', '6|凝滞师|安洁莉娜', '6|医师|闪灵', '6|群愈师|夜莺', '6|铁卫|星熊', '6|守护者|塞雷娅', '6|领主|银灰', '6|无畏者|斯卡蒂', '6|剑豪|陈', '6|重射手|黑' ]; const FIVE_STAR_OPERATORS = [ '5|异格职业|阿米娅', '5|本源术师|克里斯汀', '5|本源铁卫|聆音', '5|巡空者|蒂比', '5|工匠|阿兰娜', '5|陷阱师|钼铅', '5|回环射手|水灯心', '5|疗养师|诺威尔', '5|指挥官|寻澜', '5|护佑者|行箸', '5|塑灵术师|特克诺', '5|群愈师|瑰盐', '5|行商|裁度', '5|本源铁卫|菲莱', '5|巫役|波卜', '5|工匠|凯瑟琳', '5|无畏者|莱欧斯', '5|情报官|齐尔查克', '5|守护者|森西', '5|召唤师|衡沙', '5|链愈师|莎草', '5|炼金师|锡人', '5|战术家|渡桥', '5|削弱者|海霓', '5|哨戒铁卫|深巡', '5|冲锋手|历阵锐枪芬', '5|轰击术师|阿罗玛', '5|撼地者|奥达', '5|教官|医生', '5|傀儡师|双月', '5|强攻手|导火索', '5|尖兵|红隼', '5|滞凝师|小满', '5|执旗手|万顷', '5|本源术师|温米', '5|领主|烈夏', '5|行医|哈洛德', '5|守护者|深律', '5|本源术师|折光', '5|咒愈师|刺玫', '5|秘术师|戴菲恩', '5|钩索师|杏仁', '5|猎手|冰酿', '5|尖兵|青枳', '5|教官|苍苔', '5|巫役|凛视', '5|扩散术师|寒檀', '5|怪杰|空构', '5|速射手|隐现', '5|重射手|枚拉', '5|决战者|洋灰', '5|无畏者|摩根', '5|武者|火龙S黑角', '5|重剑手|铎铃', '5|要塞|火哨', '5|炮手|截云', '5|秘术师|和弦', '5|情报官|谜图', '5|中坚术师|雪绒', '5|神射手|子月', '5|链愈师|明椒', '5|斗士|达格达', '5|凝滞师|但书', '5|收割者|海沫', '5|情报官|晓歌', '5|驭械术师|至简', '5|投掷手|承曦格雷伊', '5|链术师|星源', '5|咒愈师|曜尘芙蓉', '5|驭法铁卫|车尼尔', '5|攻城手|埃托拉', '5|驭械术师|洛洛', '5|工匠|掠风', '5|吟游者|海蒂', '5|傀儡师|风丸', '5|推击手|见行者', '5|战术家|夜半', '5|护佑者|夏栎', '5|速射手|寒芒克洛丝', '5|护佑者|九色鹿', '5|驭法铁卫|幕落', '5|驭械术师|耶拉', '5|决战者|极光', '5|轰击术师|蚀清', '5|冲锋手|野鬃', '5|行医|蜜莓', '5|要塞|灰豪', '5|行医|桑椹', '5|收割者|羽毛笔', '5|伏击客|绮良', '5|解放者|龙舌兰', '5|武者|赤冬', '5|傀儡师|贝娜', '5|攻城手|熔泉', '5|陷阱师|霜华', '5|铁卫|暴雨', '5|剑豪|战车', '5|哨戒铁卫|闪击', '5|行商|乌有', '5|医师|图耶', '5|扩散术师|炎狱炎熔', '5|秘术师|爱丽丝', '5|处决者|卡夫卡', '5|陷阱师|罗宾', '5|散射手|奥斯塔', '5|疗养师|絮雨', '5|速射手|四月', '5|教官|鞭刃', '5|阵法术师|薄绿', '5|斗士|燧石', '5|中坚术师|特米米', '5|尖兵|贾维', '5|神射手|安哲拉', '5|阵法术师|蜜蜡', '5|召唤师|稀音', '5|领主|断崖', '5|扩散术师|莱恩哈特', '5|医师|亚叶', '5|护佑者|月禾', '5|中坚术师|苦艾', '5|驭法铁卫|石棉', '5|执旗手|极境', '5|削弱者|巫恋', '5|术战者|铸铁', '5|炮手|慑砂', '5|剑豪|柏喙', '5|链术师|惊蛰', '5|守护者|吽', '5|钩索师|雪雉', '5|速射手|灰喉', '5|冲锋手|苇草', '5|强攻手|布洛卡', '5|铁卫|拜松', '5|处决者|槐琥', '5|群愈师|微风', '5|无畏者|炎客', '5|术战者|星极', '5|散射手|送葬人', '5|疗养师|锡兰', '5|滞凝师|格劳克斯', '5|冲锋手|格拉尼', '5|教官|诗怀雅', '5|强攻手|暴行', '5|中坚术师|夜魔', '5|伏击客|狮蝎', '5|推击手|食铁兽', '5|凝滞师|真理', '5|吟游者|空', '5|削弱者|初雪', '5|钩索师|崖心', '5|神射手|守林人', '5|重射手|普罗旺斯', '5|不屈者|火神', '5|铁卫|可颂', '5|处决者|红', '5|哨戒铁卫|雷蛇', '5|守护者|临光', '5|医师|华法琳', '5|医师|赫默', '5|扩散术师|天火', '5|召唤师|梅尔', '5|速射手|百金', '5|速射手|蓝毒', '5|领主|拉普兰德', '5|强攻手|幽灵鲨', '5|斗士|因陀罗', '5|炮手|陨星', '5|无畏者|芙兰卡', '5|尖兵|德克萨斯', '5|尖兵|凛冬', '5|群愈师|白面鸮' ]; const FOUR_STAR_OPERATORS = [ '4|巡空者|云迹', '4|解放者|骋风', '4|不屈者|露托', '4|回环射手|跃跃', '4|收割者|休谟斯', '4|傀儡师|唯狄', '4|重剑手|石英', '4|攻城手|铅踝', '4|领主|罗小黑', '4|链术师|布丁', '4|行医|褐果', '4|秘术师|深靛', '4|工匠|罗比菈塔', '4|战术家|豆苗', '4|散射手|松果', '4|铁卫|泡泡', '4|斗士|杰克', '4|领主|芳汀', '4|驭械术师|卡达', '4|重射手|酸糖', '4|剑豪|刻刀', '4|行商|孑', '4|无畏者|断罪者', '4|滞凝师|波登可', '4|武者|宴', '4|神射手|安比尔', '4|疗养师|清流', '4|速射手|梅', '4|伏击客|伊桑', '4|执旗手|桃金娘', '4|驭法铁卫|坚雷', '4|医师|苏苏洛', '4|扩散术师|格雷伊', '4|斗士|猎蜂', '4|推击手|阿晓', '4|凝滞师|地灵', '4|召唤师|深海色', '4|守护者|古米', '4|铁卫|角峰', '4|铁卫|蛇屠箱', '4|医师|嘉维尔', '4|群愈师|调香师', '4|医师|末药', '4|钩索师|暗索', '4|术战者|慕斯', '4|处决者|砾', '4|领主|霜叶', '4|强攻手|艾丝黛尔', '4|无畏者|缠丸' ]; const THREE_STAR_OPERATORS = [ '3|守护者|斑点', '3|强攻手|泡普卡', '3|领主|月见夜', '3|炮手|空爆', '3|中坚术师|史都华德', '3|凝滞师|梓兰', '3|医师|安赛尔', '3|医师|芙蓉', '3|扩散术师|岩熔', '3|速射手|安德切尔', '3|速射手|史都华德', '3|铁卫|米格鲁', '3|无畏者|玫兰莎', '3|铁卫|卡缇', '3|冲锋手|翎羽', '3|尖兵|香草', '3|尖兵|芬' ]; // 插件主类 exports.name = 'arknights-card'; exports.usage = ` # 明日方舟抽卡插件 模拟明日方舟抽卡系统,支持单抽和十连。每日签到可获得${DEFAULT_DAILY_DRAWS}次抽卡机会。 ## 指令 - \`签到\` - 每日签到,获得${DEFAULT_DAILY_DRAWS}次抽卡机会 - \`单抽\` - 进行一次抽卡(消耗1次抽卡机会) - \`十连\` - 进行十次抽卡(消耗10次抽卡机会) - \`查询\` - 查询剩余抽卡次数 ## 概率设置 - 限定干员: ${DEFAULT_LIMITED_RATE}% - 六星干员: ${DEFAULT_SIX_STAR_RATE}% - 五星干员: ${DEFAULT_FIVE_STAR_RATE}% - 四星干员: ${DEFAULT_FOUR_STAR_RATE}% - 三星干员: ${DEFAULT_THREE_STAR_RATE}% `; // 配置Schema exports.Config = koishi_1.Schema.object({ limitedRate: koishi_1.Schema.number() .default(DEFAULT_LIMITED_RATE) .description('限定干员概率 (%)'), sixStarRate: koishi_1.Schema.number() .default(DEFAULT_SIX_STAR_RATE) .description('六星干员概率 (%)'), fiveStarRate: koishi_1.Schema.number() .default(DEFAULT_FIVE_STAR_RATE) .description('五星干员概率 (%)'), fourStarRate: koishi_1.Schema.number() .default(DEFAULT_FOUR_STAR_RATE) .description('四星干员概率 (%)'), threeStarRate: koishi_1.Schema.number() .default(DEFAULT_THREE_STAR_RATE) .description('三星干员概率 (%)'), dailyDraws: koishi_1.Schema.number() .default(DEFAULT_DAILY_DRAWS) .description('每日签到获得的抽卡次数'), limitedOperators: koishi_1.Schema.array(koishi_1.Schema.string()) .default(LIMITED_OPERATORS) .description('限定干员数据列表 (格式: "稀有度|职业|名称")'), sixStarOperators: koishi_1.Schema.array(koishi_1.Schema.string()) .default(SIX_STAR_OPERATORS) .description('六星干员数据列表 (格式: "稀有度|职业|名称")'), fiveStarOperators: koishi_1.Schema.array(koishi_1.Schema.string()) .default(FIVE_STAR_OPERATORS) .description('五星干员数据列表 (格式: "稀有度|职业|名称")'), fourStarOperators: koishi_1.Schema.array(koishi_1.Schema.string()) .default(FOUR_STAR_OPERATORS) .description('四星干员数据列表 (格式: "稀有度|职业|名称")'), threeStarOperators: koishi_1.Schema.array(koishi_1.Schema.string()) .default(THREE_STAR_OPERATORS) .description('三星干员数据列表 (格式: "稀有度|职业|名称")') }); // 这个接口已经在顶层定义,这里不需要重复定义 /** * 解析干员数据字符串为干员对象 * @param operatorString 格式为 "稀有度|职业|名称" 的字符串 * @param isLimited 是否为限定干员 * @returns 解析后的干员对象 */ function parseOperator(operatorString, isLimited = false) { // 分割字符串获取干员信息 const parts = operatorString.split('|'); if (parts.length !== 3) { throw new Error(`Invalid operator string format: ${operatorString}`); } const [rarityStr, operatorClass, name] = parts; const rarity = parseInt(rarityStr, 10); if (isNaN(rarity)) { throw new Error(`Invalid rarity value: ${rarityStr}`); } if (isLimited) { // 如果是限定干员,返回LimitedOperatorData类型 return { class: operatorClass, name: name, rarity: rarity, limited: true }; } else { // 普通干员,返回OperatorData类型 return { class: operatorClass, name: name, rarity: rarity }; } } // 插件应用函数 function apply(ctx, config) { // 声明对数据库服务的依赖 ctx.inject(['database'], (ctx) => { // 数据库表结构已在顶层声明 // 扩展数据库 - 用户表 ctx.database.extend('gacha_user', { // 用户ID,作为主键的一部分 id: { type: 'string', length: 255 }, // 平台,作为主键的一部分 platform: { type: 'string', length: 50 }, // 剩余抽卡次数 remainingDraws: { type: 'integer', initial: 0 }, // 上次签到日期 lastCheckIn: { type: 'string', length: 10, initial: '1970-01-01' } }, { primary: ['id', 'platform'], unique: [['id', 'platform']] }); // 扩展数据库 - 抽卡历史记录表 ctx.database.extend('gacha_history', { // 使用unsigned类型作为ID(数字类型) id: 'unsigned', // 用户ID userId: { type: 'string', length: 255 }, // 平台 platform: { type: 'string', length: 50 }, // 干员名称 operatorName: { type: 'string', length: 100 }, // 干员职业 operatorClass: { type: 'string', length: 50 }, // 稀有度 rarity: { type: 'integer', initial: 3 }, // 是否为限定干员 isLimited: { type: 'boolean', initial: false }, // 抽卡时间戳 timestamp: { type: 'integer', initial: 0 // 将在创建记录时手动设置 } }, { primary: 'id', // 明确设置主键 autoInc: true, // 明确设置自增 indexes: [ ['userId', 'platform'], ['timestamp'] ] }); // 获取用户数据 async function getUserData(userId, platform) { // 查询用户数据 const userData = await ctx.database.get('gacha_user', { id: userId, platform: platform }); // 如果用户不存在,创建新用户 if (!userData.length) { const newUser = { id: userId, platform: platform, remainingDraws: 0, lastCheckIn: '1970-01-01' }; // 创建用户记录 await ctx.database.create('gacha_user', newUser); return newUser; } // 返回现有用户数据 return userData[0]; } // 更新用户数据 async function updateUserData(userData) { // 更新用户的抽卡次数和签到日期 await ctx.database.set('gacha_user', { id: userData.id, platform: userData.platform }, { remainingDraws: userData.remainingDraws, lastCheckIn: userData.lastCheckIn }); } // 记录抽卡历史 async function recordGachaHistory(userId, platform, operator, rarity) { const isLimited = 'limited' in operator && operator.limited === true; const timestamp = Math.floor(Date.now() / 1000); try { // 不提供id字段,让数据库自动生成 await ctx.database.create('gacha_history', { // 完全省略id字段 userId, platform, operatorName: operator.name, operatorClass: operator.class, rarity, isLimited: isLimited || rarity === 7, timestamp }); ctx.logger('arknights-card').success(`成功记录抽卡历史: ${operator.name} (${rarity}星)`); } catch (error) { ctx.logger('arknights-card').error(`记录抽卡历史失败: ${error.message}`); } } // 获取用户抽卡历史 async function getUserGachaHistory(userId, platform, limit = 10) { const history = await ctx.database.get('gacha_history', { userId, platform }, { sort: { id: 'desc' }, limit }); return history; } // 获取用户抽卡统计 async function getUserGachaStats(userId, platform) { const history = await ctx.database.get('gacha_history', { userId, platform }); const total = history.length; const limitedCount = history.filter(record => record.isLimited).length; const sixStarCount = history.filter(record => record.rarity === 6).length; const fiveStarCount = history.filter(record => record.rarity === 5).length; const fourStarCount = history.filter(record => record.rarity === 4).length; const threeStarCount = history.filter(record => record.rarity === 3).length; return { total, limitedCount, sixStarCount, fiveStarCount, fourStarCount, threeStarCount }; } // 检查今天是否已经签到 function isCheckedInToday(lastCheckIn) { const today = new Date().toISOString().split('T')[0]; return lastCheckIn === today; } // 生成星星显示 function getStars(rarity) { const fullStar = '★'; const emptyStar = '☆'; const maxStars = 6; return fullStar.repeat(rarity) + emptyStar.repeat(maxStars - rarity); } /** * 执行一次抽卡操作 * @returns {GachaResult} 抽卡结果,包含干员信息和稀有度 */ function gacha() { // 生成0-100的随机数用于判定稀有度 const random = Math.random() * 100; // 默认为3星 let rarity = 3; // 默认干员,避免null let operator = { class: '近卫', name: '预设干员', rarity: 3 }; // 计算各稀有度的累积概率 const limitedProb = config.limitedRate; const sixStarProb = limitedProb + config.sixStarRate; const fiveStarProb = sixStarProb + config.fiveStarRate; const fourStarProb = fiveStarProb + config.fourStarRate; // 根据随机数判定稀有度并抽取干员 if (random < limitedProb) { // 抽到限定干员 const limitedOperators = config.limitedOperators.map(op => parseOperator(op, true)); if (limitedOperators.length > 0) { const index = Math.floor(Math.random() * limitedOperators.length); operator = limitedOperators[index]; rarity = 7; // 用7表示限定 } } else if (random < sixStarProb) { // 抽到六星干员 const sixStarOperators = config.sixStarOperators.map(op => parseOperator(op)); if (sixStarOperators.length > 0) { const index = Math.floor(Math.random() * sixStarOperators.length); operator = sixStarOperators[index]; rarity = 6; } } else if (random < fiveStarProb) { // 抽到五星干员 const fiveStarOperators = config.fiveStarOperators.map(op => parseOperator(op)); if (fiveStarOperators.length > 0) { const index = Math.floor(Math.random() * fiveStarOperators.length); operator = fiveStarOperators[index]; rarity = 5; } } else if (random < fourStarProb) { // 抽到四星干员 const fourStarOperators = config.fourStarOperators.map(op => parseOperator(op)); if (fourStarOperators.length > 0) { const index = Math.floor(Math.random() * fourStarOperators.length); operator = fourStarOperators[index]; rarity = 4; } } else { // 抽到三星干员 const threeStarOperators = config.threeStarOperators.map(op => parseOperator(op)); if (threeStarOperators.length > 0) { const index = Math.floor(Math.random() * threeStarOperators.length); operator = threeStarOperators[index]; rarity = 3; } } let result = ''; if (rarity === 7) { // 限定干员不使用getStars函数,直接显示【限定】标签 result = `【限定】${operator.class} ${operator.name}`; } else { // 只为3-6星干员生成星星显示 const stars = getStars(rarity); result = `${stars} ${operator.class} ${operator.name}`; } // 返回完整的抽卡结果对象,确保与GachaResult接口一致 return { result, rarity, operator }; } // 注册查询抽卡历史指令 ctx.command('抽卡历史', '查询最近的抽卡记录') .option('limit', '-l <number:number> 显示记录数量', { fallback: 10 }) .action(async ({ session, options }) => { if (!session?.userId || !session?.platform) { return '无法识别用户信息'; } const limit = Math.min(options?.limit ?? 10, 50); // 限制最多显示50条记录,默认显示10条 const history = await getUserGachaHistory(session.userId, session.platform, limit); if (history.length === 0) { return '博士,您还没有抽卡记录'; } const nickname = session.username || '博士'; let message = `${nickname}的抽卡历史记录(最近${history.length}条):\n`; message += '━━━━━━\n'; history.forEach((record, index) => { let displayText = ''; if (record.isLimited) { // 限定干员不显示星星,只显示【限定】标签 displayText = `【限定】${record.operatorClass} ${record.operatorName}`; } else { // 只为3-6星干员生成星星显示 const stars = getStars(record.rarity); displayText = `${stars} ${record.operatorClass} ${record.operatorName}`; } const date = new Date(record.timestamp).toLocaleString('zh-CN', { month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' }); message += `${index + 1}. ${displayText} (${date})\n`; }); message += '━━━━━━'; return message; }); // 注册抽卡统计指令 ctx.command('抽卡统计', '查询抽卡统计数据') .action(async ({ session }) => { if (!session?.userId || !session?.platform) { return '无法识别用户信息'; } const stats = await getUserGachaStats(session.userId, session.platform); if (stats.total === 0) { return '博士,您还没有抽卡记录'; } const nickname = session.username || '博士'; let message = `${nickname}的抽卡统计:\n`; message += '━━━━━━\n'; message += `总抽卡次数:${stats.total}次\n`; if (stats.limitedCount > 0) { const limitedRate = (stats.limitedCount / stats.total * 100).toFixed(2); message += `✨限定干员:${stats.limitedCount}个 (${limitedRate}%)\n`; } if (stats.sixStarCount > 0) { const sixStarRate = (stats.sixStarCount / stats.total * 100).toFixed(2); message += `🌟六星干员:${stats.sixStarCount}个 (${sixStarRate}%)\n`; } const fiveStarRate = (stats.fiveStarCount / stats.total * 100).toFixed(2); const fourStarRate = (stats.fourStarCount / stats.total * 100).toFixed(2); const threeStarRate = (stats.threeStarCount / stats.total * 100).toFixed(2); message += `五星干员:${stats.fiveStarCount}个 (${fiveStarRate}%)\n`; message += `四星干员:${stats.fourStarCount}个 (${fourStarRate}%)\n`; message += `三星干员:${stats.threeStarCount}个 (${threeStarRate}%)\n`; message += '━━━━━━'; return message; }); // 注册签到指令 ctx.command('签到', '每日签到获取抽卡次数') .action(async ({ session }) => { if (!session?.userId || !session?.platform) { return '无法识别用户信息'; } const userData = await getUserData(session.userId, session.platform); if (isCheckedInToday(userData.lastCheckIn)) { return '博士,您今天已经签到过了'; } userData.remainingDraws += config.dailyDraws; userData.lastCheckIn = new Date().toISOString().split('T')[0]; await updateUserData(userData); return `签到成功!获得${config.dailyDraws}次抽卡机会,当前剩余${userData.remainingDraws}次`; }); // 注册查询指令 ctx.command('查询', '查询剩余抽卡次数') .action(async ({ session }) => { if (!session?.userId || !session?.platform) { return '无法识别用户信息'; } const userData = await getUserData(session.userId, session.platform); return `博士,您当前剩余${userData.remainingDraws}次抽卡机会`; }); // 注册单抽指令 ctx.command('单抽', '明日方舟干员单次抽取') .action(async ({ session }) => { if (!session?.userId || !session?.platform) { return '无法识别用户信息'; } const userData = await getUserData(session.userId, session.platform); if (userData.remainingDraws < 1) { return '博士,您的抽卡次数不足,请先签到获取抽卡机会'; } userData.remainingDraws -= 1; await updateUserData(userData); const gachaResult = gacha(); // 记录抽卡历史 await recordGachaHistory(session.userId, session.platform, gachaResult.operator, gachaResult.rarity); // 构建美化的结果消息 const nickname = session.username || '博士'; let message = `${nickname}\n本次寻访获得的干员:\n`; message += '━━━━━━\n'; message += gachaResult.result + '\n'; message += '━━━━━━\n'; message += `剩余抽卡次数:${userData.remainingDraws}`; return message; }); // 注册十连指令 ctx.command('十连', '明日方舟干员十连抽取') .action(async ({ session }) => { if (!session?.userId || !session?.platform) { return '无法识别用户信息'; } const userData = await getUserData(session.userId, session.platform); if (userData.remainingDraws < 10) { return `博士,您的抽卡次数不足,当前剩余${userData.remainingDraws}次,请先签到获取抽卡机会`; } userData.remainingDraws -= 10; await updateUserData(userData); let results = []; let rarities = []; for (let i = 0; i < 10; i++) { const gachaResult = gacha(); results.push(gachaResult.result); rarities.push(gachaResult.rarity); // 记录抽卡历史 await recordGachaHistory(session.userId, session.platform, gachaResult.operator, gachaResult.rarity); } // 统计各稀有度数量 const limitedCount = rarities.filter(r => r === 7).length; const sixStarCount = rarities.filter(r => r === 6).length; const fiveStarCount = rarities.filter(r => r === 5).length; const fourStarCount = rarities.filter(r => r === 4).length; const threeStarCount = rarities.filter(r => r === 3).length; // 构建美化的结果消息 const nickname = session.username || '博士'; let message = `${nickname}\n本次寻访获得的干员:\n`; message += '━━━━━━\n'; message += results.join('\n'); message += '\n━━━━━━\n'; // 添加统计信息 if (limitedCount > 0) { message += `✨限定干员:${limitedCount}个\n`; } if (sixStarCount > 0) { message += `🌟六星干员:${sixStarCount}个\n`; } message += `五星干员:${fiveStarCount}个\n`; message += `四星干员:${fourStarCount}个\n`; message += `三星干员:${threeStarCount}个\n`; message += `剩余抽卡次数:${userData.remainingDraws}`; return message; }); // 日志输出 ctx.logger('arknights-card').info('明日方舟抽卡插件已加载'); }); }