Files
cell/examples/chess/main.js
2025-05-21 10:34:33 -05:00

300 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* main.js runs the demo with your prototype-based grid */
var moth = use('moth')
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;
prosperon.on('mouse_button_down', function(e) {
if (e.which !== 0) 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;
} else {
selectPos = null;
}
})
prosperon.on('mouse_button_up', function(e) {
if (e.which !== 0 || !holdingPiece || !selectPos) 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;
}
// Only allow moves if it's our turn or we're in local mode
if (gameState !== 'connected' || isMyTurn) {
if (mover.tryMove(grid.at(selectPos)[0], c)) {
// Send move to opponent if connected
if (gameState === 'connected' && opponent) {
$_.send(opponent, {
type: 'move',
from: selectPos,
to: c
});
isMyTurn = false; // It's now opponent's turn
}
selectPos = null;
updateTitle();
}
}
holdingPiece = false;
})
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;
})
/*──── 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 hoverColor = [0.8, 1.0, 0.8, 1.0];
var validMoveColor = [1.0, 0.8, 0.8, 1.0];
/* ── draw one 8×8 chess board ──────────────────────────────────── */
function drawBoard() {
for (var y = 0; y < 8; ++y)
for (var x = 0; x < 8; ++x) {
var isHovered = hoverPos && hoverPos[0] === x && hoverPos[1] === y;
var isValidMove = selectPos && holdingPiece && isValidMoveForTurn(selectPos, [x, y]);
var color = ((x+y)&1) ? dark : light;
if (isHovered && !isValidMove) {
color = hoverColor;
} else if (isValidMove) {
color = validMoveColor;
}
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
if (holdingPiece && selectPos &&
piece.coord[0] === selectPos[0] &&
piece.coord[1] === selectPos[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"});
}
}
}
prosperon.on('draw', function() {
drawBoard()
drawPieces()
})
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 => {
opponent = e;
gameState = 'connected';
updateTitle();
// Tell the joining player they are black
$_.send(opponent, {
type: 'game_start',
your_color: 'black'
});
}, 5678);
}
function joinServer() {
gameState = 'searching';
updateTitle();
function contact_fn(actor, reason) {
console.log("CONTACTED!")
if (actor) {
opponent = actor;
gameState = 'connected';
myColor = 'black';
isMyTurn = false;
updateTitle();
} else {
console.log(`Failed to connect: ${json.encode(reason)}`);
gameState = 'waiting';
updateTitle();
}
}
$_.contact(contact_fn, {
address: "localhost",
port: 5678
});
}
var os = use('os')
// Set up IO actor subscription
var ioguy = {
__ACTORDATA__: {
id: os.ioactor()
}
};
$_.send(ioguy, {
type: "subscribe",
actor: $_
});
$_.receiver(e => {
if (e.type === 'quit') os.exit()
if (e.type === 'game_start') {
myColor = e.your_color;
isMyTurn = (myColor === 'white');
updateTitle();
} else if (e.type === 'move') {
// 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();
}
}
}
prosperon.dispatch(e.type, e)
})