https://www4.chesstempo.com/images/pieces/svg/merida/whitepawn.vers1.svg (...)
+ Adaptation for checkered pieces
Some fairy pieces found on the web and icon scout: https://iconscout.com/
+PNG images for Eightpieces from https://greenchess.net/index.php and Jeff Kubach design.
@media screen and (max-width: 420px)
footer
+ height: 55px
display: block
+ padding: 5px 0
.menuitem.somenews
color: red
const playSubmove = (smove) => {
if (!navigate) smove.notation = this.vr.getNotation(smove);
this.vr.play(smove);
+ this.lastMove = smove;
if (!navigate) {
if (!this.inMultimove) {
if (this.cursor < this.moves.length - 1)
smove.fen = this.vr.getFen();
// Is opponent in check?
this.incheck = this.vr.getCheckSquares(this.vr.turn);
- this.lastMove = smove;
this.emitFenIfAnalyze();
this.inMultimove = false;
if (!noemit) {
const deltaCreated = maxCreated - minCreated;
return remGames.sort((g1, g2) => {
return (
- g2.priority - g1.priority + (g2.created - g1.created) / deltaCreated
+ g2.priority - g1.priority +
+ // Modulate with creation time (value in ]0,1[)
+ (g2.created - g1.created) / (deltaCreated + 1)
);
});
},
Register: "Register",
"Registration complete! Please check your emails now": "Registration complete! Please check your emails now",
Rematch: "Rematch",
- "Rematch in progress:": "Rematch in progress",
+ "Rematch in progress": "Rematch in progress",
"Remove game?": "Remove game?",
Resign: "Resign",
"Resign the game?": "Resign the game?",
Register: "Registrarse",
"Registration complete! Please check your emails now": "¡Registro completo! Revise sus correos electrónicos ahora",
Rematch: "Revancha",
- "Rematch in progress:": "Revancha en progreso:",
+ "Rematch in progress": "Revancha en progreso",
"Remove game?": "¿Eliminar la partida?",
Resign: "Abandonar",
"Resign the game?": "¿Abandonar la partida?",
Register: "S'enregistrer",
"Registration complete! Please check your emails now": "Enregistrement terminé ! Allez voir vos emails maintenant",
Rematch: "Rejouer",
- "Rematch in progress:": "Revanche en cours :",
+ "Rematch in progress": "Revanche en cours",
"Remove game?": "Supprimer la partie ?",
Resign: "Abandonner",
"Resign the game?": "Abandonner la partie ?",
return false;
}
let sq = [ x1 + step[0], y1 + step[1] ];
- while (sq[0] != x2 && sq[1] != y2) {
+ while (sq[0] != x2 || sq[1] != y2) {
if (
// NOTE: no need to check OnBoard in this special case
(!lancer && this.board[sq[0]][sq[1]] != V.EMPTY) ||
return (!choice.second ? choice : [choice, choice.second]);
}
+ // For moves notation:
+ static get LANCER_DIRNAMES() {
+ return {
+ 'c': "N",
+ 'd': "NE",
+ 'e': "E",
+ 'f': "SE",
+ 'g': "S",
+ 'h': "SW",
+ 'm': "W",
+ 'o': "NW"
+ };
+ }
+
getNotation(move) {
// Special case "king takes jailer" is a pass move
if (move.appear.length == 0 && move.vanish.length == 0) return "pass";
+ let notation = undefined;
if (this.subTurn == 2) {
// Do not consider appear[1] (sentry) for sentry pushes
const simpleMove = {
start: move.start,
end: move.end
};
- return super.getNotation(simpleMove);
- }
- return super.getNotation(move);
+ notation = super.getNotation(simpleMove);
+ } else notation = super.getNotation(move);
+ if (Object.keys(V.LANCER_DIRNAMES).includes(move.vanish[0].p))
+ // Lancer: add direction info
+ notation += "=" + V.LANCER_DIRNAMES[move.appear[0].p];
+ return notation;
}
};
)
.card.text-center
label.modal-close(for="modalInfo")
- p
- span {{ st.tr["Rematch in progress:"] }}
- a(
- :href="'#/game/' + rematchId"
- onClick="document.getElementById('modalInfo').checked=false"
- )
- | {{ "#/game/" + rematchId }}
+ a(
+ :href="'#/game/' + rematchId"
+ onClick="document.getElementById('modalInfo').checked=false"
+ )
+ | {{ st.tr["Rematch in progress"] }}
input#modalChat.modal(
type="checkbox"
@click="resetChatColor()"
)
||
(
- player.id &&
+ !!player.id &&
Object.values(this.people).some(p =>
p.id == player.id && p.focus)
)
cadence: this.game.cadence
};
const notifyNewGame = () => {
- let oppsid = this.getOppsid(); //may be null
+ const oppsid = this.getOppsid(); //may be null
this.send("rnewgame", { data: gameInfo, oppsid: oppsid });
+ // To main Hall if corr game:
+ if (this.game.type == "corr")
+ this.send("newgame", { data: gameInfo });
// Also to MyGames page:
this.notifyMyGames("newgame", gameInfo);
};
const mycolor = [undefined, "w", "b"][myIdx + 1]; //undefined for observers
if (!game.chats) game.chats = []; //live games don't have chat history
if (gtype == "corr") {
- if (game.players[0].color == "b") {
- // Adopt the same convention for live and corr games: [0] = white
- [game.players[0], game.players[1]] = [
- game.players[1],
- game.players[0]
- ];
- }
// NOTE: clocks in seconds, initime in milliseconds
game.moves.sort((m1, m2) => m1.idx - m2.idx); //in case of
game.clocks = [tc.mainTime, tc.mainTime];
const L = game.moves.length;
if (game.score == "*") {
// Set clocks + initime
- game.initime = [0, 0];
+ game.initime = [Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER];
if (L >= 1) game.initime[L % 2] = game.moves[L-1].played;
// NOTE: game.clocks shouldn't be computed right now:
// job will be done in re_setClocks() called soon below.
game.moves = game.moves.map(m => m.squares);
}
if (gtype == "live" && game.clocks[0] < 0) {
- // Game is unstarted
+ // Game is unstarted. clocks and initime are ignored until move 2
game.clocks = [tc.mainTime, tc.mainTime];
- if (game.score == "*") {
- game.initime[0] = Date.now();
- if (myIdx >= 0) {
- // I play in this live game; corr games don't have clocks+initime
- GameStorage.update(game.id, {
- clocks: game.clocks,
- initime: game.initime
- });
- }
+ game.initime = [Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER];
+ if (myIdx >= 0) {
+ // I play in this live game
+ GameStorage.update(game.id, {
+ clocks: game.clocks,
+ initime: game.initime
+ });
}
}
// TODO: merge next 2 "if" conditions
g.moves.forEach(m => {
m.squares = JSON.parse(m.squares);
});
- g.players = [{ id: g.white }, { id: g.black }];
- delete g["white"];
- delete g["black"];
afterRetrieval(g);
}
}
cursor: this.cursor
},
success: (response) => {
- if (
- response.games.length > 0 &&
- this.games.length == 0 &&
- this.gdisplay == "live"
- ) {
- document
- .getElementById("btnGcorr")
- .classList.add("somethingnew");
+ const L = response.games.length;
+ if (L > 0) {
+ this.cursor = response.games[L - 1].created;
+ if (this.games.length == 0 && this.gdisplay == "live") {
+ document
+ .getElementById("btnGcorr")
+ .classList.add("somethingnew");
+ }
}
this.games = this.games.concat(
response.games.map(g => {
if (!s.page)
// Peer is in Hall
this.send("askchallenges", { target: s.sid });
- // Peer is in Game
- else this.send("askgame", { target: s.sid, page: page });
+ // Peer is in Game: ask only if live game
+ else if (!page.match(/\/[0-9]+$/))
+ this.send("askgame", { target: s.sid, page: page });
});
break;
}
this.people[data.from] = { pages: [{ path: page, focus: true }] };
if (data.code == "connect")
this.send("askchallenges", { target: data.from });
- else this.send("askgame", { target: data.from, page: page });
+ // Ask game only if live:
+ else if (!page.match(/\/[0-9]+$/))
+ this.send("askgame", { target: data.from, page: page });
} else {
// Append page if not already in list
if (!(this.people[data.from].pages.find(p => p.path == page)))
}
break;
}
- case "game": {
- // Individual request
+ case "game": // Individual request
+ case "newgame": {
const game = data.data;
// Ignore games where I play (will go in MyGames page)
if (game.players.every(p =>
});
// Add new challenge:
chall.from = {
- // Decompose to avoid revealing email
sid: this.st.user.sid,
id: this.st.user.id,
name: this.st.user.name
{
data: { chall: chall },
success: (response) => {
- finishAddChallenge(response.cid);
+ finishAddChallenge(response.id);
}
}
);
finishProcessingChallenge: function(c) {
if (c.accepted) {
c.seat = {
- // Again, avoid c.seat = st.user to not reveal email
sid: this.st.user.sid,
id: this.st.user.id,
name: this.st.user.name
},
// NOTE: when launching game, the challenge is already being deleted
launchGame: function(c) {
- let players =
+ // White player index 0, black player index 1:
+ const players =
!!c.mycolor
? (c.mycolor == "w" ? [c.seat, c.from] : [c.from, c.seat])
: shuffle([c.from, c.seat]);
id: getRandString(),
fen: c.fen || V.GenRandInitFen(c.randomness),
randomness: c.randomness, //for rematch
- // White player index 0, black player index 1:
- players: c.mycolor
- ? (c.mycolor == "w" ? [c.seat, c.from] : [c.from, c.seat])
- : shuffle([c.from, c.seat]),
+ players: players,
vid: c.vid,
cadence: c.cadence
};
if (!!oppsid)
// Opponent is online
this.send("startgame", { data: gameInfo, target: oppsid });
+ // If new corr game, notify Hall (except opponent and me)
+ if (c.type == "corr") {
+ this.send(
+ "newgame",
+ {
+ data: gameInfo,
+ excluded: [this.st.user.sid, oppsid]
+ }
+ );
+ }
// Notify MyGames page:
this.send(
"notifynewgame",
{
data: gameInfo,
- targets: gameInfo.players.map(p => {
- return { sid: p.sid, id: p.id };
- })
+ targets: gameInfo.players
}
);
// NOTE: no need to send the game to the room, since I'll connect
"POST",
{
// cid is useful to delete the challenge:
- data: { gameInfo: gameInfo, cid: c.id },
+ data: {
+ gameInfo: gameInfo,
+ cid: c.id
+ },
success: (response) => {
- gameInfo.id = response.gameId;
+ gameInfo.id = response.id;
notifyNewgame();
- this.$router.push("/game/" + response.gameId);
+ this.$router.push("/game/" + response.id);
}
}
);
margin: 5px 0
button#loadMoreBtn
- margin-top: 0
- margin-bottom: 0
+ display: block
+ margin: 0 auto
td.remove-preset
background-color: lightgrey
"/runninggames",
"GET",
{
+ credentials: true,
success: (res) => {
// These games are garanteed to not be deleted
this.corrGames = res.games;
- this.corrGames.forEach(g => g.type = "corr");
+ this.corrGames.forEach(g => {
+ g.type = "corr";
+ g.score = "*";
+ });
this.decorate(this.corrGames);
// Now ask completed games (partial list)
ajax(
"/completedgames",
"GET",
{
+ credentials: true,
data: { cursor: this.cursor },
success: (res2) => {
if (res2.games.length > 0) {
if (thing == "turn") {
game.myTurn = !game.myTurn;
if (game.myTurn) this.tryShowNewsIndicator(type);
- }
+ } else game.myTurn = false;
// TODO: forcing refresh like that is ugly and wrong.
// How to do it cleanly?
this.$refs[type + "games"].$forceUpdate();
"/completedgames",
"GET",
{
+ credentials: true,
data: { cursor: this.cursor },
success: (res) => {
if (res.games.length > 0) {
max-height: 100%
button#loadMoreBtn
- margin-top: 0
- margin-bottom: 0
+ display: block
+ margin: 0 auto
.somethingnew
background-color: #c5fefe !important
return (
g.vid.toString().match(/^[0-9]+$/) &&
g.cadence.match(/^[0-9dhms +]+$/) &&
- g.randomness.match(/^[0-2]$/) &&
+ g.randomness.toString().match(/^[0-2]$/) &&
g.fen.match(/^[a-zA-Z0-9, /-]*$/) &&
g.players.length == 2 &&
- g.players.every(p => p.toString().match(/^[0-9]+$/))
+ g.players.every(p => p.id.toString().match(/^[0-9]+$/))
);
},
"VALUES " +
"(" +
vid + ",'" + fen + "','" + fen + "'," + randomness + "," +
- "'" + players[0] + "','" + players[1] + "," +
+ players[0].id + "," + players[1].id + "," +
"'" + cadence + "'," + Date.now() +
")";
db.run(query, function(err) {
- cb(err, { id: this.lastId });
+ cb(err, { id: this.lastID });
});
});
},
db.serialize(function() {
let query =
"SELECT " +
- "g.id, g.vid, g.fen, g.fenStart, g.cadence, g.created, " +
+ "g.id, g.fen, g.fenStart, g.cadence, g.created, " +
"g.white, g.black, g.score, g.scoreMsg, " +
"g.drawOffer, g.rematchOffer, v.name AS vname " +
"FROM Games g " +
" ON g.vid = v.id " +
"WHERE g.id = " + id;
db.get(query, (err, gameInfo) => {
+ if (!gameInfo) {
+ cb(err || { errmsg: "Game not found" }, undefined);
+ return;
+ }
query =
- "SELECT squares, played, idx " +
- "FROM Moves " +
- "WHERE gid = " + id;
- db.all(query, (err3, moves) => {
+ "SELECT id, name " +
+ "FROM Users " +
+ "WHERE id IN (" + gameInfo.white + "," + gameInfo.black + ")";
+ db.all(query, (err2, players) => {
+ if (players[0].id == gameInfo.black) players = players.reverse();
+ // The original players' IDs info isn't required anymore
+ delete gameInfo["white"];
+ delete gameInfo["black"];
query =
- "SELECT msg, name, added " +
- "FROM Chats " +
+ "SELECT squares, played, idx " +
+ "FROM Moves " +
"WHERE gid = " + id;
- db.all(query, (err4, chats) => {
- const game = Object.assign(
- {},
- gameInfo,
- {
- moves: moves,
- chats: chats
- }
- );
- cb(null, game);
+ db.all(query, (err3, moves) => {
+ query =
+ "SELECT msg, name, added " +
+ "FROM Chats " +
+ "WHERE gid = " + id;
+ db.all(query, (err4, chats) => {
+ const game = Object.assign(
+ {},
+ gameInfo,
+ {
+ players: players,
+ moves: moves,
+ chats: chats
+ }
+ );
+ cb(null, game);
+ });
});
});
});
getObserved: function(uid, cursor, cb) {
db.serialize(function() {
let query =
- "SELECT g.id, g.vid, g.cadence, g.created, " +
- " g.score, g.white, g.black " +
- "FROM Games g ";
+ "SELECT id, vid, cadence, created, score, white, black " +
+ "FROM Games ";
if (uid > 0) query +=
"WHERE " +
" created < " + cursor + " AND " +
let names = {};
users.forEach(u => { names[u.id] = u.name; });
cb(
+ err,
games.map(
g => {
return {
id: g.id,
+ vid: g.vid,
cadence: g.cadence,
- vname: g.vname,
created: g.created,
score: g.score,
- white: names[g.white],
- black: names[g.black]
+ players: [
+ { id: g.white, name: names[g.white] },
+ { id: g.black, name: names[g.black] }
+ ]
};
}
)
getRunning: function(uid, cb) {
db.serialize(function() {
let query =
- "SELECT g.id, g.cadence, g.created, g.score, " +
+ "SELECT g.id, g.cadence, g.created, " +
"g.white, g.black, v.name AS vname " +
"FROM Games g " +
"JOIN Variants v " +
" ON g.vid = v.id " +
- "WHERE white = " + uid + " OR black = " + uid;
+ "WHERE score = '*' AND (white = " + uid + " OR black = " + uid + ")";
db.all(query, (err, games) => {
// Get movesCount (could be done in // with next query)
query =
if (!pids[g.white]) pids[g.white] = true;
if (!pids[g.black]) pids[g.black] = true;
});
- UserModel.getByIds(pids, (err2, users) => {
+ UserModel.getByIds(Object.keys(pids), (err2, users) => {
let names = {};
users.forEach(u => { names[u.id] = u.name; });
cb(
+ null,
games.map(
g => {
return {
id: g.id,
- cadence: g.cadence,
vname: g.vname,
+ cadence: g.cadence,
created: g.created,
score: g.score,
- movesCount: movesCounts[g.id],
- white: names[g.white],
- black: names[g.black]
+ movesCount: movesCounts[g.id] || 0,
+ players: [
+ { id: g.white, name: names[g.white] },
+ { id: g.black, name: names[g.black] }
+ ]
};
}
)
"JOIN Variants v " +
" ON g.vid = v.id " +
"WHERE " +
+ " score <> '*' AND " +
" created < " + cursor + " AND " +
" (" +
" (" + uid + " = white AND NOT deletedByWhite) OR " +
if (!pids[g.white]) pids[g.white] = true;
if (!pids[g.black]) pids[g.black] = true;
});
- UserModel.getByIds(pids, (err2, users) => {
+ UserModel.getByIds(Object.keys(pids), (err2, users) => {
let names = {};
users.forEach(u => { names[u.id] = u.name; });
cb(
+ null,
games.map(
g => {
return {
id: g.id,
- cadence: g.cadence,
vname: g.vname,
+ cadence: g.cadence,
created: g.created,
score: g.score,
scoreMsg: g.scoreMsg,
- white: names[g.white],
- black: names[g.black],
+ players: [
+ { id: g.white, name: names[g.white] },
+ { id: g.black, name: names[g.black] }
+ ],
deletedByWhite: g.deletedByWhite,
deletedByBlack: g.deletedByBlack
};
const query =
"SELECT white, black " +
"FROM Games " +
- "WHERE gid = " + id;
- db.all(query, (err, players) => {
+ "WHERE id = " + id;
+ db.get(query, (err, players) => {
return cb(err, players);
});
});
// obj can have fields move, chat, fen, drawOffer and/or score + message
update: function(id, obj, cb) {
db.parallelize(function() {
- let query =
+ let updateQuery =
"UPDATE Games " +
"SET ";
let modifs = "";
// NOTE: if drawOffer is set, we should check that it's player's turn
// A bit overcomplicated. Let's trust the client on that for now...
- if (!!obj.drawOffer)
- {
- if (obj.drawOffer == "n") //special "None" update
+ if (!!obj.drawOffer) {
+ if (obj.drawOffer == "n")
+ // Special "None" update
obj.drawOffer = "";
modifs += "drawOffer = '" + obj.drawOffer + "',";
}
- if (!!obj.rematchOffer)
- {
- if (obj.rematchOffer == "n") //special "None" update
+ if (!!obj.rematchOffer) {
+ if (obj.rematchOffer == "n")
+ // Special "None" update
obj.rematchOffer = "";
modifs += "rematchOffer = '" + obj.rematchOffer + "',";
}
- if (!!obj.fen)
- modifs += "fen = '" + obj.fen + "',";
- if (!!obj.score)
- modifs += "score = '" + obj.score + "',";
- if (!!obj.scoreMsg)
- modifs += "scoreMsg = '" + obj.scoreMsg + "',";
+ if (!!obj.fen) modifs += "fen = '" + obj.fen + "',";
if (!!obj.deletedBy) {
const myColor = obj.deletedBy == 'w' ? "White" : "Black";
modifs += "deletedBy" + myColor + " = true,";
}
- modifs = modifs.slice(0,-1); //remove last comma
- if (modifs.length > 0)
- {
- query += modifs + " WHERE id = " + id;
- db.run(query);
+ if (!!obj.score) {
+ modifs += "score = '" + obj.score + "'," +
+ "scoreMsg = '" + obj.scoreMsg + "',";
}
- // NOTE: move, chat and delchat are mutually exclusive
- if (!!obj.move)
- {
- // Security: only update moves if index is right
- query =
- "SELECT MAX(idx) AS maxIdx " +
+ const finishAndSendQuery = () => {
+ modifs = modifs.slice(0, -1); //remove last comma
+ if (modifs.length > 0) {
+ updateQuery += modifs + " WHERE id = " + id;
+ db.run(updateQuery);
+ }
+ cb(null);
+ };
+ if (!!obj.move || (!!obj.score && obj.scoreMsg == "Time")) {
+ // Security: only update moves if index is right,
+ // and score with scoreMsg "Time" if really lost on time.
+ let query =
+ "SELECT MAX(idx) AS maxIdx, MAX(played) AS lastPlayed " +
"FROM Moves " +
"WHERE gid = " + id;
- db.get(query, (err,ret) => {
- const m = obj.move;
- if (!ret.maxIdx || ret.maxIdx + 1 == m.idx) {
- query =
- "INSERT INTO Moves (gid, squares, played, idx) VALUES " +
- "(" + id + ",?," + m.played + "," + m.idx + ")";
- db.run(query, JSON.stringify(m.squares));
- cb(null);
+ db.get(query, (err, ret) => {
+ if (!!obj.move ) {
+ if (!ret.maxIdx || ret.maxIdx + 1 == obj.move.idx) {
+ query =
+ "INSERT INTO Moves (gid, squares, played, idx) VALUES " +
+ "(" + id + ",?," + Date.now() + "," + obj.move.idx + ")";
+ db.run(query, JSON.stringify(obj.move.squares));
+ finishAndSendQuery();
+ } else cb({ errmsg: "Wrong move index" });
+ } else {
+ if (ret.maxIdx < 2) cb({ errmsg: "Time not over" });
+ else {
+ // We also need the game cadence
+ query =
+ "SELECT cadence " +
+ "FROM Games " +
+ "WHERE id = " + id;
+ db.get(query, (err2, ret2) => {
+ const daysTc = parseInt(ret2.cadence.match(/\(^[0-9]+\)/)[0]);
+ if (Date.now() - ret.lastPlayed > daysTc * 24 * 3600 * 1000)
+ finishAndSendQuery();
+ else cb({ errmsg: "Time not over" });
+ });
+ }
}
- else cb({errmsg:"Wrong move index"});
});
- }
- else cb(null);
- if (!!obj.chat)
- {
- query =
+ } else finishAndSendQuery();
+ // NOTE: chat and delchat are mutually exclusive
+ if (!!obj.chat) {
+ const query =
"INSERT INTO Chats (gid, msg, name, added) VALUES ("
+ id + ",?,'" + obj.chat.name + "'," + Date.now() + ")";
db.run(query, obj.chat.msg);
- }
- else if (obj.delchat)
- {
- query =
+ } else if (obj.delchat) {
+ const query =
"DELETE " +
"FROM Chats " +
"WHERE gid = " + id;
"deletedBy" +
(obj.deletedBy == 'w' ? "Black" : "White") +
" AS deletedByOpp";
- query =
+ const query =
"SELECT " + selection + " " +
"FROM Games " +
"WHERE id = " + id;
if (user.notify)
UserModel.notify(
user,
- "New challenge: " + params.siteURL + "/#/?disp=corr");
+ "New challenge : " + params.siteURL + "/#/?disp=corr");
}
});
} else insertChallenge();
if (
Array.isArray(gameInfo.players) &&
gameInfo.players.some(p => p.id == req.userId) &&
- (!cid || cid.toString().match(/^[0-9]+$/)) &&
+ (!cid || !!cid.toString().match(/^[0-9]+$/)) &&
GameModel.checkGameInfo(gameInfo)
) {
if (!!cid) ChallengeModel.remove(cid);
GameModel.create(
- gameInfo.vid, gameInfo.fen, gameInfo.cadence, gameInfo.players,
+ gameInfo.vid, gameInfo.fen, gameInfo.randomness,
+ gameInfo.cadence, gameInfo.players,
(err, ret) => {
const oppIdx = (gameInfo.players[0].id == req.userId ? 1 : 0);
const oppId = gameInfo.players[oppIdx].id;
const gameId = req.query["gid"];
if (!!gameId && gameId.match(/^[0-9]+$/)) {
GameModel.getOne(gameId, (err, game) => {
- res.json({ game: game });
+ res.json(err || { game: game });
});
}
});
const userId = req.query["uid"];
const cursor = req.query["cursor"];
if (!!userId.match(/^[0-9]+$/) && !!cursor.match(/^[0-9]+$/)) {
- GameModel.getObserved(userId, (err, games) => {
+ GameModel.getObserved(userId, cursor, (err, games) => {
res.json({ games: games });
});
}
});
// Get by user ID, for MyGames page
-router.get("/runninggames", access.ajax, access.logged, (req,res) => {
+router.get("/runninggames", access.logged, access.ajax, (req,res) => {
GameModel.getRunning(req.userId, (err, games) => {
res.json({ games: games });
});
});
-router.get("/completedgames", access.ajax, access.logged, (req,res) => {
+router.get("/completedgames", access.logged, access.ajax, (req,res) => {
const cursor = req.query["cursor"];
if (!!cursor.match(/^[0-9]+$/)) {
GameModel.getCompleted(req.userId, cursor, (err, games) => {
const gid = req.body.gid;
let obj = req.body.newObj;
if (gid.toString().match(/^[0-9]+$/) && GameModel.checkGameUpdate(obj)) {
- GameModel.getPlayers(gid, (err,players) => {
+ GameModel.getPlayers(gid, (err, players) => {
let myColor = '';
if (players.white == req.userId) myColor = 'w';
else if (players.black == req.userId) myColor = 'b';
const oppid = (myColor == 'w' ? players.black : players.white);
const messagePrefix =
!!obj.move
- ? "New move in game: "
- : "Game ended: ";
+ ? "New move in game : "
+ : "Game ended : ";
UserModel.tryNotify(
oppid,
messagePrefix + params.siteURL + "/#/game/" + gid
const id = query["id"];
const tmpId = query["tmpId"];
const page = query["page"];
- const notifyRoom = (page,code,obj={}) => {
- if (!clients[page]) return;
- Object.keys(clients[page]).forEach(k => {
- Object.keys(clients[page][k]).forEach(x => {
- if (k == sid && x == tmpId) return;
- send(
- clients[page][k][x].socket,
- Object.assign({ code: code, from: sid }, obj)
- );
- });
- });
- };
- // For focus events: no need to target self
- const notifyAllBut = (page,code,obj={},except) => {
+ const notifyRoom = (page, code, obj={}, except) => {
if (!clients[page]) return;
+ except = except || [];
Object.keys(clients[page]).forEach(k => {
if (except.includes(k)) return;
Object.keys(clients[page][k]).forEach(x => {
+ if (k == sid && x == tmpId) return;
send(
clients[page][k][x].socket,
Object.assign({ code: code, from: sid }, obj)
case "drawoffer":
case "rematchoffer":
case "draw":
- notifyRoom(page, obj.code, {data: obj.data});
+ notifyRoom(page, obj.code, {data: obj.data}, obj.excluded);
break;
case "rnewgame":
// A rematch game started:
- // NOTE: no need to explicitely notify Hall: the game will be sent
- notifyAllBut(page, "newgame", {data: obj.data}, [sid]);
- notifyRoom("/mygames", "newgame", {data: obj.data});
+ notifyRoom(page, "newgame", {data: obj.data});
+ // Explicitely notify Hall if gametype == corr.
+ // Live games will be polled from Hall after gconnect event.
+ if (obj.data.cadence.indexOf('d') >= 0)
+ notifyRoom("/", "newgame", {data: obj.data});
break;
case "newmove": {
case "getfocus":
case "losefocus":
- if (page == "/") notifyAllBut("/", obj.code, { page: "/" }, [sid]);
+ if (page == "/") notifyRoom("/", obj.code, { page: "/" }, [sid]);
else {
// Notify game room + Hall:
- notifyAllBut(page, obj.code, {}, [sid]);
- notifyAllBut("/", obj.code, { page: page }, [sid]);
+ notifyRoom(page, obj.code, {}, [sid]);
+ notifyRoom("/", obj.code, { page: page }, [sid]);
}
break;