+ // Send new challenge (corr or live, cf. time control), with button or click on player
+ newChallenge: async function() {
+ if (this.challenges.some(c => c.from.sid == this.st.user.sid))
+ {
+ document.getElementById("modalNewgame").checked = false;
+ return alert("You already have a pending challenge");
+ }
+ // TODO: put this "load variant" block elsewhere
+ const vname = this.loadVariant(this.newchallenge.vid, this.st.variants);
+ // checkChallenge side-effect = set FEN, and mainTime + increment in seconds
+ // TODO: should not be a side-effect but set here ; for received server challenges we do not have mainTime+increment
+ const error = checkChallenge(this.newchallenge);
+ if (!!error)
+ return alert(error);
+// TODO: set FEN, set mainTime and increment ?!
+else //generate a FEN
+ c.fen = V.GenRandInitFen();
+ // Less than 3 days ==> live game (TODO: heuristic... 40 moves also)
+ const liveGame =
+ this.newchallenge.mainTime + 40 * this.newchallenge.increment < 3*24*60*60;
+ // Check that the players (if any indicated) are online
+ let chall =
+ {
+ id: 0, //unknown yet (no ID for live challenges)
+ from: this.st.user,
+ added: Date.now(),
+ fen: this.newchallenge.fen,
+ variant: {id: this.newchallenge.vid, name: vname},
+ nbPlayers: this.newchallenge.nbPlayers,
+ to: [
+ {id: 0, name: this.newchallenge.to[0], sid: ""},
+ {id: 0, name: this.newchallenge.to[1], sid: ""},
+ {id: 0, name: this.newchallenge.to[2], sid: ""},
+ ],
+ timeControl: this.newchallenge.timeControl,
+ mainTime: this.newchallenge.mainTime,
+ increment: this.newchallenge.increment,
+ };
+ for (let p of chall.to)
+ {
+ if (p.name != "")
+ {
+ const pIdx = this.players.findIndex(pl => pl.name == p.name);
+ // NOTE: id (server DB) and sid (socket ID).
+ // Anonymous players just have a socket ID.
+ // NOTE: for correspondance play we don't require players to be online
+ // (==> we don't have IDs, and no sid)
+ if (liveGame && pIdx === -1)
+ return alert(p.name + " is not connected");
+ p.id = this.players[pIdx].id;
+ p.sid = this.players[pIdx].sid;
+ }
+ }
+ const finishAddChallenge = (cid) => {
+ chall.id = cid || "c" + genRandString();
+ this.challenges.push(chall);
+ // Send challenge to peers
+ let challSock =
+ {
+ code: "newchallenge",
+ chall: chall,
+ target: "",
+ };
+ const sendChallengeTo = (sid) => {
+ challSock.target = sid;
+ this.st.conn.send(JSON.stringify(challSock));
+ };
+ if (chall.to[0].id > 0)
+ {
+ // Challenge with targeted players
+ chall.to.forEach(p => {
+ if (p.id > 0)
+ sendChallengeTo(p.sid);
+ });
+ }
+ else
+ {
+ // Open challenge: send to all connected players (except us)
+ this.players.forEach(p => {
+ if (p.sid != this.st.user.sid) //only sid is always set
+ sendChallengeTo(p.sid);
+ });
+ }
+ document.getElementById("modalNewgame").checked = false;
+ };
+ if (liveGame)
+ {
+ // Live challenges have cid = 0
+ finishAddChallenge();
+ }
+ else
+ {
+ const chall = {
+ uid: req.body["from"],
+ vid: req.body["vid"],
+ fen: req.body["fen"],
+ timeControl: req.body["timeControl"],
+ nbPlayers: req.body["nbPlayers"],
+ to: req.body["to"], //array of IDs
+ };
+ // Correspondance game: send challenge to server