/* main.js – runs the demo with your prototype-based grid */ var moth = use('moth', $_.delay) var json = use('json') var res = 160 var internal_res = 480 moth.initialize({ width:res, height:res, resolution_x:internal_res, resolution_y:internal_res, mode:'letterbox' }); var os = use('os'); var draw2d = use('draw2d'); var gfx = use('graphics'); /*──── import our pieces + systems ───────────────────────────────────*/ var Grid = use('grid'); // your new ctor var MovementSystem = use('movement').MovementSystem; var startingPos = use('pieces').startingPosition; var rules = use('rules'); /*──── build board ───────────────────────────────────────────────────*/ var grid = new Grid(8, 8); grid.width = 8; // (the ctor didn't store them) grid.height = 8; var mover = new MovementSystem(grid, rules); startingPos(grid); /*──── networking and game state ─────────────────────────────────────*/ var gameState = 'waiting'; // 'waiting', 'searching', 'server_waiting', 'connected' var isServer = false; var opponent = null; var myColor = null; // 'white' or 'black' var isMyTurn = false; function updateTitle() { var title = "Misty Chess - "; switch(gameState) { case 'waiting': title += "Press S to start server or J to join"; break; case 'searching': title += "Searching for server..."; break; case 'server_waiting': title += "Waiting for player to join..."; break; case 'connected': if (myColor) { title += (mover.turn === myColor ? "Your turn (" + myColor + ")" : "Opponent's turn (" + mover.turn + ")"); } else { title += mover.turn + " turn"; } break; } prosperon.window.title = title } // Initialize title updateTitle(); /*──── mouse → click-to-move ─────────────────────────────────────────*/ var selectPos = null; var hoverPos = null; var holdingPiece = false; var opponentMousePos = null; var opponentHoldingPiece = false; var opponentSelectPos = null; prosperon.on('mouse_button_down', function(e) { if (e.which !== 0) return; // Don't allow piece selection unless we have an opponent if (gameState !== 'connected' || !opponent) return; var mx = e.mouse.x; var my = e.mouse.y; var c = [Math.floor(mx / 60), Math.floor(my / 60)]; if (!grid.inBounds(c)) return; var cell = grid.at(c); if (cell.length && cell[0].colour === mover.turn) { selectPos = c; holdingPiece = true; // Send pickup notification to opponent if (opponent) { send(opponent, { type: 'piece_pickup', pos: c }); } } else { selectPos = null; } }) prosperon.on('mouse_button_up', function(e) { if (e.which !== 0 || !holdingPiece || !selectPos) return; // Don't allow moves unless we have an opponent and it's our turn if (gameState !== 'connected' || !opponent || !isMyTurn) { holdingPiece = false; return; } var mx = e.mouse.x; var my = e.mouse.y; var c = [Math.floor(mx / 60), Math.floor(my / 60)]; if (!grid.inBounds(c)) { holdingPiece = false; return; } if (mover.tryMove(grid.at(selectPos)[0], c)) { console.log("Made move from", selectPos, "to", c); // Send move to opponent console.log("Sending move to opponent:", opponent); send(opponent, { type: 'move', from: selectPos, to: c }); isMyTurn = false; // It's now opponent's turn console.log("Move sent, now opponent's turn"); selectPos = null; updateTitle(); } holdingPiece = false; // Send piece drop notification to opponent if (opponent) { send(opponent, { type: 'piece_drop' }); } }) prosperon.on('mouse_motion', function(e) { var mx = e.pos.x; var my = e.pos.y; var c = [Math.floor(mx / 60), Math.floor(my / 60)]; if (!grid.inBounds(c)) { hoverPos = null; return; } hoverPos = c; // Send mouse position to opponent in real-time if (opponent && gameState === 'connected') { send(opponent, { type: 'mouse_move', pos: c, holding: holdingPiece, selectPos: selectPos }); } }) /*──── drawing helpers ───────────────────────────────────────────────*/ /* ── constants ─────────────────────────────────────────────────── */ var S = 60; // square size in px var light = [0.93,0.93,0.93,1]; var dark = [0.25,0.25,0.25,1]; var allowedColor = [1.0, 0.84, 0.0, 1.0]; // Gold for allowed moves var myMouseColor = [0.0, 1.0, 0.0, 1.0]; // Green for my mouse var opponentMouseColor = [1.0, 0.0, 0.0, 1.0]; // Red for opponent mouse /* ── draw one 8×8 chess board ──────────────────────────────────── */ function drawBoard() { for (var y = 0; y < 8; ++y) for (var x = 0; x < 8; ++x) { var isMyHover = hoverPos && hoverPos[0] === x && hoverPos[1] === y; var isOpponentHover = opponentMousePos && opponentMousePos[0] === x && opponentMousePos[1] === y; var isValidMove = selectPos && holdingPiece && isValidMoveForTurn(selectPos, [x, y]); var color = ((x+y)&1) ? dark : light; if (isValidMove) { color = allowedColor; // Gold for allowed moves } else if (isMyHover && !isOpponentHover) { color = myMouseColor; // Green for my mouse } else if (isOpponentHover) { color = opponentMouseColor; // Red for opponent mouse } draw2d.rectangle( { x: x*S, y: y*S, width: S, height: S }, { thickness: 0, color: color } ); } } function isValidMoveForTurn(from, to) { if (!grid.inBounds(to)) return false; var piece = grid.at(from)[0]; if (!piece) return false; // Check if the destination has a piece of the same color var destCell = grid.at(to); if (destCell.length && destCell[0].colour === piece.colour) { return false; } return rules.canMove(piece, from, to, grid); } /* ── draw every live piece ─────────────────────────────────────── */ function drawPieces() { grid.each(function (piece) { if (piece.captured) return; // Skip drawing the piece being held (by me or opponent) if (holdingPiece && selectPos && piece.coord[0] === selectPos[0] && piece.coord[1] === selectPos[1]) { return; } // Skip drawing the piece being held by opponent if (opponentHoldingPiece && opponentSelectPos && piece.coord[0] === opponentSelectPos[0] && piece.coord[1] === opponentSelectPos[1]) { return; } var r = { x: piece.coord[0]*S, y: piece.coord[1]*S, width:S, height:S }; draw2d.image(piece.sprite, r, 0, [0,0], [0,0], {mode:"nearest"}); }); // Draw the held piece at the mouse position if we're holding one if (holdingPiece && selectPos && hoverPos) { var piece = grid.at(selectPos)[0]; if (piece) { var r = { x: hoverPos[0]*S, y: hoverPos[1]*S, width:S, height:S }; draw2d.image(piece.sprite, r, 0, [0,0], [0,0], {mode:"nearest"}); } } // Draw opponent's held piece if they're dragging one if (opponentHoldingPiece && opponentSelectPos && opponentMousePos) { var opponentPiece = grid.at(opponentSelectPos)[0]; if (opponentPiece) { var r = { x: opponentMousePos[0]*S, y: opponentMousePos[1]*S, width:S, height:S }; // Draw with slight transparency to show it's the opponent's piece draw2d.image(opponentPiece.sprite, r, 0, [0,0], [0,0], {mode:"nearest", color: [1, 1, 1, 0.7]}); } } } var graphics = use('graphics') prosperon.on('draw', function() { drawBoard() drawPieces() draw2d.text("HELL", [100,100]) }) prosperon.on('key_down', function(e) { // S key - start server if (e.scancode === 22 && gameState === 'waiting') { // S key startServer(); } // J key - join server else if (e.scancode === 13 && gameState === 'waiting') { // J key joinServer(); } }) function startServer() { gameState = 'server_waiting'; isServer = true; myColor = 'white'; isMyTurn = true; updateTitle(); $_.portal(e => { console.log("Portal received contact message"); // Reply with this actor to establish connection console.log (json.encode($_)) send(e, $_); console.log("Portal replied with server actor"); }, 5678); } function joinServer() { gameState = 'searching'; updateTitle(); function contact_fn(actor, reason) { console.log("CONTACTED!", actor ? "SUCCESS" : "FAILED", reason); if (actor) { opponent = actor; console.log("Connection established with server, sending join request"); // Send a greet message with our actor object send(opponent, { type: 'greet', client_actor: $_ }); } else { console.log(`Failed to connect: ${json.encode(reason)}`); gameState = 'waiting'; updateTitle(); } } $_.contact(contact_fn, { address: "192.168.0.149", port: 5678 }); } var os = use('os') var actor = use('actor') for (var i in actor) console.log(i) // Set up IO actor subscription var ioguy = { __ACTORDATA__: { id: actor.ioactor() } }; send(ioguy, { type: "subscribe", actor: $_ }); $_.receiver(e => { if (e.type === 'game_start' || e.type === 'move' || e.type === 'greet') console.log("Receiver got message:", e.type, e); if (e.type === 'quit') os.exit() if (e.type === 'greet') { console.log("Server received greet from client"); // Store the client's actor object for ongoing communication opponent = e.client_actor; console.log("Stored client actor:", json.encode(opponent)); gameState = 'connected'; updateTitle(); // Send game_start to the client console.log("Sending game_start to client"); send(opponent, { type: 'game_start', your_color: 'black' }); console.log("game_start message sent to client"); } else if (e.type === 'game_start') { console.log("Game starting, I am:", e.your_color); myColor = e.your_color; isMyTurn = (myColor === 'white'); gameState = 'connected'; updateTitle(); } else if (e.type === 'move') { console.log("Received move from opponent:", e.from, "to", e.to); // Apply opponent's move var fromCell = grid.at(e.from); if (fromCell.length) { var piece = fromCell[0]; if (mover.tryMove(piece, e.to)) { isMyTurn = true; // It's now our turn updateTitle(); console.log("Applied opponent move, now my turn"); } else { console.log("Failed to apply opponent move"); } } else { console.log("No piece found at from position"); } } else if (e.type === 'mouse_move') { // Update opponent's mouse position opponentMousePos = e.pos; opponentHoldingPiece = e.holding; opponentSelectPos = e.selectPos; } else if (e.type === 'piece_pickup') { // Opponent picked up a piece opponentSelectPos = e.pos; opponentHoldingPiece = true; } else if (e.type === 'piece_drop') { // Opponent dropped their piece opponentHoldingPiece = false; opponentSelectPos = null; } prosperon.dispatch(e.type, e) })