// plugins/coinflip.js - Coin Flip Casino game plugin const fs = require('fs'); const path = require('path'); module.exports = { init(bot) { console.log('Coin Flip Casino plugin initialized'); this.bot = bot; // Persistent player statistics (saved to file) this.playerStats = new Map(); // nick -> { totalWins, totalLosses, totalFlips, biggestWin, winStreak, bestStreak, name } // Set up score file path this.scoresFile = path.join(__dirname, 'coinflip_scores.json'); // Load existing scores this.loadScores(); }, cleanup(bot) { console.log('Coin Flip Casino plugin cleaned up'); // Save scores before cleanup this.saveScores(); }, // Load scores from file loadScores() { try { if (fs.existsSync(this.scoresFile)) { const data = fs.readFileSync(this.scoresFile, 'utf8'); const scoresObject = JSON.parse(data); // Convert back to Map this.playerStats = new Map(Object.entries(scoresObject)); console.log(`🪙 Loaded ${this.playerStats.size} coin flip player stats from ${this.scoresFile}`); // Log top 3 players if any exist if (this.playerStats.size > 0) { const topPlayers = Array.from(this.playerStats.values()) .sort((a, b) => b.totalWins - a.totalWins) .slice(0, 3); console.log('🏆 Top coin flippers:', topPlayers.map(p => `${p.name}(${p.totalWins}W)`).join(', ')); } } else { console.log(`🪙 No existing coin flip scores file found, starting fresh`); } } catch (error) { console.error(`❌ Error loading coin flip scores:`, error); this.playerStats = new Map(); // Reset to empty if load fails } }, // Save scores to file saveScores() { try { // Convert Map to plain object for JSON serialization const scoresObject = Object.fromEntries(this.playerStats); const data = JSON.stringify(scoresObject, null, 2); fs.writeFileSync(this.scoresFile, data, 'utf8'); console.log(`💾 Saved ${this.playerStats.size} coin flip player stats to ${this.scoresFile}`); } catch (error) { console.error(`❌ Error saving coin flip scores:`, error); } }, // Update a player's persistent stats and save to file updatePlayerStats(nick, updates) { // Ensure playerStats Map exists if (!this.playerStats) { this.playerStats = new Map(); } if (!this.playerStats.has(nick)) { this.playerStats.set(nick, { totalWins: 0, totalLosses: 0, totalFlips: 0, biggestWin: 0, winStreak: 0, bestStreak: 0, name: nick }); } const player = this.playerStats.get(nick); Object.assign(player, updates); // Save to file after each update this.saveScores(); }, // Flip the coin and return result flipCoin() { return Math.random() < 0.5 ? 'heads' : 'tails'; }, // Calculate win amount based on bet calculateWinnings(bet, isWin) { if (!isWin) return 0; // Simple 1:1 payout for coin flip return bet; }, commands: [ { name: 'flip', description: 'Flip a coin and bet on the outcome', execute: function(context, bot) { const plugin = module.exports; const target = context.replyTo; const from = context.nick; const args = context.args; // Parse command: !flip [bet] if (args.length === 0) { bot.say(target, `Usage: !flip [bet] - Example: !flip heads 5`); return; } const guess = args[0].toLowerCase(); if (guess !== 'heads' && guess !== 'tails') { bot.say(target, `${from}: Choose 'heads' or 'tails'`); return; } // Parse bet amount (default to 1) let bet = 1; if (args.length > 1) { bet = parseInt(args[1]); if (isNaN(bet) || bet < 1 || bet > 100) { bot.say(target, `${from}: Bet must be between 1 and 100`); return; } } // Initialize player if new if (!plugin.playerStats.has(from)) { plugin.updatePlayerStats(from, { totalWins: 0, totalLosses: 0, totalFlips: 0, biggestWin: 0, winStreak: 0, bestStreak: 0, name: from }); } // Flip the coin const result = plugin.flipCoin(); const isWin = guess === result; const winnings = plugin.calculateWinnings(bet, isWin); // Update player stats const player = plugin.playerStats.get(from); const updates = { totalFlips: player.totalFlips + 1 }; if (isWin) { updates.totalWins = player.totalWins + 1; updates.winStreak = player.winStreak + 1; // Update best streak if (updates.winStreak > player.bestStreak) { updates.bestStreak = updates.winStreak; } // Update biggest win if (winnings > player.biggestWin) { updates.biggestWin = winnings; } } else { updates.totalLosses = player.totalLosses + 1; updates.winStreak = 0; // Reset streak on loss } // Choose coin flip animation const coinEmojis = ['🪙', '🥇', '💰']; const coinEmoji = coinEmojis[Math.floor(Math.random() * coinEmojis.length)]; // Result message with color coding let resultEmoji, resultText; if (result === 'heads') { resultEmoji = '👑'; resultText = 'HEADS'; } else { resultEmoji = '🦅'; resultText = 'TAILS'; } // Create result message let output = `${coinEmoji} ${from}: ${resultEmoji} ${resultText}! `; if (isWin) { output += `✅ WIN! +${winnings} pts`; if (updates.winStreak > 1) { output += ` | 🔥 ${updates.winStreak} streak!`; } } else { output += `❌ LOSE! -${bet} pts`; } // Add totals output += ` | W:${updates.totalWins} L:${updates.totalLosses}`; bot.say(target, output); plugin.updatePlayerStats(from, updates); } }, { name: 'flipstats', description: 'Show your coin flip statistics', execute: function(context, bot) { const plugin = module.exports; const target = context.replyTo; const from = context.nick; if (!plugin.playerStats.has(from)) { bot.say(target, `${from}: You haven't flipped any coins yet! Use !flip to start.`); return; } const player = plugin.playerStats.get(from); const winRate = player.totalFlips > 0 ? ((player.totalWins / player.totalFlips) * 100).toFixed(1) : 0; bot.say(target, `🪙 ${from}: ${player.totalWins}W/${player.totalLosses}L (${winRate}%) | Best: ${player.biggestWin} | Streak: ${player.winStreak} (best: ${player.bestStreak}) | Flips: ${player.totalFlips}`); } }, { name: 'topflip', description: 'Show top coin flip players', execute: function(context, bot) { const plugin = module.exports; const target = context.replyTo; if (plugin.playerStats.size === 0) { bot.say(target, 'No coin flip scores recorded yet! Use !flip to start playing.'); return; } // Get top players by different metrics const byWins = Array.from(plugin.playerStats.values()) .sort((a, b) => b.totalWins - a.totalWins) .slice(0, 3); const byStreak = Array.from(plugin.playerStats.values()) .sort((a, b) => b.bestStreak - a.bestStreak) .slice(0, 1); let output = '🏆 Top Flippers: '; byWins.forEach((player, i) => { const trophy = i === 0 ? '🥇' : i === 1 ? '🥈' : '🥉'; const winRate = player.totalFlips > 0 ? ((player.totalWins / player.totalFlips) * 100).toFixed(0) : 0; output += `${trophy}${player.name}(${player.totalWins}W/${winRate}%) `; }); if (byStreak[0] && byStreak[0].bestStreak > 0) { output += `| 🔥 Best Streak: ${byStreak[0].name}(${byStreak[0].bestStreak})`; } bot.say(target, output); } }, { name: 'fliptest', description: 'Test coin fairness with multiple flips', execute: function(context, bot) { const plugin = module.exports; const target = context.replyTo; const from = context.nick; const args = context.args; // Parse number of flips (default 10, max 100) let numFlips = 10; if (args.length > 0) { numFlips = parseInt(args[0]); if (isNaN(numFlips) || numFlips < 1 || numFlips > 100) { bot.say(target, `${from}: Number of flips must be between 1 and 100`); return; } } // Perform multiple flips let heads = 0; let tails = 0; let sequence = ''; for (let i = 0; i < numFlips; i++) { const result = plugin.flipCoin(); if (result === 'heads') { heads++; sequence += '👑'; } else { tails++; sequence += '🦅'; } } const headsPercent = ((heads / numFlips) * 100).toFixed(1); const tailsPercent = ((tails / numFlips) * 100).toFixed(1); bot.say(target, `🪙 ${from}: ${numFlips} flips | 👑 ${heads} (${headsPercent}%) | 🦅 ${tails} (${tailsPercent}%)`); bot.say(target, `Sequence: ${sequence}`); } }, { name: 'resetflip', description: 'Reset all coin flip scores (admin command)', execute: function(context, bot) { const plugin = module.exports; const target = context.replyTo; const from = context.nick; // Simple admin check const adminNicks = ['admin', 'owner', 'cancerbot', 'megasconed']; if (!adminNicks.includes(from)) { bot.say(target, `${from}: Access denied - admin only command`); return; } const playerCount = plugin.playerStats.size; plugin.playerStats.clear(); plugin.saveScores(); bot.say(target, `🗑️ ${from}: Reset ${playerCount} coin flip player stats`); } } ] };