Compare commits
3 Commits
66a9e59db6
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1149687e3c | |||
| 3cf338d014 | |||
| 23ae455ec1 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "shelem",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.7",
|
||||
"description": "Shelem card game — multiplayer",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
||||
+4
-4
@@ -235,7 +235,7 @@ function show(id) { const el = $(id); if (el) el.classList.remove('hidden'); }
|
||||
function hide(id) { const el = $(id); if (el) el.classList.add('hidden'); }
|
||||
|
||||
function cardSvg(code) {
|
||||
if (code === 'JOKER-COLOR') return '/cards/JOKER-1.svg';
|
||||
if (code === 'JOKER-COLOR') return '/cards/JOKER-3.svg';
|
||||
if (code === 'JOKER-BLACK') return '/cards/JOKER-2.svg';
|
||||
const [suit, rank] = code.split('-');
|
||||
const suitMap = { C: 'CLUB', D: 'DIAMOND', H: 'HEART', S: 'SPADE' };
|
||||
@@ -1037,7 +1037,7 @@ function renderWidowOverlay(st) {
|
||||
updateWidowPreview(st);
|
||||
}
|
||||
|
||||
const WIDOW_SUIT_ORDER = ['C', 'D', 'H', 'S'];
|
||||
const WIDOW_SUIT_ORDER = ['C', 'D', 'S', 'H'];
|
||||
const WIDOW_SUIT_LABEL = { C: '♣', D: '♦', H: '♥', S: '♠' };
|
||||
const WIDOW_JOKER_LABEL = { 'JOKER-COLOR': '🌈', 'JOKER-BLACK': '⚫' };
|
||||
|
||||
@@ -1179,7 +1179,7 @@ function onHandOver(st) {
|
||||
const isWinner = mySeat >= 0 && teamOf(mySeat) === team && delta > 0;
|
||||
if (isWinner) row.classList.add('winner');
|
||||
row.innerHTML = `
|
||||
<span class="team-label">${names}</span>
|
||||
<span class="team-label">${escHtml(names)}</span>
|
||||
<span class="delta ${delta >= 0 ? 'pos' : 'neg'}">${delta >= 0 ? '+' : ''}${delta}</span>
|
||||
<span style="color:rgba(255,255,255,.6);font-size:.8rem">→ ${st.scores[team]}</span>
|
||||
`;
|
||||
@@ -1211,7 +1211,7 @@ function onGameOver(st) {
|
||||
.filter(Boolean).join(' & ') || `Team ${team + 1}`;
|
||||
const row = document.createElement('div');
|
||||
row.className = 'gameover-row' + (winTeams.has(team) ? ' winner' : '');
|
||||
row.innerHTML = `<span>${names}</span><span style="font-weight:700;color:${team===0?'var(--team-a)':'var(--team-b)'}">${st.scores[team]}</span>`;
|
||||
row.innerHTML = `<span>${escHtml(names)}</span><span style="font-weight:700;color:${team===0?'var(--team-a)':'var(--team-b)'}">${st.scores[team]}</span>`;
|
||||
scoresEl.appendChild(row);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,17 @@ const bcrypt = require('bcryptjs');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const app = express();
|
||||
app.disable('x-powered-by'); // don't advertise the tech stack
|
||||
|
||||
// Safe security headers (no CSP here — inline SW script + socket.io would need
|
||||
// 'unsafe-inline'/wss exceptions; Cloudflare already terminates TLS/HSTS)
|
||||
app.use((_req, res, next) => {
|
||||
res.setHeader('X-Content-Type-Options', 'nosniff');
|
||||
res.setHeader('X-Frame-Options', 'DENY');
|
||||
res.setHeader('Referrer-Policy', 'no-referrer');
|
||||
next();
|
||||
});
|
||||
|
||||
const httpServer = http.createServer(app);
|
||||
|
||||
let httpsServer = null;
|
||||
@@ -351,7 +362,8 @@ function trumpRank(card) {
|
||||
}
|
||||
|
||||
// Suit display order: C D H S JOKER
|
||||
const SUIT_ORD = { C: 0, D: 1, H: 2, S: 3, JOKER: 4 };
|
||||
// Alternate colours (black-red-black-red) so same-colour suits aren't adjacent
|
||||
const SUIT_ORD = { C: 0, D: 1, S: 2, H: 3, JOKER: 4 };
|
||||
function sortCards(hand) {
|
||||
return [...hand].sort((a, b) => {
|
||||
const sa = SUIT_ORD[suitOf(a)], sb = SUIT_ORD[suitOf(b)];
|
||||
|
||||
Reference in New Issue
Block a user