diff --git a/flopobot.db-shm b/flopobot.db-shm index db6d44f..c65a141 100644 Binary files a/flopobot.db-shm and b/flopobot.db-shm differ diff --git a/flopobot.db-wal b/flopobot.db-wal index 9cf605d..0822f6f 100644 Binary files a/flopobot.db-wal and b/flopobot.db-wal differ diff --git a/index.js b/index.js index f6a88c8..70ca00d 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ const server = http.createServer(app); // --- SOCKET.IO INITIALIZATION --- const FLAPI_URL = process.env.DEV_SITE === 'true' ? process.env.FLAPI_URL_DEV : process.env.FLAPI_URL; -const io = new Server(server, { +export const io = new Server(server, { cors: { origin: FLAPI_URL, methods: ['GET', 'POST', 'PUT', 'OPTIONS'], diff --git a/src/game/elo.js b/src/game/elo.js index cddc8ae..ee02ae5 100644 --- a/src/game/elo.js +++ b/src/game/elo.js @@ -52,8 +52,8 @@ export async function eloHandler(p1Id, p2Id, p1Score, p2Score, type) { const p2NewElo = Math.round(p2CurrentElo + K_FACTOR * (p2Score - expectedP2)); // Ensure Elo doesn't drop below a certain threshold (e.g., 100) - const finalP1Elo = Math.max(100, p1NewElo); - const finalP2Elo = Math.max(100, p2NewElo); + const finalP1Elo = Math.max(0, p1NewElo); + const finalP2Elo = Math.max(0, p2NewElo); console.log(`Elo Update (${type}) for ${p1DB.globalName}: ${p1CurrentElo} -> ${finalP1Elo}`); console.log(`Elo Update (${type}) for ${p2DB.globalName}: ${p2CurrentElo} -> ${finalP2Elo}`); @@ -136,6 +136,7 @@ export async function pokerEloHandler(room) { p1_new_elo: newElo, p2_new_elo: null, type: 'POKER_ROUND', + timestamp: Date.now(), }); } else { console.error(`Error calculating new Elo for ${player.globalName}.`); diff --git a/src/server/app.js b/src/server/app.js index 13bd90a..2ad3892 100644 --- a/src/server/app.js +++ b/src/server/app.js @@ -42,7 +42,7 @@ app.use('/public', express.static('public')); app.use('/', apiRoutes(client)); // Poker-specific routes -app.use('/poker-room', pokerRoutes(client)); +app.use('/', pokerRoutes(client)); // Solitaire-specific routes app.use('/solitaire', solitaireRoutes(client)); diff --git a/src/server/routes/poker.js b/src/server/routes/poker.js index c10f0b4..e724b60 100644 --- a/src/server/routes/poker.js +++ b/src/server/routes/poker.js @@ -7,6 +7,8 @@ import { initialShuffledCards, getFirstActivePlayerAfterDealer, getNextActivePla import { pokerEloHandler } from '../../game/elo.js'; import { getUser, updateUserCoins, insertLog } from '../../database/index.js'; import {sleep} from "openai/core"; +import {client} from "../../bot/client.js"; +import { io } from '../../../index.js' // Create a new router instance const router = express.Router(); @@ -14,18 +16,17 @@ const router = express.Router(); /** * Factory function to create and configure the poker API routes. * @param {object} client - The Discord.js client instance. - * @param {object} io - The Socket.IO server instance. * @returns {object} The configured Express router. */ -export function pokerRoutes(client, io) { +export function pokerRoutes(client) { // --- Room Management Endpoints --- - router.get('/', (req, res) => { + router.get('/poker-rooms', (req, res) => { res.status(200).json({ rooms: pokerRooms }); }); - router.get('/:id', (req, res) => { + router.get('/poker-rooms/:id', (req, res) => { const room = pokerRooms[req.params.id]; if (room) { res.status(200).json({ room }); @@ -34,7 +35,7 @@ export function pokerRoutes(client, io) { } }); - router.post('/create', async (req, res) => { + router.post('/create-poker-room', async (req, res) => { const { creatorId } = req.body; if (!creatorId) return res.status(400).json({ message: 'Creator ID is required.' }); @@ -55,6 +56,7 @@ export function pokerRoutes(client, io) { last_move_at: Date.now(), players: {}, queue: {}, + afk: {}, pioche: initialShuffledCards(), tapis: [], dealer: null, @@ -76,7 +78,7 @@ export function pokerRoutes(client, io) { res.status(201).json({ roomId: id }); }); - router.post('/join', async (req, res) => { + router.post('/poker-room/join', async (req, res) => { const { userId, roomId } = req.body; if (!userId || !roomId) return res.status(400).json({ message: 'User ID and Room ID are required.' }); if (!pokerRooms[roomId]) return res.status(404).json({ message: 'Room not found.' }); @@ -89,15 +91,15 @@ export function pokerRoutes(client, io) { res.status(200).json({ message: 'Successfully joined room.' }); }); - router.post('/leave', (req, res) => { + router.post('poker-room/leave', (req, res) => { // Implement leave logic... res.status(501).json({ message: "Not Implemented" }); }); // --- Game Action Endpoints --- - router.post('/:roomId/start', async (req, res) => { - const { roomId } = req.params; + router.post('/poker-room/start', async (req, res) => { + const { roomId } = req.body; const room = pokerRooms[roomId]; if (!room) return res.status(404).json({ message: 'Room not found.' }); if (Object.keys(room.players).length < 2) return res.status(400).json({ message: 'Not enough players to start.' }); @@ -106,9 +108,9 @@ export function pokerRoutes(client, io) { res.status(200).json({ message: 'Game started.' }); }); - router.post('/:roomId/action', async (req, res) => { - const { roomId } = req.params; - const { playerId, action, amount } = req.body; + router.post('/poker-room/action/:action', async (req, res) => { + const { playerId, amount, roomId } = req.body; + const { action } = req.params; const room = pokerRooms[roomId]; if (!room || !room.players[playerId] || room.current_player !== playerId) { @@ -295,7 +297,7 @@ async function handleShowdown(room, io, winners) { updatePlayerCoins(winnerPlayer, winAmount, room.fakeMoney); }); - await pokerEloHandler(room); + //await pokerEloHandler(room); io.emit('poker-update', { type: 'showdown', room, winners, winAmount }); } @@ -309,6 +311,7 @@ function updatePlayerCoins(player, amount, isFake) { insertLog.run({ id: `${player.id}-poker-${Date.now()}`, user_id: player.id, + target_user_id: null, action: `POKER_${amount > 0 ? 'WIN' : 'BET'}`, coins_amount: amount, user_new_amount: newCoins, diff --git a/src/server/socket.js b/src/server/socket.js index 1424b55..1cb99a1 100644 --- a/src/server/socket.js +++ b/src/server/socket.js @@ -70,6 +70,25 @@ async function onQueueJoin(client, gameType, playerId) { await emitQueueUpdate(client, gameType); } +/** + * A helper function to check for a win in Tic-Tac-Toe. + * @param {Array} moves - An array of the player's moves (e.g., [1, 5, 9]). + * @returns {boolean} - True if the player has won, false otherwise. + */ +function checkTicTacToeWin(moves) { + const winningCombinations = [ + [1, 2, 3], [4, 5, 6], [7, 8, 9], // Rows + [1, 4, 7], [2, 5, 8], [3, 6, 9], // Columns + [1, 5, 9], [3, 5, 7] // Diagonals + ]; + for (const combination of winningCombinations) { + if (combination.every(num => moves.includes(num))) { + return true; + } + } + return false; +} + async function onTicTacToeMove(client, eventData) { const { playerId, value, boxId } = eventData; const lobby = Object.values(activeTicTacToeGames).find(g => (g.p1.id === playerId || g.p2.id === playerId) && !g.gameOver); @@ -79,11 +98,26 @@ async function onTicTacToeMove(client, eventData) { const isP2Turn = lobby.sum % 2 === 0 && value === 'O' && lobby.p2.id === playerId; if (isP1Turn || isP2Turn) { - (isP1Turn) ? lobby.xs.push(boxId) : lobby.os.push(boxId); + const playerMoves = isP1Turn ? lobby.xs : lobby.os; + playerMoves.push(boxId); lobby.sum++; lobby.lastmove = Date.now(); - await updateDiscordMessage(client, lobby, 'Tic Tac Toe'); + + if (isP1Turn) lobby.p1.move = boxId + if (isP2Turn) lobby.p2.move = boxId + io.emit('tictactoeplaying', { allPlayers: Object.values(activeTicTacToeGames) }); + const hasWon = checkTicTacToeWin(playerMoves); + if (hasWon) { + // The current player has won. End the game. + await onGameOver(client, 'tictactoe', playerId, playerId); + } else if (lobby.sum > 9) { + // It's a draw (9 moves made, sum is now 10). End the game. + await onGameOver(client, 'tictactoe', playerId, null); // null winner for a draw + } else { + // The game continues. Update the state and notify clients. + await updateDiscordMessage(client, lobby, 'Tic Tac Toe'); + } } await emitQueueUpdate(client, 'tictactoe'); } @@ -145,9 +179,8 @@ async function onGameOver(client, gameType, playerId, winnerId, reason = '') { if(gameType === 'connect4') io.emit('connect4gameOver', { game, winner: winnerId }); if (gameKey) { - setTimeout(() => delete activeGames[gameKey], 10000); + setTimeout(() => delete activeGames[gameKey], 1000) } - await emitQueueUpdate(client, gameType); } // --- Game Lifecycle & Discord Helpers ---