koishi-plugin-arknights-card
Version:
明日方舟抽卡模拟插件 - 支持限定池、标准池抽卡模拟,包含完整的干员数据和抽卡统计功能
898 lines (892 loc) • 32.5 kB
JavaScript
;
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('明日方舟抽卡插件已加载');
});
}