Experimental change: options replacing randomness (more general)
[vchess.git] / client / src / views / Game.vue
index d88ac1e..b13e383 100644 (file)
@@ -7,7 +7,7 @@ main
   )
     .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(
@@ -78,7 +78,10 @@ main
   .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.constructor.AbbreviateOptions(game.options) }}
       span#nextGame(
         v-if="nextIds.length > 0"
         @click="showNextGame()"
@@ -408,8 +411,15 @@ export default {
           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.
@@ -514,7 +524,8 @@ export default {
             "DELETE",
             { data: { gid: this.game.id } }
           );
-        } else {
+        }
+        else {
           // Live game
           GameStorage.update(this.gameRef, { delchat: true });
         }
@@ -578,7 +589,8 @@ export default {
             // 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
           }
@@ -674,9 +686,8 @@ export default {
                 ) {
                   this.send("asklastate", { target: user.sid });
                   counter++;
-                } else {
-                  clearInterval(this.askLastate);
                 }
+                else clearInterval(this.askLastate);
               },
               1500
             );
@@ -706,7 +717,7 @@ export default {
           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(
@@ -874,13 +885,15 @@ export default {
             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;
@@ -972,7 +985,8 @@ export default {
           // 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();
         }
@@ -994,7 +1008,8 @@ export default {
             : "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"]);
@@ -1008,7 +1023,8 @@ export default {
             this.gameRef,
             { drawOffer: this.game.mycolor }
           );
-        } else this.updateCorrGame({ drawOffer: this.game.mycolor });
+        }
+        else this.updateCorrGame({ drawOffer: this.game.mycolor });
       }
     },
     addAndGotoLiveGame: function(gameInfo, callback) {
@@ -1018,7 +1034,6 @@ export default {
         {
           // (other) Game infos: constant
           fenStart: gameInfo.fen,
-          vname: this.game.vname,
           created: Date.now(),
           // Game state (including FEN): will be updated
           moves: [],
@@ -1043,39 +1058,55 @@ export default {
         // Start a new game!
         let gameInfo = {
           id: getRandString(), //ignored if corr
-          fen: V.GenRandInitFen(this.game.randomness),
-          randomness: this.game.randomness,
+          fen: V.GenRandInitFen(this.game.options),
+          options: 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",
             {
-              data: { gameInfo: gameInfo },
+              data: Object.assign(
+                {},
+                gameInfo,
+                { options: JSON.stringify(this.game.options) }
+              ),
               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") {
@@ -1083,8 +1114,10 @@ export default {
             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 });
@@ -1093,7 +1126,8 @@ export default {
             this.gameRef,
             { rematchOffer: '' }
           );
-        } else this.updateCorrGame({ rematchOffer: 'n' });
+        }
+        else this.updateCorrGame({ rematchOffer: 'n' });
       }
     },
     abortGame: function() {
@@ -1162,11 +1196,10 @@ export default {
               { 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"
@@ -1262,18 +1295,33 @@ export default {
       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);
-      });
-      this.rulesContent =
-        afterRawLoad(
-          require(
-            "raw-loader!@/translations/rules/" +
-            game.vname + "/" + this.st.lang + ".pug"
-          ).default
-        ).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 => v.id == game.vid);
+          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)
@@ -1329,7 +1377,8 @@ export default {
                 currentTurn == "w" ? "0-1" : "1-0",
                 "Time"
               );
-          } else {
+          }
+          else {
             this.$set(
               this.virtualClocks,
               colorIdx,
@@ -1385,18 +1434,20 @@ export default {
           // 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) {
-          if (V.LoseOnRepetition)
-            this.gameOver(moveCol == "w" ? "0-1" : "1-0", "Repetition");
-          else this.drawOffer = "threerep";
+        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 = "";
         }
-        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);
@@ -1592,7 +1643,7 @@ export default {
     // 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: