+// * - accept challenge (corr or live) --> send info to challenge creator
+// * - cancel challenge (click on sent challenge) --> send info to all concerned players
+// * - withdraw from challenge (if >= 3 players and previously accepted)
+// * --> send info to challenge creator
+// * - refuse challenge: send "refuse" to challenge sender, and "delete" to others
+// * - prepare and start new game (if challenge is full after acceptation)
+// * --> include challenge ID (so that opponents can delete the challenge too)
+ clickChallenge: function(c) {
+
+ console.log("click challenge");
+ console.log(c);
+
+ if (!!c.accepted)
+ {
+ this.st.conn.send(JSON.stringify({code: "withdrawchallenge",
+ cid: c.id, target: c.from.sid}));
+ if (c.type == "corr")
+ {
+ ajax(
+ "/challenges",
+ "PUT",
+ {action:"withdraw", id: this.challenges[cIdx].id}
+ );
+ }
+ c.accepted = false;
+ }
+ else if (c.from.sid == this.st.user.sid
+ || (this.st.user.id > 0 && c.from.id == this.st.user.id))
+ {
+ // It's my challenge: cancel it
+ this.sendSomethingTo(c.to, "deletechallenge", {cid:c.id});
+ ArrayFun.remove(this.challenges, ch => ch.id == c.id);
+ if (c.type == "corr")
+ {
+ ajax(
+ "/challenges",
+ "DELETE",
+ {id: this.challenges[cIdx].id}
+ );
+ }
+ }
+ else //accept (or refuse) a challenge
+ {
+ c.accepted = true;
+ if (!!c.to[0])
+ {
+ // TODO: if special FEN, show diagram after loading variant
+ c.accepted = confirm("Accept challenge?");
+ }
+ this.st.conn.send(JSON.stringify({
+ code: (c.accepted ? "accept" : "refuse") + "challenge",
+ cid: c.id, target: c.from.sid}));
+ if (c.type == "corr" && c.accepted)
+ {
+ ajax(
+ "/challenges",
+ "PUT",
+ {action: "accept", id: this.challenges[cIdx].id}
+ );
+ }
+ if (!c.accepted)
+ {
+ ArrayFun.remove(this.challenges, ch => ch.id == c.id);
+ if (c.type == "corr")
+ {
+ ajax(
+ "/challenges",
+ "DELETE",
+ {id: this.challenges[cIdx].id}
+ );
+ }
+ }
+ }
+ },
+ // NOTE: for live games only (corr games are launched on server)
+ launchGame: async function(c) {
+ // Just assign colors and pass the message
+ const vname = this.getVname(c.vid);
+ const vModule = await import("@/variants/" + vname + ".js");
+ window.V = vModule.VariantRules;
+ let players = [c.from];
+ Array.prototype.push.apply(players, c.seats);
+ let gameInfo =
+ {
+ fen: c.fen || V.GenRandInitFen(),
+ // Shuffle players order (white then black then other colors).
+ // Players' names may be required if game start when a player is offline
+ players: shuffle(players).map(p => { return {name:p.name, sid:p.sid} }),
+ vid: c.vid,
+ timeControl: c.timeControl,
+ };
+ c.seats.forEach(s => {
+ // NOTE: cid required to remove challenge
+ this.st.conn.send(JSON.stringify({code:"newgame",
+ gameInfo:gameInfo, cid:c.id, target:s.sid}));
+ });
+ // Delete corresponding challenge:
+ ArrayFun.remove(this.challenges, ch => ch.id == c.id);
+ this.newGame(gameInfo); //also!
+ },
+ // NOTE: for live games only (corr games are launched on server)
+ newGame: function(gameInfo) {
+ localStorage["gid"] = getRandString();
+ // Extract times (in [milli]seconds), set clocks, store in localStorage
+ const tc = extractTime(gameInfo.timeControl);
+ localStorage["timeControl"] = gameInfo.timeControl;
+ localStorage["clocks"] = JSON.stringify(
+ [...Array(gameInfo.players.length)].fill(tc.mainTime));
+ localStorage["increment"] = tc.increment;
+ localStorage["started"] = JSON.stringify(
+ [...Array(gameInfo.players.length)].fill(false));
+ localStorage["vname"] = this.getVname(gameInfo.vid);
+ localStorage["fenInit"] = gameInfo.fen;
+ localStorage["players"] = JSON.stringify(gameInfo.players);
+ if (this.st.settings.sound >= 1)
+ new Audio("/sounds/newgame.mp3").play().catch(err => {});
+ // TODO: redirect to game