)
.card
label.modal-close(for="modalRules")
- a#variantNameInGame(:href="'/#/variants/'+game.vname") {{ game.vname }}
+ a#variantNameInGame(:href="'/#/variants/'+game.vname") {{ game.vdisp }}
div(v-html="rulesContent")
input#modalScore.modal(type="checkbox")
div#scoreDiv(
.row
#aboveBoard.col-sm-12
span.variant-cadence(v-if="game.type!='import'") {{ game.cadence }}
- span.variant-name {{ game.vname }}
+ span.variant-name
+ | {{ game.vname }}
+ | {{ !!vr ? vr.constructor.AbbreviateOptions(game.options) : '' }}
span#nextGame(
v-if="nextIds.length > 0"
@click="showNextGame()"
</template>
<script>
-// TODO: this will be a component instead ?
-// If simultaneous games, no "rematch" button
-
import BaseGame from "@/components/BaseGame.vue";
import UserBio from "@/components/UserBio.vue";
import Chat from "@/components/Chat.vue";
import { processModalClick } from "@/utils/modalClick";
import { playMove, getFilteredMove } from "@/utils/playUndo";
import { ArrayFun } from "@/utils/array";
+import afterRawLoad from "@/utils/afterRawLoad";
import params from "@/parameters";
export default {
name: "my-game",
)
);
},
+ requestLastate: function(sid) {
+ // TODO: maybe also find opponent SID ?
+ //const oppSid =
+ // this.game.players.find(p => p.sid != this.st.user.sid).sid;
+ this.send("asklastate", { target: sid });
+ let counter = 1;
+ this.askLastate = setInterval(
+ () => {
+ // Ask at most 3 times:
+ // if no reply after that there should be a network issue.
+ if (
+ counter < 3 &&
+ !this.gotLastate &&
+ !!this.people[sid]
+ ) {
+ this.send("asklastate", { target: sid });
+ counter++;
+ }
+ else clearInterval(this.askLastate);
+ },
+ 1500
+ );
+ },
atCreation: function() {
document.addEventListener('visibilitychange', this.visibilityChange);
window.addEventListener('focus', this.onFocus);
"message", this.socketMessageListener);
this.conn = new WebSocket(this.connexionString);
this.conn.addEventListener("message", this.socketMessageListener);
+ const oppSid = this.getOppsid();
+ if (!!oppSid) this.requestLastate(oppSid); //in case of
}
},
1000
this.conn.onopen = () => callback();
};
this.fetchGame((game) => {
- if (!!game)
+ if (!!game) {
+ if (!game.options) {
+ // Patch for retro-compatibility (TODO: remove it)
+ game.options = { randomness: game.randomness };
+ delete game["randomness"];
+ }
+ else game.options = JSON.parse(game.options);
this.loadVariantThenGame(game, () => socketInit(this.roomInit));
+ }
else
// Live game stored remotely: need socket to retrieve it
// NOTE: the callback "roomInit" will be lost, so it's not provided.
"DELETE",
{ data: { gid: this.game.id } }
);
- } else {
+ }
+ else {
// Live game
GameStorage.update(this.gameRef, { delchat: true });
}
},
getGameType: function(game) {
if (!!game.id.toString().match(/^i/)) return "import";
- return (
- game.cadence.indexOf("d") >= 0
- ? "corr"
- : (game.cadence.indexOf("/") >= 0 ? "simul" : "live")
- );
+ return (game.cadence.indexOf("d") >= 0 ? "corr" : "live");
},
// Notify something after a new move (to opponent and me on MyGames page)
notifyMyGames: function(thing, data) {
// For self multi-connects tests:
this.newConnect[data.from[0]] = true;
this.send("askidentity", { target: data.from[0] });
- } else {
+ }
+ else {
this.people[data.from[0]].tmpIds[data.from[1]] = { focus: true };
this.$forceUpdate(); //TODO: shouldn't be required
}
this.game.type == "live" &&
this.game.players.some(p => p.sid == user.sid)
) {
- this.send("asklastate", { target: user.sid });
- let counter = 1;
- this.askLastate = setInterval(
- () => {
- // Ask at most 3 times:
- // if no reply after that there should be a network issue.
- if (
- counter < 3 &&
- !this.gotLastate &&
- !!this.people[user.sid]
- ) {
- this.send("asklastate", { target: user.sid });
- counter++;
- } else {
- clearInterval(this.askLastate);
- }
- },
- 1500
- );
+ this.requestLastate(user.sid);
}
break;
}
const gameToSend = Object.keys(this.game)
.filter(k =>
[
- "id","fen","players","vid","cadence","fenStart","vname",
+ "id","fen","players","vid","cadence","fenStart","options",
"moves","clocks","score","drawOffer","rematchOffer"
].includes(k))
.reduce(
case "newmove": {
// DEBUG:
-console.log("Receive move");
-console.log(data.data);
-//moveslist not updated when receiving a move? (see in baseGame)
+//console.log("Receive move");
+//console.log(data.data);
+//moveslist not updated when receiving a move? (see in BaseGame)
const movePlus = data.data;
const movesCount = this.game.moves.length;
gameInfo.players.some(p => p.sid == this.st.user.sid)
) {
this.addAndGotoLiveGame(gameInfo);
- } else if (
+ }
+ else if (
gameType == "corr" &&
this.st.user.id > 0 &&
gameInfo.players.some(p => p.id == this.st.user.id)
) {
this.$router.push("/game/" + gameInfo.id);
- } else {
+ }
+ else {
this.rematchId = gameInfo.id;
document.getElementById("modalRules").checked = false;
document.getElementById("modalScore").checked = false;
// Just got last move from him
this.$refs["basegame"].play(data.lastMove, "received");
this.processMove(data.lastMove);
- } else {
+ }
+ else {
if (!!this.clockUpdate) clearInterval(this.clockUpdate);
this.re_setClocks();
}
: "Three repetitions";
this.send("draw", { data: message });
this.gameOver("1/2", message);
- } else if (this.drawOffer == "") {
+ }
+ else if (this.drawOffer == "") {
// No effect if drawOffer == "sent"
if (this.game.mycolor != this.vr.turn) {
alert(this.st.tr["Draw offer only in your turn"]);
this.gameRef,
{ drawOffer: this.game.mycolor }
);
- } else this.updateCorrGame({ drawOffer: this.game.mycolor });
+ }
+ else this.updateCorrGame({ drawOffer: this.game.mycolor });
}
},
addAndGotoLiveGame: function(gameInfo, callback) {
{
// (other) Game infos: constant
fenStart: gameInfo.fen,
- vname: this.game.vname,
created: Date.now(),
// Game state (including FEN): will be updated
moves: [],
// Start a new game!
let gameInfo = {
id: getRandString(), //ignored if corr
- fen: V.GenRandInitFen(this.game.randomness),
+ fen: V.GenRandInitFen(this.game.options),
+ options: JSON.stringify(this.game.options),
players: [this.game.players[1], this.game.players[0]],
vid: this.game.vid,
cadence: this.game.cadence
};
const notifyNewGame = () => {
- const oppsid = this.getOppsid(); //may be null
- this.send("rnewgame", { data: gameInfo, oppsid: oppsid });
+ this.send("rnewgame", { data: gameInfo });
// To main Hall if corr game:
if (this.game.type == "corr")
this.send("newgame", { data: gameInfo, page: "/" });
// Also to MyGames page:
this.notifyMyGames("newgame", gameInfo);
};
- if (this.game.type == "live")
+ if (this.game.type == "live") {
+ GameStorage.update(
+ this.gameRef,
+ { rematchOffer: "" }
+ );
+ // Increment game stats counter in DB
+ ajax(
+ "/gamestat",
+ "POST",
+ { data: { vid: gameInfo.vid } }
+ );
this.addAndGotoLiveGame(gameInfo, notifyNewGame);
+ }
else {
// corr game
+ this.updateCorrGame({ rematchOffer: 'n' });
ajax(
"/games",
"POST",
{
- // cid is useful to delete the challenge:
data: { gameInfo: gameInfo },
success: (response) => {
- gameInfo.id = response.gameId;
+ gameInfo.id = response.id;
notifyNewGame();
- this.$router.push("/game/" + response.gameId);
+ this.$router.push("/game/" + response.id);
}
}
);
}
- } else if (this.rematchOffer == "") {
+ }
+ else if (this.rematchOffer == "") {
this.rematchOffer = "sent";
this.send("rematchoffer", { data: true });
if (this.game.type == "live") {
this.gameRef,
{ rematchOffer: this.game.mycolor }
);
- } else this.updateCorrGame({ rematchOffer: this.game.mycolor });
- } else if (this.rematchOffer == "sent") {
+ }
+ else this.updateCorrGame({ rematchOffer: this.game.mycolor });
+ }
+ else if (this.rematchOffer == "sent") {
// Toggle rematch offer (on --> off)
this.rematchOffer = "";
this.send("rematchoffer", { data: false });
this.gameRef,
{ rematchOffer: '' }
);
- } else this.updateCorrGame({ rematchOffer: 'n' });
+ }
+ else this.updateCorrGame({ rematchOffer: 'n' });
}
},
abortGame: function() {
{ clocks: game.clocks }
);
}
- } else {
- if (!!game.initime)
- // It's my turn: clocks not updated yet
- game.clocks[myIdx] -= (Date.now() - game.initime) / 1000;
}
+ else if (!!game.initime)
+ // It's my turn: clocks not updated yet
+ game.clocks[myIdx] -= (Date.now() - game.initime) / 1000;
}
else
// gtype == "import"
if (!!callback) callback();
},
loadVariantThenGame: async function(game, callback) {
- await import("@/variants/" + game.vname + ".js")
- .then((vModule) => {
- window.V = vModule[game.vname + "Rules"];
- this.loadGame(game, callback);
- });
- // (AJAX) Request to get rules content (plain text, HTML)
- this.rulesContent =
- require(
- "raw-loader!@/translations/rules/" +
- game.vname + "/" +
- this.st.lang + ".pug"
- )
- // Next two lines fix a weird issue after last update (2019-11)
- .replace(/\\n/g, " ")
- .replace(/\\"/g, '"')
- .replace('module.exports = "', "")
- .replace(/"$/, "")
- .replace(/(fen:)([^:]*):/g, replaceByDiag);
+ const afterSetVname = async () => {
+ await import("@/variants/" + game.vname + ".js")
+ .then((vModule) => {
+ window.V = vModule[game.vname + "Rules"];
+ this.loadGame(game, callback);
+ });
+ this.rulesContent =
+ afterRawLoad(
+ require(
+ "raw-loader!@/translations/rules/" +
+ game.vname + "/" + this.st.lang + ".pug"
+ ).default
+ ).replace(/(fen:)([^:]*):/g, replaceByDiag);
+ };
+ let variant = undefined;
+ const trySetVname = setInterval(
+ () => {
+ // this.st.variants might be uninitialized (variant == null)
+ variant = this.st.variants.find(v => {
+ return v.id == game.vid || v.name == game.vname
+ });
+ if (!!variant) {
+ clearInterval(trySetVname);
+ game.vname = variant.name;
+ game.vdisp = variant.display;
+ afterSetVname();
+ }
+ }, 500
+ );
},
// 3 cases for loading a game:
// - from indexedDB (running or completed live game I play)
currentTurn == "w" ? "0-1" : "1-0",
"Time"
);
- } else {
+ }
+ else {
this.$set(
this.virtualClocks,
colorIdx,
// In corr games, just reset clock to mainTime:
this.game.clocks[colorIdx] = extractTime(this.game.cadence).mainTime;
}
- // If repetition detected, consider that a draw offer was received:
- const fenObj = this.vr.getFenForRepeat();
- this.repeat[fenObj] =
- !!this.repeat[fenObj]
- ? this.repeat[fenObj] + 1
- : 1;
- if (this.repeat[fenObj] >= 3) this.drawOffer = "threerep";
- else if (this.drawOffer == "threerep") this.drawOffer = "";
+ if (!V.IgnoreRepetition) {
+ // If repetition detected, consider that a draw offer was received:
+ const fenObj = this.vr.getFenForRepeat();
+ this.repeat[fenObj] =
+ !!this.repeat[fenObj]
+ ? this.repeat[fenObj] + 1
+ : 1;
+ if (this.repeat[fenObj] >= 3) {
+ if (this.vr.loseOnRepetition())
+ this.gameOver(moveCol == "w" ? "0-1" : "1-0", "Repetition");
+ else this.drawOffer = "threerep";
+ }
+ else if (this.drawOffer == "threerep") this.drawOffer = "";
+ }
if (!!this.game.mycolor && !data.receiveMyMove) {
// NOTE: 'var' to see that variable outside this block
var filtered_move = getFilteredMove(move);
};
if (
this.game.type == "corr" &&
- V.CorrConfirm &&
moveCol == this.game.mycolor &&
!data.receiveMyMove
) {
if (data.score == "*") this.re_setClocks();
}
};
+ if (!V.CorrConfirm) {
+ afterSetScore();
+ return;
+ }
let el = document.querySelector("#buttonsConfirm > .acceptBtn");
// We may play several moves in a row: in case of, remove listener:
let elClone = el.cloneNode(true);
if (["all","byrow"].includes(V.ShowMoves)) {
this.curDiag = getDiagram({
position: position,
- orientation: V.CanFlip ? this.game.mycolor : "w"
+ orientation: V.CanFlip ? this.game.mycolor : "w",
+ color: this.game.mycolor,
+ score: "*"
});
document.querySelector("#confirmDiv > .card").style.width =
boardDiv.offsetWidth + "px";
// In corr games, callback to change page only after score is set:
gameOver: function(score, scoreMsg, callback) {
this.game.score = score;
- if (!scoreMsg) scoreMsg = getScoreMessage(score);
+ if (!scoreMsg) scoreMsg = getScoreMessage(score, V.ReverseColors);
this.game.scoreMsg = scoreMsg;
document.getElementById("modalRules").checked = false;
// Display result in a un-missable way: