koishi-plugin-interactive
Version:
多功能互动型QQ机器人插件,支持猜数字、每日签到、幸运抽奖、积分商店、排行榜、成就系统、个人资料、随机互动、每日提醒等功能
1,438 lines • 126 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Config = exports.using = exports.name = void 0;
exports.apply = apply;
const koishi_1 = require("koishi");
// 默认商店配置 (增加技能券)
const defaultShopItems = [
{
id: 'double_card',
name: '双倍积分卡',
description: '下次签到获得双倍积分',
price: 50,
storable: false,
effect: (user) => {
user.hasDoubleCard = true;
return '购买成功!下次签到将获得双倍积分!';
}
},
{
id: 'lottery_ticket',
name: '免费抽奖券',
description: '免费抽奖一次',
price: 40,
storable: false,
effect: (user) => {
user.freeLotteryCount += 1;
return '购买成功!获得一张免费抽奖券!';
}
},
{
id: 'hint_token',
name: '提示令牌',
description: '猜数字/答题/猜歌名时获得提示',
price: 30,
storable: true
},
{
id: 'lucky_charm',
name: '幸运护符',
description: '增加抽中高级奖品的概率',
price: 100,
storable: false,
effect: (user) => {
user.luckyCharmCount += 1;
return '购买成功!获得幸运护符,下次抽奖时生效!';
}
},
{
id: 'coffee',
name: '提神咖啡',
description: '使用后恢复5次每日使用次数',
price: 80,
storable: true
},
{
id: 'exp_card',
name: '经验卡',
description: '使用后游戏积分奖励+20%',
price: 120,
storable: true
},
// 新增技能券
{
id: 'skill_ticket',
name: '技能券',
description: '使用后获得1个技能碎片',
price: 10000,
storable: true,
effect: (user) => {
user.skillFragments += 1;
return '使用成功!获得1个技能碎片';
}
}
];
exports.name = 'interactive';
exports.using = ['database', 'ffmpeg', 'silk'];
// 配置Schema
exports.Config = koishi_1.Schema.object({
maxGuessNumber: koishi_1.Schema.number()
.default(100)
.min(10).max(1000)
.description('猜数字游戏的最大数值'),
signReward: koishi_1.Schema.number()
.default(10)
.min(5).max(100)
.description('每日签到基础奖励积分'),
lotteryItems: koishi_1.Schema.array(koishi_1.Schema.string())
.default(['SSR·神秘大奖', 'SR·高级道具', 'R·普通道具', 'N·谢谢参与'])
.description('抽奖物品列表'),
replyProbability: koishi_1.Schema.percent()
.default(0.3)
.description('随机回复概率'),
coolDown: koishi_1.Schema.number()
.default(5000)
.min(1000).max(60000)
.description('命令冷却时间(ms)'),
dailyLimit: koishi_1.Schema.number()
.default(50)
.min(10).max(200)
.description('每日命令使用上限'),
quizRewardBase: koishi_1.Schema.number()
.default(15)
.min(5).max(30)
.description('答题基础奖励积分'),
shopItems: koishi_1.Schema.array(koishi_1.Schema.object({
id: koishi_1.Schema.string().required(),
name: koishi_1.Schema.string().required(),
description: koishi_1.Schema.string().required(),
price: koishi_1.Schema.number().min(1),
storable: koishi_1.Schema.boolean().default(false)
}))
.default(defaultShopItems)
.description('商店商品配置')
});
// 成就系统配置
const ACHIEVEMENTS = [
{
id: 'first_blood',
name: '初出茅庐',
description: '赢得第一场游戏',
condition: (user) => user.gamesWon >= 1,
reward: 500
},
{
id: 'sign_master',
name: '签到达人',
description: '连续签到7天',
condition: (user) => user.consecutiveDays >= 7,
reward: 1000
},
{
id: 'millionaire',
name: '积分大亨',
description: '总积分达到500',
condition: (user) => user.points >= 500,
reward: 2000
},
{
id: 'game_addict',
name: '游戏沉迷',
description: '参与20场游戏',
condition: (user) => user.gamesPlayed >= 20,
reward: 1500
},
{
id: 'lottery_king',
name: '抽卡之王',
description: '抽中5次SSR大奖',
condition: (user) => user.ssrCount >= 5,
reward: 3000
},
{
id: 'shopper',
name: '购物狂',
description: '在商店消费1000积分',
condition: (user) => user.totalSpent >= 1000,
reward: 2500
},
{
id: 'robber',
name: '江洋大盗',
description: '成功抢劫10次',
condition: (user) => user.robberySuccess >= 10,
reward: 3000
},
{
id: 'red_envelope_master',
name: '红包达人',
description: '发送10个红包',
condition: (user) => user.redEnvelopesSent >= 10,
reward: 2000
},
{
id: 'quiz_master',
name: '答题达人',
description: '答对50道题',
condition: (user) => user.quizCorrect >= 50,
reward: 1500
},
{
id: 'farmer_expert',
name: '农场专家',
description: '收获100次作物或动物',
condition: (user) => (user.farmLand?.length || 0) + (user.farmAnimals?.length || 0) >= 100,
reward: 2000
},
{
id: 'intimacy_max',
name: '永恒誓言',
description: '亲密值达到1000点',
condition: (user) => user.intimacy >= 1000,
reward: 30000
},
// 新增公司成就
{
id: 'company_tycoon',
name: '商业大亨',
description: '公司等级达到5级',
condition: (user) => user.companyLevel >= 5,
reward: 50000
},
{
id: 'skill_master',
name: '技能大师',
description: '技能等级达到10级',
condition: (user) => user.skillLevel >= 10,
reward: 40000
},
// 新增猜歌名成就
{
id: 'music_master',
name: '音乐达人',
description: '猜对50首歌',
condition: (user) => user.musicCorrect >= 50,
reward: 3000
},
// 新增养牛成就
{
id: 'cow_master',
name: '养牛专家',
description: '牛牛亲密度达到1000点',
condition: (user) => !!user.cow && user.cow.intimacy >= 1000,
reward: 40000
}
];
// 新增关系类型常量
const RELATIONSHIP_TYPES = {
lover: '恋人',
friend: '闺蜜',
buddy: '死党',
bro: '基友'
};
// 新增农场配置
const FARM_CONFIG = {
crops: [
{ id: 'wheat', name: '小麦', growthTime: 30 * 60 * 1000, reward: 20 },
{ id: 'corn', name: '玉米', growthTime: 60 * 60 * 1000, reward: 50 },
{ id: 'carrot', name: '胡萝卜', growthTime: 2 * 60 * 60 * 1000, reward: 100 },
{ id: 'strawberry', name: '草莓', growthTime: 4 * 60 * 60 * 1000, reward: 200 }
],
animals: [
{ id: 'chicken', name: '小鸡', growthTime: 60 * 60 * 1000, reward: 30 },
{ id: 'cow', name: '奶牛', growthTime: 3 * 60 * 60 * 1000, reward: 100 },
{ id: 'pig', name: '小猪', growthTime: 6 * 60 * 60 * 1000, reward: 200 },
{ id: 'sheep', name: '小羊', growthTime: 8 * 60 * 60 * 1000, reward: 300 }
],
tools: [
{ id: 'water_can', name: '高级浇水壶', price: 200, effect: '作物生长时间减少20%' },
{ id: 'feed_machine', name: '自动喂食器', price: 300, effect: '动物生长时间减少25%' },
{ id: 'fertilizer', name: '超级肥料', price: 500, effect: '作物产量增加50%' },
{ id: 'barn_upgrade', name: '谷仓升级', price: 800, effect: '农田和动物栏上限+1' }
],
intimacyLevels: [
{ level: 1, intimacy: 0, multiplier: 1, name: '初识' },
{ level: 2, intimacy: 100, multiplier: 1.5, name: '熟络' },
{ level: 3, intimacy: 300, multiplier: 2, name: '亲密' },
{ level: 4, intimacy: 600, multiplier: 2.5, name: '挚爱' },
{ level: 5, intimacy: 1000, multiplier: 3, name: '永恒' }
]
};
// 猜歌名歌曲列表
const SONG_LIST = [
"爱河", "把回忆拼好给你emo", "把回忆拼好给你", "白月光与朱砂痣", "百花香",
"叱咤风云", "春泥", "赐我", "盗将行", "第57次取消发送", "多远都要在一起",
"飞", "隔岸", "孤城", "红色高跟鞋", "纪念", "寂寞烟火", "戒烟", "惊雷",
"精卫", "快乐", "浪人琵琶", "老男孩", "恋爱循环", "芒种", "梦的光点",
"迷失幻境", "命中注定不能靠近", "莫愁乡藿藿版", "你从未离去", "年轮",
"偏向", "牵丝戏", "桥边姑娘", "青衣", "清空", "清明上河图", "缺氧",
"时间过客", "世界那么大还是遇见你", "死心塌地去爱你", "踏浪", "叹云兮",
"天若有情", "出山藿藿版", "我不信你不惭愧", "夏天的风", "笑纳", "学猫叫",
"一个人", "一路生花", "又活了一天", "雨爱", "谪仙", "doll", "MOM", "彩虹",
"大东北是我的家乡", "金玉良缘", "绝世舞姬", "绿色", "你扶琵琶奏琴弦",
"青春不打烊", "热爱105度的你", "雅俗共赏", "众里寻他", "三国恋", "兰亭序",
"兰亭序粤语", "燕无歇", "心如止水", "室内系的TrackMaker", "红昭愿",
"终会与你同行", "起风了", "九九八十一", "恰逢那年你明媚", "群青", "游京",
"死别", "如果在遇到爱的人", "四季予你", "沈园外", "Lemon", "烟火易冷",
"爱情专属权", "是想你的声音啊", "鹿befree", "失控", "一点归鸿", "暖暖",
"Ringring", "无人", "探故知", "难生恨", "美丽的神话", "九九八十一温柔",
"猜不透", "爱情讯息", "凑热闹"
];
// 养牛系统配置
const COW_CONFIG = {
// 亲密度等级
intimacyLevels: [
{ level: 1, intimacy: 0, name: '陌生' },
{ level: 2, intimacy: 100, name: '熟悉' },
{ level: 3, intimacy: 300, name: '友好' },
{ level: 4, intimacy: 600, name: '亲密' },
{ level: 5, intimacy: 1000, name: '家人' }
],
// 操作冷却时间 (毫秒)
cooldowns: {
feed: 30 * 60 * 1000, // 30分钟
clean: 60 * 60 * 1000, // 60分钟
play: 90 * 60 * 1000, // 90分钟
plow: 30 * 60 * 1000, // 30分钟
milk: 60 * 60 * 1000, // 60分钟
grind: 90 * 60 * 1000 // 90分钟
},
// 操作增加的亲密度
intimacyGains: {
feed: 10,
clean: 20,
play: 30
},
// 操作获得的积分奖励
rewards: {
plow: 1000, // 基础奖励
milk: 2000,
grind: 3000
}
};
// 公司配置默认值
const COMPANY_CONFIG = {
registerCost: 50000,
levelUpCost: 50000,
workRewardBase: 500,
taxRate: 0.2 // 默认税率20%
};
function apply(ctx, config) {
// 创建用户数据表(添加新字段)
ctx.model.extend('interactive_users', {
id: { type: 'char', length: 50 },
platform: { type: 'char', length: 50 },
points: { type: 'unsigned', initial: 0 },
lastSign: { type: 'char', length: 20 },
consecutiveDays: { type: 'unsigned', initial: 0 },
totalSignDays: { type: 'unsigned', initial: 0 },
gamesPlayed: { type: 'unsigned', initial: 0 },
gamesWon: { type: 'unsigned', initial: 0 },
achievements: { type: 'json', initial: [] },
hasDoubleCard: { type: 'boolean', initial: false },
freeLotteryCount: { type: 'unsigned', initial: 0 },
hintTokens: { type: 'unsigned', initial: 0 },
luckyCharmCount: { type: 'unsigned', initial: 0 },
lastCommandTime: { type: 'unsigned', initial: 0 },
dailyCommandCount: { type: 'unsigned', initial: 0 },
lastCommandDate: { type: 'char', length: 20 },
totalSpent: { type: 'unsigned', initial: 0 },
ssrCount: { type: 'unsigned', initial: 0 },
inventory: { type: 'json', initial: [] },
bankBalance: { type: 'unsigned', initial: 0 },
lastInterestDate: { type: 'char', length: 20, initial: '' },
propertyType: { type: 'char', length: 20, initial: '' },
propertyPurchasePrice: { type: 'unsigned', initial: 0 },
lastRentDate: { type: 'char', length: 20, initial: '' },
lastTreasureDate: { type: 'char', length: 20, initial: '' },
jailedUntil: { type: 'unsigned', initial: 0 },
robberyAttempts: { type: 'unsigned', initial: 0 },
robberySuccess: { type: 'unsigned', initial: 0 },
redEnvelopesSent: { type: 'unsigned', initial: 0 },
redEnvelopesReceived: { type: 'unsigned', initial: 0 },
quizAnswered: { type: 'unsigned', initial: 0 },
quizCorrect: { type: 'unsigned', initial: 0 },
relationshipType: { type: 'char', length: 20, initial: '' },
partnerId: { type: 'char', length: 50, initial: '' },
partnerPlatform: { type: 'char', length: 50, initial: '' },
intimacy: { type: 'unsigned', initial: 0 },
farmLand: { type: 'json', initial: [] },
farmAnimals: { type: 'json', initial: [] },
farmTools: { type: 'json', initial: [] },
rentCollectedToday: { type: 'unsigned', initial: 0 },
lastRentTime: { type: 'unsigned', initial: 0 },
// 新增公司系统字段
companyName: { type: 'char', length: 50, initial: '' },
companyLevel: { type: 'unsigned', initial: 0 },
skillLevel: { type: 'unsigned', initial: 0 },
skillFragments: { type: 'unsigned', initial: 0 },
lastWorkTime: { type: 'unsigned', initial: 0 },
// 新增猜歌名游戏字段
musicGameState: { type: 'json', initial: null },
musicCorrect: { type: 'unsigned', initial: 0 },
// 新增养牛系统字段
cow: { type: 'json', initial: null }
}, {
primary: ['id', 'platform']
});
// 创建红包表
ctx.model.extend('red_envelopes', {
id: { type: 'char', length: 10 },
senderId: { type: 'char', length: 50 },
senderPlatform: { type: 'char', length: 50 },
amount: { type: 'unsigned' },
remaining: { type: 'unsigned' },
count: { type: 'unsigned' },
receivers: { type: 'json' },
createdAt: { type: 'unsigned' }
}, {
primary: 'id'
});
// 创建公司表(添加公户字段)
ctx.model.extend('companies', {
id: { type: 'char', length: 10 },
name: { type: 'char', length: 50 },
ownerId: { type: 'char', length: 50 },
ownerPlatform: { type: 'char', length: 50 },
level: { type: 'unsigned', initial: 1 },
tax: { type: 'unsigned', initial: 0 },
capital: { type: 'unsigned', initial: 0 },
members: { type: 'json', initial: [] },
publicBalance: { type: 'unsigned', initial: 0 } // 新增公户
}, {
primary: 'id'
});
// 存储游戏状态(内存中)
const games = {};
// 答题题库
const quizQuestions = [
{
question: "什么东西越洗越脏?",
answer: "水",
hint: "它是我们每天都要用的资源"
},
{
question: "什么动物你打死了它,却流了你的血?",
answer: "蚊子",
hint: "夏天经常出现"
},
{
question: "什么书在书店买不到?",
answer: "秘书",
hint: "与职业相关"
},
{
question: "什么车寸步难行?",
answer: "风车",
hint: "需要风力驱动"
},
{
question: "什么路最窄?",
answer: "冤家路窄",
hint: "成语"
},
{
question: "什么花不能浇水?",
answer: "烟花",
hint: "节日常见"
},
{
question: "什么蛋不能吃?",
answer: "零蛋",
hint: "与成绩相关"
},
{
question: "什么东西不能吃?",
answer: "东西方向",
hint: "方向词"
},
{
question: "什么牛不会吃草?",
answer: "蜗牛",
hint: "有壳的动物"
},
{
question: "什么山没有石头?",
answer: "人山人海",
hint: "形容人多"
}
];
// 存储答题状态
const quizStates = {};
// 获取用户数据
async function getUserData(session) {
const userId = session.userId;
const platform = session.platform;
if (!userId || !platform)
throw new Error('无法获取用户信息');
const [user] = await ctx.database.get('interactive_users', {
id: userId,
platform
});
if (user)
return user;
// 新用户初始化
const today = getToday();
const newUser = {
id: userId,
platform,
points: 100, // 新用户赠送100积分
lastSign: '',
consecutiveDays: 0,
totalSignDays: 0,
gamesPlayed: 0,
gamesWon: 0,
achievements: [],
hasDoubleCard: false,
freeLotteryCount: 0,
hintTokens: 0,
luckyCharmCount: 0,
lastCommandTime: 0,
dailyCommandCount: 0,
lastCommandDate: today,
totalSpent: 0,
ssrCount: 0,
inventory: [],
bankBalance: 0,
lastInterestDate: '',
propertyType: '',
propertyPurchasePrice: 0,
lastRentDate: '',
lastTreasureDate: '',
jailedUntil: 0,
robberyAttempts: 0,
robberySuccess: 0,
redEnvelopesSent: 0,
redEnvelopesReceived: 0,
quizAnswered: 0,
quizCorrect: 0,
relationshipType: '',
partnerId: '',
partnerPlatform: '',
intimacy: 0,
farmLand: [],
farmAnimals: [],
farmTools: [],
rentCollectedToday: 0,
lastRentTime: 0,
// 新增字段初始化
companyName: '',
companyLevel: 0,
skillLevel: 0,
skillFragments: 0,
lastWorkTime: 0,
musicGameState: null,
musicCorrect: 0,
cow: null // 养牛系统初始化为null
};
await ctx.database.create('interactive_users', newUser);
return newUser;
}
// 更新用户数据
async function updateUserData(user) {
const { id, platform, ...updateData } = user;
await ctx.database.set('interactive_users', {
id: user.id,
platform: user.platform
}, updateData);
}
// 检查成就
async function checkAchievements(session, user) {
const unlocked = [];
for (const achievement of ACHIEVEMENTS) {
if (!user.achievements.includes(achievement.id)) {
if (achievement.condition(user)) {
user.achievements.push(achievement.id);
user.points += achievement.reward;
unlocked.push(`🎖️ ${achievement.name} - ${achievement.description} (+${achievement.reward}积分)`);
}
}
}
if (unlocked.length) {
await updateUserData(user);
session.send(`🎉 解锁成就!\n${unlocked.join('\n')}`);
}
}
// 获取今天日期字符串
function getToday() {
const now = new Date();
return `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
}
// 检查冷却时间和每日限制
async function checkCommandLimits(session) {
const user = await getUserData(session);
const now = Date.now();
const today = getToday();
// 检查是否被监禁
if (user.jailedUntil > now) {
const remaining = Math.ceil((user.jailedUntil - now) / 1000 / 60);
session.send(`⛔ 你正在小黑屋中,${remaining}分钟后才能重获自由!`);
return false;
}
// 重置每日计数器
if (user.lastCommandDate !== today) {
user.dailyCommandCount = 0;
user.lastCommandDate = today;
}
// 检查每日限制
if (user.dailyCommandCount >= config.dailyLimit) {
session.send(`今日使用次数已达上限(${config.dailyLimit}次),请明天再来吧!`);
return false;
}
// 检查冷却时间
if (now - user.lastCommandTime < config.coolDown) {
const remaining = Math.ceil((config.coolDown - (now - user.lastCommandTime)) / 1000);
session.send(`操作太频繁啦,请 ${remaining} 秒后再试~`);
return false;
}
// 更新计数器
user.dailyCommandCount += 1;
user.lastCommandTime = now;
await updateUserData(user);
return true;
}
// ========== 猜数字游戏 ==========
ctx.command('猜数字 <message:text>', '猜数字游戏')
.alias('猜')
.usage('输入 "猜数字 开始" 开始游戏,然后输入数字进行猜测')
.action(async ({ session }, message) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
if (!message)
return '输入 "猜数字 开始" 开始猜数字游戏!';
const userId = session.userId;
if (message === '开始') {
if (!await checkCommandLimits(session))
return;
const user = await getUserData(session);
user.gamesPlayed += 1;
await updateUserData(user);
games[userId] = {
targetNumber: Math.floor(Math.random() * config.maxGuessNumber) + 1,
attempts: 0,
startTime: Date.now()
};
return `🎮 游戏开始!我已经想好了一个 1~${config.maxGuessNumber} 之间的数字,猜猜看是多少?\n` +
`提示:输入 "提示" 可以使用提示令牌(当前持有: ${user.inventory.find(i => i.id === 'hint_token')?.count || 0} 枚)`;
}
if (message === '提示') {
const game = games[userId];
if (!game)
return '你还没有开始游戏!';
const user = await getUserData(session);
const hintToken = user.inventory.find(i => i.id === 'hint_token');
if (!hintToken || hintToken.count <= 0)
return '你没有提示令牌了!去商店购买吧~';
// 减少提示令牌数量
hintToken.count -= 1;
if (hintToken.count <= 0) {
user.inventory = user.inventory.filter(i => i.id !== 'hint_token');
}
await updateUserData(user);
const range = Math.floor(config.maxGuessNumber / 10);
const lower = Math.max(1, game.targetNumber - range);
const upper = Math.min(config.maxGuessNumber, game.targetNumber + range);
return `🔍 提示:数字在 ${lower} ~ ${upper} 之间(当前持有: ${hintToken.count} 枚)`;
}
if (message === '放弃') {
const game = games[userId];
if (!game)
return '你还没有开始游戏!';
const user = await getUserData(session);
delete games[userId];
return `😢 你放弃了游戏!正确答案是 ${game.targetNumber},下次加油哦!`;
}
const game = games[userId];
if (!game)
return '你还没有开始游戏,输入 "猜数字 开始" 开始吧!';
const guess = parseInt(message);
if (isNaN(guess))
return '请输入有效的数字!';
if (guess < 1 || guess > config.maxGuessNumber) {
return `请输入 1~${config.maxGuessNumber} 之间的数字!`;
}
game.attempts++;
if (guess === game.targetNumber) {
const timeUsed = Math.floor((Date.now() - game.startTime) / 1000);
const basePoints = Math.max(1, 10 - game.attempts) * 5;
const timeBonus = Math.max(1, 60 - timeUsed) * 2;
// 检查是否有经验卡加成
let expCardBonus = 0;
let expCardMsg = '';
const user = await getUserData(session);
const expCard = user.inventory.find(item => item.id === 'exp_card');
if (expCard) {
expCardBonus = Math.floor((basePoints + timeBonus) * 0.2);
expCardMsg = `(经验卡加成 +${expCardBonus})`;
}
const totalPoints = basePoints + timeBonus + expCardBonus;
user.points += totalPoints;
user.gamesWon += 1;
await updateUserData(user);
// 检查成就
await checkAchievements(session, user);
delete games[userId];
// 根据表现给出不同评价
let comment = '';
if (game.attempts <= 3) {
comment = '🎯 太厉害了!你是天才吗?';
}
else if (game.attempts <= 7) {
comment = '👍 很棒的表现!';
}
else {
comment = '💪 再接再厉!';
}
return `${comment}\n🎉 恭喜你猜对了!答案就是 ${game.targetNumber}!\n` +
`尝试次数: ${game.attempts} (${basePoints}分) | ` +
`用时: ${timeUsed}秒 (${timeBonus}分)${expCardMsg}\n` +
`总计获得 ${totalPoints} 积分!`;
}
const diff = Math.abs(guess - game.targetNumber);
let hint = '';
if (diff > config.maxGuessNumber * 0.3) {
hint = '差得远呢~';
}
else if (diff > config.maxGuessNumber * 0.1) {
hint = '接近了,但还不够~';
}
else {
hint = '非常接近了!';
}
return guess < game.targetNumber
? `⬇️ 猜小了!${hint}(已尝试 ${game.attempts} 次)`
: `⬆️ 猜大了!${hint}(已尝试 ${game.attempts} 次)`;
});
// ========== 答题活动 ==========
ctx.command('答题', '知识问答赚取积分')
.usage('输入 "答题 开始" 开始答题,输入 "答题 提示" 获取提示')
.action(async ({ session }, action) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
const userId = session.userId;
if (!action) {
return '输入 "答题 开始" 开始答题赚取积分!\n' +
'输入 "答题 提示" 可以使用提示令牌获取提示';
}
if (action === '开始') {
if (!await checkCommandLimits(session))
return;
// 随机选择题目
const questionIndex = Math.floor(Math.random() * quizQuestions.length);
const question = quizQuestions[questionIndex];
quizStates[userId] = {
questionIndex,
startTime: Date.now()
};
const user = await getUserData(session);
user.quizAnswered += 1;
await updateUserData(user);
return `🧠 知识问答开始!\n\n` +
`题目:${question.question}\n\n` +
`请直接回答你的答案(输入 "答题 提示" 获取提示)`;
}
if (action === '提示') {
const state = quizStates[userId];
if (!state)
return '你还没有开始答题!';
const user = await getUserData(session);
const hintToken = user.inventory.find(i => i.id === 'hint_token');
if (!hintToken || hintToken.count <= 0)
return '你没有提示令牌了!去商店购买吧~';
// 减少提示令牌数量
hintToken.count -= 1;
if (hintToken.count <= 0) {
user.inventory = user.inventory.filter(i => i.id !== 'hint_token');
}
await updateUserData(user);
const question = quizQuestions[state.questionIndex];
return `💡 提示:${question.hint || '本题暂无提示'}`;
}
if (action === '放弃') {
if (!quizStates[userId])
return '你还没有开始答题!';
delete quizStates[userId];
return '😢 你放弃了答题,下次加油哦!';
}
// 处理答案
const state = quizStates[userId];
if (!state)
return '你还没有开始答题,输入 "答题 开始" 开始答题吧!';
const answer = action.trim();
const question = quizQuestions[state.questionIndex];
if (answer === question.answer) {
const user = await getUserData(session);
const timeUsed = Math.floor((Date.now() - state.startTime) / 1000);
// 计算奖励:基础奖励 + 时间奖励(越快越多)
const timeBonus = Math.max(0, 10 - Math.floor(timeUsed / 10));
const points = config.quizRewardBase + timeBonus;
user.points += points;
user.quizCorrect += 1;
await updateUserData(user);
delete quizStates[userId];
// 检查成就
await checkAchievements(session, user);
return `✅ 回答正确!\n` +
`答案:${question.answer}\n` +
`用时:${timeUsed}秒(时间奖励:+${timeBonus}分)\n` +
`获得积分:${points}\n` +
`当前积分:${user.points}`;
}
else {
return '❌ 回答错误!再想想吧~';
}
});
// ========== 每日签到 ==========
ctx.command('签到', '每日签到')
.action(async ({ session }) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
if (!await checkCommandLimits(session))
return;
const user = await getUserData(session);
const today = getToday();
if (user.lastSign === today) {
return '你今天已经签到过了哦,明天再来吧!';
}
// 计算连续签到
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const yesterdayStr = `${yesterday.getFullYear()}-${yesterday.getMonth() + 1}-${yesterday.getDate()}`;
if (user.lastSign === yesterdayStr) {
user.consecutiveDays += 1;
}
else {
user.consecutiveDays = 1;
}
user.totalSignDays += 1;
// 计算奖励
let baseReward = config.signReward;
const bonus = Math.min(100, user.consecutiveDays * 2);
// 双倍卡效果
let doubleEffect = '';
if (user.hasDoubleCard) {
baseReward *= 2;
user.hasDoubleCard = false;
doubleEffect = '(双倍卡生效)';
}
const total = baseReward + bonus;
user.points += total;
user.lastSign = today;
await updateUserData(user);
// 检查成就
await checkAchievements(session, user);
// 特殊签到奖励
let specialBonus = '';
if (user.consecutiveDays % 7 === 0) {
const weekBonus = 50;
user.points += weekBonus;
specialBonus = `\n✨ 连续签到满 ${user.consecutiveDays} 天,额外奖励 ${weekBonus} 积分!`;
await updateUserData(user);
}
return `✅ 签到成功!🎉\n` +
`连续签到:${user.consecutiveDays} 天 (总签到: ${user.totalSignDays}天)\n` +
`获得积分:${baseReward}${doubleEffect} + ${bonus} = ${total}${specialBonus}\n` +
`当前积分:${user.points}`;
});
// ========== 抽奖功能 ==========
ctx.command('抽奖', '消耗10积分抽奖')
.action(async ({ session }) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
if (!await checkCommandLimits(session))
return;
const user = await getUserData(session);
// 检查免费抽奖券
let useFreeTicket = false;
if (user.freeLotteryCount > 0) {
user.freeLotteryCount -= 1;
useFreeTicket = true;
}
else {
if (user.points < 10) {
return `积分不足!抽奖需要10积分,你当前只有 ${user.points} 积分`;
}
user.points -= 10;
user.totalSpent += 10;
}
// 抽奖动画
let animation = '抽奖中';
for (let i = 0; i < 3; i++) {
await (0, koishi_1.sleep)(500);
animation += '...';
session.send(animation);
}
// 按概率抽奖
let rand = Math.random();
// 幸运护符效果
let charmEffect = '';
if (user.luckyCharmCount > 0) {
rand *= 0.8; // 增加20%中奖概率
user.luckyCharmCount -= 1;
charmEffect = '(幸运护符生效)';
await updateUserData(user);
}
let index = 0;
if (rand < 0.05)
index = 0; // 5% 概率
else if (rand < 0.15)
index = 1; // 10% 概率
else if (rand < 0.4)
index = 2; // 25% 概率
else
index = 3; // 60% 概率
const prize = config.lotteryItems[index];
let result = `🎰 抽奖结果:${prize}!${charmEffect}`;
// 特殊奖励处理
if (index === 0) {
user.points += 1000;
user.ssrCount += 1;
result += `✨ 额外获得 1000 积分!`;
}
else if (index === 1) {
user.points += 300;
result += `✨ 额外获得 300 积分!`;
}
else if (index === 2) {
user.points += 100;
result += `✨ 额外获得 100 积分!`;
}
result += `\n当前积分:${user.points}`;
if (useFreeTicket) {
result = `(使用免费券) ${result}`;
}
await updateUserData(user);
// 检查成就
await checkAchievements(session, user);
return result;
});
// ========== 商店系统 ==========
ctx.command('商店 [action]', '积分商店')
.usage('输入 "商店列表" 查看商品,输入 "商店购买 <商品ID> [数量]" 购买')
.action(async ({ session }, action, itemId, countText) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
if (action === '列表' || !action) {
let list = '🛍️ 商店商品列表 🛍️\n';
config.shopItems.forEach(item => {
list += `[${item.id}] ${item.name} - ${item.description}\n`;
list += `💰 价格: ${item.price} 积分 | `;
list += `类型: ${item.storable ? '可存储物品' : '立即生效道具'}\n\n`;
});
return list + '输入 "商店购买 <商品ID> [数量]" 购买商品';
}
if (action === '购买') {
if (!itemId)
return '请输入要购买的商品ID';
const count = countText ? parseInt(countText) : 1;
if (isNaN(count) || count <= 0)
return '请输入正确的数量(大于0)';
const item = config.shopItems.find(i => i.id === itemId);
if (!item)
return '找不到该商品,请检查商品ID';
const user = await getUserData(session);
const totalPrice = item.price * count;
if (user.points < totalPrice) {
return `积分不足!需要 ${totalPrice} 积分,你当前只有 ${user.points} 积分`;
}
// 非存储物品只能买一个
if (!item.storable && count > 1) {
return '该物品不支持批量购买,一次只能购买一个';
}
user.points -= totalPrice;
user.totalSpent += totalPrice;
let effectMsg = '购买成功!';
// 处理可存储物品
if (item.storable) {
// 查找用户是否已有该物品
const existingItem = user.inventory.find(i => i.id === item.id);
if (existingItem) {
// 如果已有,增加数量
existingItem.count += count;
}
else {
// 否则添加新物品
user.inventory.push({
id: item.id,
name: item.name,
description: item.description,
count: count
});
}
effectMsg = `🛍️ 成功购买 ${item.name} x${count}!已添加到物品栏,使用"使用 ${item.id}"来使用它`;
}
else {
// 处理立即生效物品 - 多次触发效果
for (let i = 0; i < count; i++) {
if (item.effect) {
effectMsg = item.effect(user);
}
}
effectMsg = `🛍️ 成功购买 ${item.name} x${count}!\n` + effectMsg;
}
await updateUserData(user);
// 检查成就
await checkAchievements(session, user);
return `${effectMsg}\n剩余积分: ${user.points}`;
}
return '无效操作,请输入 "商店列表" 或 "商店购买 <商品ID> [数量]"';
});
// ========== 使用物品功能 ==========
ctx.command('使用 <itemId:string>', '使用物品')
.usage('输入"使用 <物品ID>"来使用物品栏中的物品')
.action(async ({ session }, itemId) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
if (!itemId)
return '请输入要使用的物品ID,使用"商店列表"查看可购买物品';
if (!await checkCommandLimits(session))
return;
const user = await getUserData(session);
// 查找物品
const itemIndex = user.inventory.findIndex(item => item.id === itemId || item.name === itemId);
if (itemIndex === -1) {
return `你没有该物品或物品不存在,请检查物品ID是否正确`;
}
const item = user.inventory[itemIndex];
// 根据物品ID执行不同效果
let result = '';
switch (item.id) {
case 'coffee':
// 提神咖啡:恢复5次每日使用次数
const before = user.dailyCommandCount;
if (user.dailyCommandCount >= 5) {
user.dailyCommandCount -= 5;
}
else {
user.dailyCommandCount = 0;
}
const restored = before - user.dailyCommandCount;
result = `☕ 你喝了一杯提神咖啡,恢复了${restored}次每日使用次数!当前剩余使用次数:${config.dailyLimit - user.dailyCommandCount}`;
break;
case 'exp_card':
// 经验卡:下次游戏获得额外积分
result = '✨ 经验卡已激活!下次猜数字游戏将获得额外20%积分奖励!';
break;
case 'skill_ticket': // 新增技能券
user.skillFragments += 1;
result = '✨ 使用技能券成功!获得1个技能碎片';
break;
default:
// 默认效果
result = `✅ 使用了 ${item.name}:${item.description}`;
break;
}
// 减少物品数量
if (item.count > 1) {
item.count -= 1;
}
else {
// 如果只剩一个,从物品栏移除
user.inventory.splice(itemIndex, 1);
}
await updateUserData(user);
return result;
});
// ========== 查看物品栏 ==========
ctx.command('背包', '查看物品栏')
.action(async ({ session }) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
const user = await getUserData(session);
if (!user.inventory.length) {
return '你的物品栏空空如也,快去商店购买物品吧!';
}
let result = '🎒 你的物品栏 🎒\n';
user.inventory.forEach(item => {
result += `[${item.id}] ${item.name} x${item.count}\n`;
result += `📝 ${item.description}\n\n`;
});
result += '使用"使用 <物品ID>"来使用物品';
return result;
});
// ========== 排行榜功能 ==========
ctx.command('排行榜 [type]', '排行榜')
.usage('可选类型: points(积分), sign(签到), games(游戏), lottery(抽奖), quiz(答题), farm(农场)')
.action(async ({ session }, type = 'points') => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
let orderBy;
let title;
switch (type) {
case 'points':
orderBy = 'points';
title = '积分排行榜';
break;
case 'sign':
orderBy = 'consecutiveDays';
title = '连续签到排行榜';
break;
case 'games':
orderBy = 'gamesWon';
title = '游戏胜场排行榜';
break;
case 'lottery':
orderBy = 'ssrCount';
title = '抽卡之王排行榜';
break;
case 'quiz':
orderBy = 'quizCorrect';
title = '答题达人排行榜';
break;
case 'farm':
orderBy = 'intimacy';
title = '农场亲密值排行榜';
break;
default: return '无效排行榜类型!可选: points, sign, games, lottery, quiz, farm';
}
// 获取排行榜数据
const users = await ctx.database.get('interactive_users', {}, {
sort: { [orderBy]: 'desc' },
limit: 10
});
if (!users.length)
return '暂无数据';
let result = `🏆 ${title} 🏆\n`;
const medals = ['🥇', '🥈', '🥉', '🏅', '🏅', '🏅', '🏅', '🏅', '🏅', '🏅'];
users.forEach((user, index) => {
const value = user[orderBy];
const medal = index < medals.length ? medals[index] : '🏅';
result += `${medal} ${index + 1}. ${user.id} - ${value}${type === 'points' ? '分' : ''}\n`;
});
return result;
});
// ========== 成就系统 ==========
ctx.command('成就', '查看成就')
.action(async ({ session }) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
const user = await getUserData(session);
let result = '🏆 成就系统 🏆\n';
if (!user.achievements.length) {
result += '你还没有解锁任何成就,继续努力吧!\n\n';
}
else {
result += '🎖️ 已解锁成就 🎖️\n';
user.achievements.forEach(achId => {
const achievement = ACHIEVEMENTS.find(a => a.id === achId);
if (achievement) {
result += `✅ ${achievement.name}: ${achievement.description}\n`;
}
});
result += '\n';
}
result += '🔒 未解锁成就 🔒\n';
ACHIEVEMENTS.forEach(achievement => {
if (!user.achievements.includes(achievement.id)) {
result += `❌ ${achievement.name}: ${achievement.description}\n`;
}
});
return result;
});
// ========== 寻宝功能 ==========
ctx.command('寻宝 <points:number>', '寻宝功能,成功获得双倍积分,失败损失积分')
.usage('输入 "寻宝 <积分数>" 开始寻宝')
.action(async ({ session }, points) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
if (!await checkCommandLimits(session))
return;
if (points === undefined || isNaN(points) || points <= 0) {
return '请输入正确的积分数量(大于0)';
}
const user = await getUserData(session);
const today = getToday();
// 检查每日寻宝限制
if (user.points < points) {
return `积分不足!你只有 ${user.points} 积分,无法寻宝 ${points} 积分`;
}
// 计算成功率(基础为70%,投入越多成功率越低)
const baseChance = 0.7;
const riskFactor = Math.min(0.3, points / 10000); // 每10000积分降低30%成功率
const successChance = baseChance - riskFactor;
const isSuccess = Math.random() < successChance;
user.lastTreasureDate = today;
if (isSuccess) {
const reward = points * 2;
user.points += reward;
await updateUserData(user);
return `🎉 寻宝成功!你获得了双倍奖励:${reward} 积分!\n当前积分:${user.points}`;
}
else {
user.points -= points;
await updateUserData(user);
return `😢 寻宝失败!你失去了 ${points} 积分...\n当前积分:${user.points}`;
}
});
// ========== 银行系统 ==========
ctx.command('银行 [action]', '银行系统')
.usage('存钱: 银行存款 <金额>\n取钱: 银行取款 <金額>\n利息: 银行利息\n查看: 银行')
.action(async ({ session }, action, amountText) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
const user = await getUserData(session);
const today = getToday();
// 查看银行状态
if (!action) {
return `🏦 银行账户信息 🏦\n` +
`存款余额: ${user.bankBalance} 积分\n` +
`现金余额: ${user.points} 积分\n` +
`今日利息: ${user.lastInterestDate === today ? '已领取' : '可领取'}\n` +
`存款上限: 20000000积分\n` +
`利息: 10% (每天可领取一次)\n` +
`命令: 银行存款 <金额> - 存款\n` +
` 银行取款 <金额> - 取款\n` +
` 银行利息 - 领取利息`;
}
if (!await checkCommandLimits(session))
return;
// 存款
if (action === '存款') {
if (!amountText)
return '请输入存款金额';
const amount = parseInt(amountText);
if (isNaN(amount))
return '请输入有效的数字';
if (amount <= 0)
return '存款金额必须大于0';
// 检查存款上限
if (user.bankBalance + amount > 20000000) {
return `存款超过上限!最多可存 20000000积分(当前已存: ${user.bankBalance})`;
}
if (user.points < amount) {
return `现金不足!你只有 ${user.points} 积分`;
}
user.points -= amount;
user.bankBalance += amount;
await updateUserData(user);
return `✅ 存款成功!\n` +
`存款余额: ${user.bankBalance} 积分\n` +
`现金余额: ${user.points} 积分`;
}
// 取款
if (action === '取款') {
if (!amountText)
return '请输入取款金额';
const amount = parseInt(amountText);
if (isNaN(amount))
return '请输入有效的数字';
if (amount <= 0)
return '取款金额必须大于0';
if (user.bankBalance < amount) {
return `存款不足!你只有 ${user.bankBalance} 积分存款`;
}
user.bankBalance -= amount;
user.points += amount;
await updateUserData(user);
return `✅ 取款成功!\n` +
`存款余额: ${user.bankBalance} 积分\n` +
`现金余额: ${user.points} 积分`;
}
// 领取利息
if (action === '利息') {
if (user.lastInterestDate === today) {
return '你今天已经领取过利息了!';
}
if (user.bankBalance <= 0) {
return '你的存款为0,无法领取利息';
}
// 修改:利息从1%提高到10%
const interest = Math.floor(user.bankBalance * 0.10); // 10%利息
user.points += interest;
user.lastInterestDate = today;
await updateUserData(user);
return `💰 成功领取利息:${interest} 积分!\n` +
`当前现金: ${user.points} 积分\n` +
`存款余额: ${user.bankBalance} 积分`;
}
return '无效操作,请输入 存款, 取款 或 利息';
});
// ========== 房产系统 ==========
ctx.command('房产 [action]', '房产系统')
.usage('市场: 房产市场\n买房: 房产购买 <类型>\n卖房: 房产出售\n收租: 房产收租')
.action(async ({ session }, action, propertyType) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
const user = await getUserData(session);
const today = getToday();
// 查看房产状态
if (!action) {
if (!user.propertyType) {
return `🏠 房产系统 🏠\n` +
`你目前没有房产\n` +
`输入 "房产市场" 查看房地产市场\n` +
`输入 "房产购买 <类型>" 购买房产`;
}
return `🏠 房产信息 🏠\n` +
`房产类型: ${getPropertyTypeName(user.propertyType)}\n` +
`购买价格: ${user.propertyPurchasePrice} 积分\n` +
`今日租金: ${user.lastRentDate === today ? '已收取' : '可收取'}\n` +
`今日收租次数: ${user.rentCollectedToday}/8\n` +
`租金收益: ${Math.floor(user.propertyPurchasePrice * 0.01)} 积分/次\n` +
`命令: 房产市场 - 查看房产市场\n` +
` 房产出售 - 出售房产\n` +
` 房产收租 - 收取租金`;
}
if (!await checkCommandLimits(session))
return;
// 查看房产市场
if (action === '市场') {
// 生成随机房价(在范围内波动)
const tier1Price = Math.floor(Math.random() * 50000) + 50000;
const tier2Price = Math.floor(Math.random() * 20000) + 20000;
const tier3Price = Math.floor(Math.random() * 9000) + 1000;
return `🏘️ 房地产市场 🏘️\n` +
`1. 一线房产: ${tier1Price} 积分\n` +
` (豪华地段,高投资回报)\n` +
`2. 二线房产: ${tier2Price} 积分\n` +
` (稳定增值,中等回报)\n` +
`3. 三线房产: ${tier3Price} 积分\n` +
` (经济实惠,适合新手)\n\n` +
`输入 "房产购买 <类型>" 购买房产\n` +
`类型: tier1, tier2, tier3`;
}
// 购买房产
if (action === '购买') {
if (!propertyType)
return '请输入房产类型 (tier1/tier2/tier3)';
if (user.propertyType)
return '你已拥有房产,无法再次购买';
// 生成随机房价
let price = 0;
let typeName = '';
switch (propertyType) {
case 'tier1':
price = Math.floor(Math.random() * 50000) + 50000;
typeName = '一线房产';
break;
case 'tier2':
price = Math.floor(Math.random() * 20000) + 20000;
typeName = '二线房产';
break;
case 'tier3':
price = Math.floor(Math.random() * 9000) + 1000;
typeName = '三线房产';
break;
default:
return '无效房产类型!请输入 tier1, tier2 或 tier3';
}
if (user.points < price) {
return `积分不足!购买${typeName}需要 ${price} 积分,你只有 ${user.points} 积分`;
}
user.points -= price;
user.propertyType = propertyType;
user.propertyPurchasePrice = price;
await updateUserData(user);
return `🎉 恭喜你购买了${typeName}!\n` +
`房产价格: ${price} 积分\n` +
`每日租金: ${Math.floor(price * 0.01)} 积分/次\n` +
`剩余积分: ${user.points}\n` +
`使用 "房产收租" 每小时收取租金(每天最多8次)`;
}
// 出售房产
if (action === '出售') {
if (!user.propertyType)
return '你没有房产可出售';
// 出售价格为购买价格的90%
const sellPrice = Math.floor(user.propertyPurchasePrice * 0.9);
user.points += sellPrice;
const typeName = getPropertyTypeName(user.propertyType);
// 重置房产信息
user.propertyType = '';
user.propertyPurchasePrice = 0;
user.lastRentDate = '';
user.rentCollectedToday = 0;
await updateUserData(user);
return `🏠 你已出售${typeName},获得 ${sellPrice} 积分!\n` +
`当前积分: ${user.points}`;
}
// 收取租金
if (action === '收租') {
if (!user.propertyType)
return '你没有房产可收取租金';
const now = Date.now();
const today = getToday();
// 重置每日收租次数(如果是新的一天)
if (user.lastRentDate !== today) {
user.rentCollectedToday = 0;
user.lastRentDate = today;
}
// 检查收租次数是否达到上限(8次/天)
if (user.rentCollectedToday >= 8) {
return '今日收租次数已达上限(8次)!';
}
// 检查是否在冷却中(1小时)
const lastRentTime = user.lastRentTime || 0;
const cooldown = 60 * 60 * 1000; // 1小时
if (now - lastRentTime < cooldown) {
const remaining = Math.ceil((cooldown - (now - lastRentTime)) / 1000 / 60);
return `请等待 ${remaining} 分钟后再收取租金!`;
}
const rentAmount = Math.floor(user.propertyPurchasePrice * 0.01);
user.points += rentAmount;
user.rentCollectedToday += 1;
user.lastRentTime = now;
user.lastRentDate = today;
await updateUserData(user);
return `💰 成功收取租金:${rentAmount} 积分!\n` +
`今日已收租: ${user.rentCollectedToday}/8 次\n` +
`当前积分: ${user.points}`;
}
return '无效操作,请输入 市场, 购买, 出售 或 收租';
});
// 获取房产类型名称
function getPropertyTypeName(type) {
switch (type) {
case 'tier1': return '一线房产';
case 'tier2': return '二线房产';
case 'tier3': return '三线房产';
default: return '未知房产';
}
}
// ========== 个人资料 ==========
ctx.command('资料', '查看个人资料')
.action(async ({ session }) => {
if (!session)
return '会话异常';
if (!session.userId)
return '无法获取用户ID';
const user = await getUserData(session);
// 构建物品列表字符串
let itemsList = '无';
if (user.inventory.length > 0) {
itemsList = user.inventory.map(item => `${item.name} x${item.count}`).join('\n ');
}
// 房产信息
let propertyInfo = '无';
if (user.propertyType) {
propertyInfo = `${getPropertyTypeName(user.propertyType)} (购买价: ${user.propertyPurchasePrice})`;
}
// 监禁状态
const now = Date.now();
let jailInfo = '自由身';
if (user.jailedUntil > now) {
const remaining =