- Add Rock Paper Scissors game with PvP and bot modes - Fixed syntax errors and improved game mechanics - PvP moves now require PM for secrecy - Add Word Scramble game with difficulty levels - Multiple word categories and persistent scoring - Enhance duck hunt with better statistics tracking - Separate points vs duck count tracking - Fixed migration logic issues - Add core rate limiting system (5 commands/30s) - Admin whitelist for megasconed - Automatic cleanup and unblocking - Improve reload functionality for hot-reloading plugins - Add channel-specific commands (\!stopducks/\!startducks) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
108 lines
No EOL
4.3 KiB
JavaScript
108 lines
No EOL
4.3 KiB
JavaScript
// plugins/basic.js - Basic commands plugin
|
|
module.exports = {
|
|
init(bot) {
|
|
console.log('Basic plugin initialized');
|
|
},
|
|
|
|
cleanup(bot) {
|
|
console.log('Basic plugin cleaned up');
|
|
},
|
|
|
|
commands: [
|
|
{
|
|
name: 'ping',
|
|
description: 'Responds with pong',
|
|
execute(context, bot) {
|
|
bot.say(context.replyTo, `${context.nick}: pong!`);
|
|
}
|
|
},
|
|
|
|
{
|
|
name: 'help',
|
|
description: 'Shows available commands',
|
|
execute(context, bot) {
|
|
const commands = Array.from(bot.commands.keys());
|
|
bot.say(context.replyTo, `Available commands: ${commands.join(', ')}`);
|
|
}
|
|
},
|
|
|
|
{
|
|
name: 'time',
|
|
description: 'Shows current time',
|
|
execute(context, bot) {
|
|
const now = new Date().toLocaleString();
|
|
bot.say(context.replyTo, `Current time: ${now}`);
|
|
}
|
|
},
|
|
|
|
{
|
|
name: 'ratelimit',
|
|
description: 'Check your rate limit status',
|
|
execute(context, bot) {
|
|
// Only allow in #bakedbeans or for admins
|
|
if (context.channel !== '#bakedbeans' && !bot.rateLimitConfig.adminWhitelist.includes(context.nick)) {
|
|
bot.say(context.replyTo, '🚫 This command can only be used in #bakedbeans!');
|
|
return;
|
|
}
|
|
|
|
const userLimits = bot.rateLimits.get(context.nick);
|
|
const config = bot.rateLimitConfig;
|
|
|
|
if (config.adminWhitelist.includes(context.nick)) {
|
|
bot.say(context.replyTo, `✅ ${context.nick}: You are whitelisted (no rate limits)`);
|
|
return;
|
|
}
|
|
|
|
if (!userLimits) {
|
|
bot.say(context.replyTo, `✅ ${context.nick}: No rate limit data (you're clean!)`);
|
|
return;
|
|
}
|
|
|
|
const now = Date.now();
|
|
|
|
if (userLimits.blocked && now < userLimits.blockExpiry) {
|
|
const remainingMs = userLimits.blockExpiry - now;
|
|
const remainingSeconds = Math.ceil(remainingMs / 1000);
|
|
bot.say(context.replyTo, `🚫 ${context.nick}: Rate limited for ${remainingSeconds} more seconds`);
|
|
return;
|
|
}
|
|
|
|
const windowStart = now - config.windowMs;
|
|
const recentCommands = userLimits.commands.filter(timestamp => timestamp > windowStart);
|
|
const remaining = config.maxCommands - recentCommands.length;
|
|
|
|
bot.say(context.replyTo, `📊 ${context.nick}: ${recentCommands.length}/${config.maxCommands} commands used in last ${config.windowMs/1000}s (${remaining} remaining)`);
|
|
}
|
|
},
|
|
|
|
{
|
|
name: 'reload',
|
|
description: 'Reload all plugins (admin only)',
|
|
execute(context, bot) {
|
|
// Only allow for admin
|
|
if (context.nick !== 'megasconed') {
|
|
bot.say(context.replyTo, '🚫 Only admins can reload plugins!');
|
|
return;
|
|
}
|
|
|
|
// Only allow in #bakedbeans
|
|
if (context.channel !== '#bakedbeans') {
|
|
bot.say(context.replyTo, '🚫 Plugin reload can only be done in #bakedbeans!');
|
|
return;
|
|
}
|
|
|
|
bot.say(context.replyTo, '🔄 Reloading all plugins...');
|
|
const pluginCount = bot.plugins.size;
|
|
|
|
try {
|
|
bot.reloadAllPlugins();
|
|
const newCommandCount = bot.commands.size;
|
|
bot.say(context.replyTo, `✅ Reloaded ${pluginCount} plugins successfully! Now have ${newCommandCount} commands available.`);
|
|
} catch (error) {
|
|
console.error('❌ Error during plugin reload:', error);
|
|
bot.say(context.replyTo, '❌ Error during plugin reload - check console for details.');
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}; |