const mongoose = require("mongoose"); const { createCanvas, loadImage } = require("canvas"); const fs = require("fs-extra"); const path = require("path"); const bankUserSchema = new mongoose.Schema({ userID: { type: String, required: true, unique: true }, balance: { type: Number, default: 0 } }); const BankUser = mongoose.models.DiabloBankUser || mongoose.model("DiabloBankUser", bankUserSchema); // Slot Machine Symbols const symbols = ["šŸŽ°", "šŸ’Ž", "7ļøāƒ£", "šŸ‘‘", "šŸ’", "šŸ‹", "šŸ””"]; // Maximum Bet Limit: 69 Billion const MAX_BET = 69000000000; module.exports = { config: { name: "slot", aliases: ["slots", "stlogame", "be11t"], version: "1.2.0", author: "Protik Shah", countDown: 5, role: 0, shortDescription: "Play Slot Machine Game & Win Bank Money", category: "games", guide: { en: "{p}slot " } }, formatMoney: function (num) { if (num >= 1000000000) return (num / 1000000000).toFixed(1).replace(/\.0$/, "") + "B"; if (num >= 1000000) return (num / 1000000).toFixed(1).replace(/\.0$/, "") + "M"; if (num >= 1000) return (num / 1000).toFixed(1).replace(/\.0$/, "") + "K"; return num.toLocaleString(); }, parseBetAmount: function (input, userBalance) { if (!input) return null; const str = input.toString().trim().toLowerCase(); if (str === "all" || str === "max") { return userBalance; } const match = str.match(/^(\d+(?:\.\d+)?)\s*([kmb])?$/); if (!match) return null; let value = parseFloat(match[1]); const unit = match[2]; if (unit === "k") value *= 1000; else if (unit === "m") value *= 1000000; else if (unit === "b") value *= 1000000000; return Math.floor(value); }, onStart: async function ({ api, event, args, message, usersData }) { const sendMsg = (txt) => message && typeof message.reply === "function" ? message.reply(txt) : api.sendMessage(txt, event.threadID, event.messageID); const { senderID } = event; const rawInput = args[0]; if (!rawInput) { return sendMsg("āš ļø š—£š—Ÿš—˜š—”š—¦š—˜ š—˜š—”š—§š—˜š—„ š—” š—©š—”š—Ÿš—œš—— š—•š—˜š—§ š—”š— š—¢š—Øš—”š—§!\nšŸ‘‰ š—˜š˜…š—®š—ŗš—½š—¹š—²: !š˜€š—¹š—¼š˜ šŸ±šŸ¬šŸ¬, !š˜€š—¹š—¼š˜ šŸ­š—ø, !š˜€š—¹š—¼š˜ šŸ±š—ŗ, !š˜€š—¹š—¼š˜ šŸ­š—Æ, !š˜€š—¹š—¼š˜ š—ŗš—®š˜…"); } try { let user = await BankUser.findOne({ userID: senderID }); const currentBalance = user ? user.balance : 0; const betAmount = this.parseBetAmount(rawInput, currentBalance); if (betAmount === null || isNaN(betAmount) || betAmount <= 0) { return sendMsg("āš ļø š—œš—”š—©š—”š—Ÿš—œš—— š—•š—˜š—§ š—™š—¢š—„š— š—”š—§!\nšŸ‘‰ š—Øš˜€š—² š—»š˜‚š—ŗš—Æš—²š—æš˜€ š—¼š—æ š˜€š˜‚š—³š—³š—¶š˜…š—²š˜€ š—¹š—¶š—øš—²: šŸ­š—ø, šŸ®.šŸ±š—ŗ, šŸ­š—Æ, š—ŗš—®š˜…"); } // Check Max Bet Limit (69 Billion) if (betAmount > MAX_BET) { return sendMsg(`āš ļø š— š—”š—«š—œš— š—Øš—  š—•š—˜š—§ š—Ÿš—œš— š—œš—§ š—œš—¦ $${this.formatMoney(MAX_BET)} USD!`); } if (!user || currentBalance < betAmount) { return sendMsg(`āŒ š—œš—”š—¦š—Øš—™š—™š—œš—–š—œš—˜š—”š—§ š—•š—”š—Ÿš—”š—”š—–š—˜!\nšŸ’³ š—¬š—¼š˜‚š—æ š—–š˜‚š—æš—æš—²š—»š˜ š—•š—®š—¹š—®š—»š—°š—²: $${this.formatMoney(currentBalance)} USD`); } let userName = senderID; if (usersData && typeof usersData.getName === "function") { try { userName = await usersData.getName(senderID); } catch (e) {} } // Spin Logic (3 Random Symbols) const slot1 = symbols[Math.floor(Math.random() * symbols.length)]; const slot2 = symbols[Math.floor(Math.random() * symbols.length)]; const slot3 = symbols[Math.floor(Math.random() * symbols.length)]; let winMultiplier = 0; let isWin = false; if (slot1 === slot2 && slot2 === slot3) { winMultiplier = 5; // All 3 match = 5x payout isWin = true; } else if (slot1 === slot2 || slot2 === slot3 || slot1 === slot3) { winMultiplier = 2; // 2 match = 2x payout isWin = true; } const winAmount = isWin ? betAmount * winMultiplier : 0; const netChange = isWin ? winAmount - betAmount : -betAmount; // Update Database Balance user.balance += netChange; await user.save(); // Canvas Rendering (Cyber Neon Slot Machine Card) const canvas = createCanvas(900, 500); const ctx = canvas.getContext("2d"); // Dark Background ctx.fillStyle = "#050a14"; ctx.fillRect(0, 0, 900, 500); // Multi-layer Laser Glow Outer Border const laserGlows = [ { color: isWin ? "rgba(74, 222, 128, 0.2)" : "rgba(239, 68, 68, 0.2)", blur: 35, width: 14 }, { color: isWin ? "#4ade80" : "#ef4444", blur: 15, width: 4 }, { color: "#ffffff", blur: 4, width: 2 } ]; laserGlows.forEach(g => { ctx.save(); ctx.shadowColor = g.color; ctx.shadowBlur = g.blur; ctx.strokeStyle = g.color; ctx.lineWidth = g.width; ctx.strokeRect(20, 20, 860, 460); ctx.restore(); }); // Header Banner ctx.fillStyle = "#ffffff"; ctx.font = "900 32px 'Segoe UI', Sans-serif"; ctx.fillText("šŸŽ° CASINO SLOT MACHINE šŸŽ°", 50, 75); ctx.fillStyle = isWin ? "#4ade80" : "#ef4444"; ctx.font = "bold 15px 'Segoe UI', Sans-serif"; ctx.fillText(isWin ? `ā–ŗ BIG WIN! YOU WON ${winMultiplier}X MULTIPLIER` : "ā–ŗ BETTER LUCK NEXT TIME!", 52, 102); // User Avatar Render try { const avatarUrl = `https://graph.facebook.com/${senderID}/picture?height=300&width=300&access_token=6628568379%7Cc1e620fa708a1d5696fb991c1bde5662`; const avatarImg = await loadImage(avatarUrl); ctx.save(); ctx.shadowColor = isWin ? "#4ade80" : "#ef4444"; ctx.shadowBlur = 20; ctx.beginPath(); ctx.arc(740, 115, 60, 0, Math.PI * 2); ctx.clip(); ctx.drawImage(avatarImg, 680, 55, 120, 120); ctx.restore(); ctx.strokeStyle = isWin ? "#4ade80" : "#ef4444"; ctx.lineWidth = 4; ctx.beginPath(); ctx.arc(740, 115, 60, 0, Math.PI * 2); ctx.stroke(); } catch (e) {} // 3 Slot Reel Boxes const reels = [slot1, slot2, slot3]; const startX = 140; for (let i = 0; i < 3; i++) { const boxX = startX + (i * 210); const boxY = 150; // Reel Box Background ctx.fillStyle = "rgba(15, 23, 42, 0.8)"; ctx.beginPath(); ctx.roundRect(boxX, boxY, 180, 180, 16); ctx.fill(); ctx.strokeStyle = isWin ? "#4ade80" : "rgba(255, 255, 255, 0.15)"; ctx.lineWidth = 3; ctx.stroke(); // Symbol Render ctx.fillStyle = "#ffffff"; ctx.font = "80px 'Segoe UI Emoji', 'Segoe UI', Sans-serif"; ctx.textAlign = "center"; ctx.fillText(reels[i], boxX + 90, boxY + 118); ctx.textAlign = "left"; } // Footer Stats Dashboard ctx.fillStyle = "#64748b"; ctx.font = "bold 14px 'Segoe UI', Sans-serif"; ctx.fillText("PLAYER", 50, 385); ctx.fillText("BET AMOUNT", 300, 385); ctx.fillText(isWin ? "PROFIT" : "LOSS", 520, 385); ctx.fillText("NEW BALANCE", 700, 385); ctx.fillStyle = "#ffffff"; ctx.font = "bold 20px 'Segoe UI', Sans-serif"; const shortName = userName.length > 15 ? userName.substring(0, 15) + "..." : userName; ctx.fillText(shortName, 50, 415); ctx.fillStyle = "#38bdf8"; ctx.fillText(`$${this.formatMoney(betAmount)}`, 300, 415); ctx.fillStyle = isWin ? "#4ade80" : "#ef4444"; ctx.fillText(`${isWin ? "+" : "-"}$${this.formatMoney(Math.abs(isWin ? winAmount : betAmount))}`, 520, 415); ctx.fillStyle = "#f1c40f"; ctx.fillText(`$${this.formatMoney(user.balance)}`, 700, 415); // Save and Send Attachment const cacheDir = path.join(__dirname, "cache"); await fs.ensureDir(cacheDir); const cachePath = path.join(cacheDir, `slot_${senderID}_${Date.now()}.png`); await fs.writeFile(cachePath, canvas.toBuffer("image/png")); const payload = { body: isWin ? `šŸŽ‰ š—–š—¢š—”š—šš—„š—”š—§š—Øš—Ÿš—”š—§š—œš—¢š—”š—¦ ${userName.toUpperCase()}!\nšŸ’Ž š—¬š—¢š—Ø š—Ŗš—¢š—” $${this.formatMoney(winAmount)} USD!` : `šŸ’” š—•š—˜š—§š—§š—˜š—„ š—Ÿš—Øš—–š—ž š—”š—˜š—«š—§ š—§š—œš— š—˜ ${userName.toUpperCase()}!\nšŸ“‰ š—¬š—¢š—Ø š—Ÿš—¢š—¦š—§ $${this.formatMoney(betAmount)} USD!`, attachment: fs.createReadStream(cachePath) }; const sendCallback = () => { if (fs.existsSync(cachePath)) fs.unlinkSync(cachePath); }; return message && typeof message.reply === "function" ? message.reply(payload, sendCallback) : api.sendMessage(payload, event.threadID, sendCallback, event.messageID); } catch (err) { console.error(err); return sendMsg("āŒ š—¦š—Ÿš—¢š—§ š—šš—”š— š—˜ š—˜š—„š—„š—¢š—„!"); } } };