Save current state (unmerged, broken, not working...)
[vchess.git] / public / javascripts / components / room.js
1 // TODO: main playing hall, chat + online players + current challenges + button "new game"
2 /*
3 input#modal-newgame.modal(type="checkbox")
4 div(role="dialog" aria-labelledby="newGameTxt")
5 .card.smallpad.small-modal
6 label#close-newgame.modal-close(for="modal-newgame")
7 h3#newGameTxt= translations["New game"]
8 p= translations["Waiting for opponent..."]
9 */
10
11 /*
12 Players + challenges : == "room" home of variant (surligner si nouveau défi perso et pas affichage courant)
13 joueurs en ligne (dte),
14 Nouvelle partie + défis en temps réel + parties en cours (milieu, tabs),
15 chat général (gauche, activé ou non (bool global storage)).
16 (cadences base + incrément, corr == incr >= 1jour ou base >= 7j)
17 --> correspondance: stocker sur serveur lastMove + peerId + color + movesCount + gameId + variant + timeleft
18 quand je poste un lastMove corr, supprimer mon ancien lastMove le cas échéant (tlm l'a eu)
19 fin de partie corr: garder maxi nbPlayers lastMove sur serveur, pendant 7 jours (arbitraire)
20 */
21 case "newgame": //opponent found
22 // oppid: opponent socket ID
23 this.newGame("human", data.fen, data.color, data.oppid, data.gameid);
24 break;
25
26 // TODO: elsewhere, probably (new game button)
27 clickGameSeek: function(e) {
28 this.getRidOfTooltip(e.currentTarget);
29 if (this.mode == "human" && this.score == "*")
30 return; //no newgame while playing
31 if (this.seek)
32 {
33 this.conn.send(JSON.stringify({code:"cancelnewgame"}));
34 this.seek = false;
35 }
36 else
37 this.newGame("human");
38 },
39 clickComputerGame: function(e) {
40 this.getRidOfTooltip(e.currentTarget);
41 if (this.mode == "computer" && this.score == "*"
42 && this.vr.turn != this.mycolor)
43 {
44 // Wait for computer reply first (avoid potential "ghost move" bug)
45 return;
46 }
47 this.newGame("computer");
48 },
49 clickFriendGame: function(e) {
50 this.getRidOfTooltip(e.currentTarget);
51 document.getElementById("modal-fenedit").checked = true;
52 },
53 // In main hall :
54 newGame: function(mode, fenInit, color, oppId, gameId) {
55 const fen = fenInit || VariantRules.GenRandInitFen();
56 console.log(fen); //DEBUG
57 if (mode=="human" && !oppId)
58 {
59 const storageVariant = localStorage.getItem("variant");
60 if (!!storageVariant && storageVariant !== variant.name
61 && localStorage["score"] == "*")
62 {
63 return alert(translations["Finish your "] +
64 storageVariant + translations[" game first!"]);
65 }
66 // Send game request and wait..
67 try {
68 this.conn.send(JSON.stringify({code:"newgame", fen:fen, gameid: getRandString() }));
69 } catch (INVALID_STATE_ERR) {
70 return; //nothing achieved
71 }
72 this.seek = true;
73 let modalBox = document.getElementById("modal-newgame");
74 modalBox.checked = true;
75 setTimeout(() => { modalBox.checked = false; }, 2000);
76 return;
77 }
78 const prefix = this.getStoragePrefix(mode);
79 if (mode == "computer")
80 {
81 const storageVariant = localStorage.getItem(prefix+"variant");
82 if (!!storageVariant)
83 {
84 const score = localStorage.getItem(prefix+"score");
85 if (storageVariant !== variant.name && score == "*")
86 {
87 if (!confirm(storageVariant +
88 translations[": unfinished computer game will be erased"]))
89 {
90 return;
91 }
92 }
93 }
94 }
95 else if (mode == "friend")
96 {
97 const storageVariant = localStorage.getItem(prefix+"variant");
98 if (!!storageVariant)
99 {
100 const score = localStorage.getItem(prefix+"score");
101 if (storageVariant !== variant.name && score == "*")
102 {
103 if (!confirm(storageVariant +
104 translations[": current analysis will be erased"]))
105 {
106 return;
107 }
108 }
109 }
110 }
111 this.vr = new VariantRules(fen, []);
112 this.score = "*";
113 this.pgnTxt = ""; //redundant with this.score = "*", but cleaner
114 this.mode = mode;
115 this.incheck = [];
116 this.fenStart = V.ParseFen(fen).position; //this is enough
117 if (mode=="human")
118 {
119 // Opponent found!
120 this.gameId = gameId;
121 this.oppid = oppId;
122 this.oppConnected = true;
123 this.mycolor = color;
124 this.seek = false;
125 if (this.sound >= 1)
126 new Audio("/sounds/newgame.mp3").play().catch(err => {});
127 document.getElementById("modal-newgame").checked = false;
128 }
129 else if (mode == "computer")
130 {
131 this.compWorker.postMessage(["init",this.vr.getFen()]);
132 this.mycolor = (Math.random() < 0.5 ? 'w' : 'b');
133 if (this.mycolor != this.vr.turn)
134 this.playComputerMove();
135 }
136 else if (mode == "friend")
137 this.mycolor = "w"; //convention...
138 //else: problem solving: nothing more to do
139 if (mode != "problem")
140 this.setStorage(); //store game state in case of interruptions
141 },
142 continueGame: function(mode) {
143 this.mode = mode;
144 this.oppid = (mode=="human" ? localStorage.getItem("oppid") : undefined);
145 const prefix = this.getStoragePrefix(mode);
146 this.mycolor = localStorage.getItem(prefix+"mycolor");
147 const moves = JSON.parse(localStorage.getItem(prefix+"moves"));
148 const fen = localStorage.getItem(prefix+"fen");
149 const score = localStorage.getItem(prefix+"score"); //set in "endGame()"
150 this.fenStart = localStorage.getItem(prefix+"fenStart");
151 this.vr = new VariantRules(fen, moves);
152 this.incheck = this.vr.getCheckSquares(this.vr.turn);
153 if (mode == "human")
154 {
155 this.gameId = localStorage.getItem("gameId");
156 // Send ping to server (answer pong if opponent is connected)
157 this.conn.send(JSON.stringify({
158 code:"ping",oppid:this.oppid,gameId:this.gameId}));
159 }
160 else if (mode == "computer")
161 {
162 this.compWorker.postMessage(["init",fen]);
163 if (score == "*" && this.mycolor != this.vr.turn)
164 this.playComputerMove();
165 }
166 //else: nothing special to do in friend mode
167 if (score != "*")
168 {
169 // Small delay required when continuation run faster than drawing page
170 setTimeout(() => this.endGame(score), 100);
171 }
172 },
173
174
175 // TODO: option du bouton "new game"
176 const modalFenEdit = [
177 h('input',
178 {
179 attrs: { "id": "modal-fenedit", type: "checkbox" },
180 "class": { "modal": true },
181 }),
182 h('div',
183 {
184 attrs: { "role": "dialog", "aria-labelledby": "titleFenedit" },
185 },
186 [
187 h('div',
188 {
189 "class": { "card": true, "smallpad": true },
190 },
191 [
192 h('label',
193 {
194 attrs: { "id": "close-fenedit", "for": "modal-fenedit" },
195 "class": { "modal-close": true },
196 }
197 ),
198 h('h3',
199 {
200 attrs: { "id": "titleFenedit" },
201 "class": { "section": true },
202 domProps: { innerHTML: translations["Game state (FEN):"] },
203 }
204 ),
205 h('input',
206 {
207 attrs: {
208 "id": "input-fen",
209 type: "text",
210 value: VariantRules.GenRandInitFen(),
211 },
212 }
213 ),
214 h('button',
215 {
216 on: { click:
217 () => {
218 const fen = document.getElementById("input-fen").value;
219 document.getElementById("modal-fenedit").checked = false;
220 this.newGame("friend", fen);
221 }
222 },
223 domProps: { innerHTML: translations["Ok"] },
224 }
225 ),
226 h('button',
227 {
228 on: { click:
229 () => {
230 document.getElementById("input-fen").value =
231 VariantRules.GenRandInitFen();
232 }
233 },
234 domProps: { innerHTML: translations["Random"] },
235 }
236 ),
237 ]
238 )
239 ]
240 )
241 ];
242 elementArray = elementArray.concat(modalFenEdit);