Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# The port for the Node.js / Socket.io server
PUBLIC_SERVER_PORT=8001
# The full URL for the client to connect to
<<<<<<< HEAD
PUBLIC_SERVER_URL=http://localhost:8000
=======
PUBLIC_SERVER_URL=http://localhost:8001
>>>>>>> master
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
"@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/kit": "^2.55.0",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"svelte": "^5.55.1",
"svelte": "^5.55.5",
"svelte-check": "^4.3.3",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vite": "^7.3.2",
"vitest": "^4.0.15"
},
"dependencies": {
"dotenv": "^17.3.1",
"dotenv": "^17.4.2",
"express": "^5.2.1",
"express.js": "^1.0.0",
"honeycomb-grid": "^4.1.5",
Expand Down
35 changes: 35 additions & 0 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,55 @@ app.post('/save-map', (req, res) => {
app.post('/create-lobby', (req, res) => {
const { map } = req.body;
const gameId = uuidv4().substring(0, 6); // Shorter ID for easier sharing
const mode = req.body?.mode || 'multi';
const isPublic = req.body?.isPublic || false;
lobbies[gameId] = {
players: {}, // Using object keyed by socket.id
status: 'waiting',
full: false,
turn: 1, // Tracks the current round number (starts at 1)
activePlayer: null, // Tracks whose turn it is
isPublic: isPublic,
fleets: {}, // Secret fleet positions { socketId: { alpha: {q,r}, beta: {q,r} } }
assets: {}, // Tracks assets like fuel, special weapons, etc.
botMemory: { knownHits: [], firedShots: [] },
mode: mode,
history: [], // Stores a log of all moves/strikes for replay or reconnection
fleetPlaced: {},
map: map || null
};
res.json({ gameId, message: 'Lobby created!' });
});

/**
* Matchmaking: Find a lobby that is 'waiting' and has exactly 1 player.
*/
app.get('/find-lobby', (req, res) => {
const gameId = Object.keys(lobbies).find(id => {
const lobby = lobbies[id];
return (
lobby.isPublic &&
lobby.status === 'waiting' &&
!lobby.full &&
Object.keys(lobby.players).length === 1 &&
lobby.mode === 'multi'
);
});
res.json({ gameId: gameId || null });
});

/**
* Dequeue/Delete: Remove a lobby if a player cancels matchmaking or leaves.
*/
app.post('/delete-lobby', (req, res) => {
const { gameId } = req.body;
if (lobbies[gameId]) {
delete lobbies[gameId];
return res.json({ success: true });
}
res.status(404).json({ success: false, error: 'Lobby not found' });
});


// --- SOCKET.IO: GAME LOGIC ---

Expand Down
41 changes: 37 additions & 4 deletions server/socketHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,27 @@ module.exports = (io, lobbies) => {
}


function checkForActionConditions(lobby, socket){
let result = true;

if (!lobby ) {
socket.emit('error', 'Game does not exist');
result = false;
}

else if (lobby.status !== 'active') {
socket.emit('error', 'Game is not active');
result = false;
}

else if (lobby.activePlayer !== socket.id) {
socket.emit('error', 'It is not your turn.');
result = false;
}

return result;
}

const switchTurn = (gameId) => {
const lobby = lobbies[gameId];
if (!lobby) return;
Expand Down Expand Up @@ -405,6 +426,10 @@ module.exports = (io, lobbies) => {
delete lobby.fleets[socketId];
if (lobby.assets) delete lobby.assets[socketId];

if (Object.keys(lobby.players).length < 2) {
lobby.full = false;
}

if (lobby.status === 'active' && Object.keys(lobby.players).length > 0) {
const winnerId = Object.keys(lobby.players)[0];
lobby.status = 'game_over';
Expand Down Expand Up @@ -449,6 +474,10 @@ module.exports = (io, lobbies) => {
return;
}

if (Object.keys(lobby.players).length == 1) {
lobby.full = true;
}

socket.join(gameId);

lobby.players[socket.id] = {
Expand Down Expand Up @@ -554,13 +583,16 @@ module.exports = (io, lobbies) => {


// Handle the "Finish" - Strike Logic
socket.on('execute_strike', ({ gameId, targetHex, dieResult1, dieResult2 }) => {
socket.on('execute_strike', ({ gameId, sourceFleet, targetHex, dieResult1, dieResult2 }) => {
const lobby = lobbies[gameId];


// Calculate the shortest distance from a living friendly fleet to the target hex
const attackerFleets = lobby.fleets[socket.id];
const firingFleet = attackerFleets[sourceFleet];
console.log("fire" + firingFleet)
const distances = [];

if (attackerFleets.alpha && attackerFleets.alpha.hp > 0) {
distances.push(calculateHexDistance(attackerFleets.alpha, targetHex));
}
Expand All @@ -570,6 +602,7 @@ module.exports = (io, lobbies) => {
}

const shortestDistance = distances.length > 0 ? Math.min(...distances) : Infinity;
lobby.lastAttackerPos = { q: firingFleet.q, r: firingFleet.r };

// Find the opponent
const opponentId = Object.keys(lobby.players).find(id => id !== socket.id);
Expand Down Expand Up @@ -659,13 +692,13 @@ module.exports = (io, lobbies) => {
}

const isSuccess = counterResult >= 3;
console.log("sad" + lobby.lastAttackerPos);

io.to(gameId).emit('counter_result', {
success: isSuccess
success: isSuccess,
attackerPos : isSuccess ? lobby.lastAttackerPos : null
});

console.log("ASTFASTF");

switchTurn(gameId);
});

Expand Down
14 changes: 8 additions & 6 deletions src/lib/+map.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,12 @@
}
});

$socket.on("counter_result", ({success}) => {
$socket.on("counter_result", ({success, attackerPos}) => {

console.log("COUNTTEERRRR RESULTTTTTT");
if(isMyTurn){
if (success) {
enemySearchedHexes = [...enemySearchedHexes, { q: sourceFleet.q, r: sourceFleet.r }];
enemySearchedHexes = [...enemySearchedHexes, { q: attackerPos.q, r: attackerPos.r }];
triggerOverlay("WARNING: LOCATION COMPROMISED!", "fail");
addLog("WARNING: Enemy traced your firing signal!", "enemy");
setTimeout(() => handleTurnEnd(), 2000);
Expand All @@ -294,10 +294,8 @@
}
}
else{
console.log("not my turn");
if (success) {
const attacker = enemyFleets[Math.floor(Math.random() * enemyFleets.length)];
friendlySearchedHexes = [...friendlySearchedHexes, { q: attacker.q, r: attacker.r }];
friendlySearchedHexes = [...friendlySearchedHexes, { q: attackerPos.q, r: attackerPos.r }];
triggerOverlay("ENEMY SIGNAL TRACED!", "success");
} else {
triggerOverlay("SIGNAL TRACE FAILED!", "fail");
Expand Down Expand Up @@ -408,7 +406,6 @@

const coordStr = `${String.fromCharCode(65 + hex.col)}-${hex.row + 1}`; // e.g., "A-1"

console.log("hiii" + targetEnemy);
if(targetEnemy){
const friendlyFleet = fleetSelections.find(f => f.q === hex.q && f.r === hex.r);

Expand Down Expand Up @@ -531,6 +528,7 @@
addLog("All fleets are positioned!", "system");
isPlacementLocked = true;
if ($isMultiplayer) {
console.log("wooooo");
const fleetPositions = { alpha: { q: fleetSelections[0].q, r: fleetSelections[0].r }, beta: { q: fleetSelections[1].q, r: fleetSelections[1].r } };
$socket.emit('place_fleets', { gameId: $gameId, fleetPositions });
$socket.once('fleets_placed_confirmation', () => { $socket.emit('ready_check', {gameId: $gameId}); });
Expand Down Expand Up @@ -626,6 +624,9 @@
function resolveAttack() {
if (!sourceFleet || !targetEnemy) return;

const fleetIndex = fleetSelections.findIndex(f => f.id === sourceFleet.id);
const fleetKey = fleetIndex === 0 ? 'alpha' : 'beta';

const targetCoord = `${String.fromCharCode(65 + targetEnemy.col)}-${targetEnemy.row + 1}`;
addLog(`[${sourceFleet.name}] firing on coordinates ${targetCoord}...`, "player");

Expand All @@ -646,6 +647,7 @@
if ($isMultiplayer) {
$socket.emit('execute_strike', {
gameId: $gameId,
sourceFleet: fleetKey,
targetHex: { q: cachedTarget.q, r: cachedTarget.r },
dieResult1: roll1,
dieResult2: roll2
Expand Down
4 changes: 2 additions & 2 deletions src/lib/Sidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,10 @@
.panel-header {
font-family: 'Chakra Petch', sans-serif;
color: #abbbd1;
font-size: clamp(1.2rem, 3vh, 1.8rem);
font-size: clamp(0.6rem, 3vh, 1rem);
border-bottom: 1px solid rgba(171, 187, 209, 0.3);
padding-bottom: 10px;
letter-spacing: 2px;
letter-spacing: 1px;
}

/*Focus, Directional, Area, Activate*/
Expand Down
2 changes: 1 addition & 1 deletion src/lib/StatusBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@
/*HEALTH and FUEL*/
.stat-label {
font-family: 'Chakra Petch', sans-serif;
font-size: clamp(0.9rem, 3vh, 1.2rem);
font-size: clamp(0.4rem, 3vh, 0.8rem);
color: #abbbd1;
letter-spacing: 2px;
font-weight: 700;
Expand Down
Loading
Loading