Commit | Line | Data |
---|---|---|
ccd4a2b7 | 1 | <template lang="pug"> |
9d58ef95 | 2 | main |
5b020e73 BA |
3 | input#modalNewgame.modal(type="checkbox") |
4 | div(role="dialog" aria-labelledby="titleFenedit") | |
5 | .card.smallpad | |
6 | label#closeNewgame.modal-close(for="modalNewgame") | |
7 | fieldset | |
8 | label(for="selectVariant") {{ st.tr["Variant"] }} | |
9d58ef95 | 9 | select#selectVariant(v-model="newchallenge.vid") |
85e5b5c1 | 10 | option(v-for="v in st.variants" :value="v.id") {{ v.name }} |
5b020e73 BA |
11 | fieldset |
12 | label(for="selectNbPlayers") {{ st.tr["Number of players"] }} | |
9d58ef95 | 13 | select#selectNbPlayers(v-model="newchallenge.nbPlayers") |
5b020e73 BA |
14 | option(v-show="possibleNbplayers(2)" value="2") 2 |
15 | option(v-show="possibleNbplayers(3)" value="3") 3 | |
16 | option(v-show="possibleNbplayers(4)" value="4") 4 | |
17 | fieldset | |
9d58ef95 BA |
18 | label(for="timeControl") Time control (e.g. 3m, 1h+30s, 7d+1d) |
19 | input#timeControl(type="text" v-model="newchallenge.timeControl" | |
20 | placeholder="Time control") | |
5b020e73 | 21 | fieldset |
9d58ef95 | 22 | label(for="selectPlayers") {{ st.tr["Play with? (optional)"] }} |
5b020e73 | 23 | #selectPlayers |
03608482 | 24 | input(type="text" v-model="newchallenge.to[0].name") |
9d58ef95 | 25 | input(v-show="newchallenge.nbPlayers>=3" type="text" |
03608482 | 26 | v-model="newchallenge.to[1].name") |
9d58ef95 | 27 | input(v-show="newchallenge.nbPlayers==4" type="text" |
03608482 | 28 | v-model="newchallenge.to[2].name") |
5b020e73 | 29 | fieldset |
9d58ef95 BA |
30 | label(for="inputFen") {{ st.tr["FEN (optional)"] }} |
31 | input#inputFen(type="text" v-model="newchallenge.fen") | |
32 | button(@click="newChallenge") Send challenge | |
33 | .row | |
34 | .col-sm-12.col-md-5.col-md-offset-1.col-lg-4.col-lg-offset-2 | |
03608482 BA |
35 | .button-group |
36 | button(@click="cpdisplay='challenges'") Challenges | |
37 | button(@click="cpdisplay='players'") Players | |
38 | ChallengeList(v-show="cpdisplay=='challenges'" | |
39 | :challenges="challenges" @click-challenge="clickChallenge") | |
40 | #players(v-show="cpdisplay=='players'") | |
9d58ef95 | 41 | h3 Online players |
03608482 BA |
42 | //TODO: uniquePlayers, show "5 anonymous", and do nothing on click on anonymous |
43 | div(v-for="p in uniquePlayers" @click="challenge(p)") {{ p.name }} | |
9d58ef95 BA |
44 | .row |
45 | .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 | |
46 | button(onClick="doClick('modalNewgame')") New game | |
47 | .row | |
48 | .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 | |
49 | .button-group | |
50 | button(@click="gdisplay='live'") Live games | |
51 | button(@click="gdisplay='corr'") Correspondance games | |
52 | GameList(v-show="gdisplay=='live'" :games="liveGames" | |
53 | @show-game="showGame") | |
54 | GameList(v-show="gdisplay=='corr'" :games="corrGames" | |
55 | @show-game="showGame") | |
625022fd BA |
56 | </template> |
57 | ||
58 | <script> | |
9d58ef95 | 59 | // TODO: blank time control == untimed |
5b020e73 BA |
60 | // main playing hall: online players + current challenges + button "new game" |
61 | // TODO: si on est en train de jouer une partie, le notifier aux nouveaux connectés | |
62 | /* | |
63 | TODO: surligner si nouveau défi perso et pas affichage courant | |
64 | (cadences base + incrément, corr == incr >= 1jour ou base >= 7j) | |
65 | --> correspondance: stocker sur serveur lastMove + uid + color + movesCount + gameId + variant + timeleft | |
66 | fin de partie corr: supprimer partie du serveur au bout de 7 jours (arbitraire) | |
67 | */ | |
68 | // TODO: au moins l'échange des coups en P2P ? et game chat ? | |
69 | // TODO: objet game, objet challenge ? et player ? | |
9d58ef95 BA |
70 | /* |
71 | * Possible events: | |
72 | * - send new challenge (corr or live, cf. time control), with button or click on player | |
73 | * - accept challenge (corr or live) --> send info to all concerned players | |
74 | * - cancel challenge (click on sent challenge) --> send info to all concerned players | |
75 | * - withdraw from challenge (if >= 3 players and previously accepted) | |
76 | * --> send info to all concerned players | |
77 | * - prepare and start new game (if challenge is full after acceptation) | |
78 | * Also send to all connected players (only from me) | |
79 | * - receive "player connect": send all our current challenges (to him or global) | |
80 | * Also send all our games (live - max 1 - and corr) [in web worker ?] | |
81 | * + all our sent challenges. | |
82 | * - receive "playergames": list of games by some connected player (NO corr) | |
83 | * - receive "playerchallenges": list of challenges (sent) by some online player (NO corr) | |
84 | * - receive "player disconnect": remove from players list | |
85 | * - receive "accept/withdraw/cancel challenge": apply action to challenges list | |
86 | * - receive "new game": if live, store locally + redirect to game | |
87 | * If corr: notify "new game has started", give link, but do not redirect | |
03608482 | 88 | * - receive new challenge: if targeted, replace our name with sender name |
9d58ef95 | 89 | */ |
5b020e73 | 90 | import { store } from "@/store"; |
85e5b5c1 | 91 | import { NbPlayers } from "@/data/nbPlayers"; |
9d58ef95 BA |
92 | import { checkChallenge } from "@/data/challengeCheck"; |
93 | import { ArrayFun } from "@/utils/array"; | |
03608482 | 94 | import { ajax } from "@/utils/ajax"; |
5b020e73 BA |
95 | import GameList from "@/components/GameList.vue"; |
96 | import ChallengeList from "@/components/ChallengeList.vue"; | |
625022fd | 97 | export default { |
cf2343ce | 98 | name: "my-hall", |
5b020e73 BA |
99 | components: { |
100 | GameList, | |
101 | ChallengeList, | |
102 | }, | |
fb54f098 BA |
103 | data: function () { |
104 | return { | |
5b020e73 | 105 | st: store.state, |
fb54f098 BA |
106 | gdisplay: "live", |
107 | liveGames: [], | |
108 | corrGames: [], | |
109 | players: [], //online players | |
110 | challenges: [], //live challenges | |
111 | willPlay: [], //IDs of challenges in which I decide to play (>= 3 players) | |
9d58ef95 | 112 | newchallenge: { |
fb54f098 BA |
113 | fen: "", |
114 | vid: 0, | |
115 | nbPlayers: 0, | |
03608482 BA |
116 | // NOTE: id (server DB) and sid (socket ID). |
117 | // Anonymous players just have a socket ID. | |
118 | to: [ | |
119 | {id:0, sid:"", name:""}, | |
120 | {id:0, sid:"", name:""}, | |
121 | {id:0, sid:"", name:""} | |
122 | ], | |
9d58ef95 | 123 | timeControl: "", |
fb54f098 BA |
124 | }, |
125 | }; | |
126 | }, | |
85e5b5c1 BA |
127 | watch: { |
128 | "st.conn": function() { | |
9d58ef95 BA |
129 | this.st.conn.onmessage = this.socketMessageListener; |
130 | this.st.conn.onclose = this.socketCloseListener; | |
85e5b5c1 BA |
131 | }, |
132 | }, | |
9d58ef95 BA |
133 | created: function() { |
134 | // TODO: ask server for current corr games (all but mines: names, ID, time control) | |
135 | if (!!this.st.conn) | |
136 | { | |
137 | this.st.conn.onmessage = this.socketMessageListener; | |
138 | this.st.conn.onclose = this.socketCloseListener; | |
139 | } | |
140 | }, | |
fb54f098 | 141 | methods: { |
9d58ef95 BA |
142 | socketMessageListener: function(msg) { |
143 | const data = JSON.parse(msg.data); | |
144 | switch (data.code) | |
145 | { | |
146 | case "newgame": | |
147 | // TODO: new game just started: data contain all informations | |
148 | // (id, players, time control, fenStart ...) | |
149 | break; | |
150 | // TODO: also receive live games summaries (update) | |
151 | // (just players names, time control, and ID + player ID) | |
152 | case "acceptchallenge": | |
153 | if (true) //TODO: if challenge is full | |
154 | this.newGame(data.challenge, data.user); //user.id et user.name | |
155 | break; | |
156 | case "withdrawchallenge": | |
157 | const cIdx = this.challenges.findIndex(c => c.id == data.cid); | |
158 | let chall = this.challenges[cIdx] | |
159 | ArrayFun.remove(chall.players, p => p.id == data.uid); | |
160 | chall.players.push({id:0, name:""}); | |
161 | break; | |
162 | case "cancelchallenge": | |
163 | ArrayFun.remove(this.challenges, c => c.id == data.cid); | |
164 | break; | |
165 | case "hallconnect": | |
166 | this.players.push({name:data.name, id:data.uid}); | |
167 | break; | |
168 | case "halldisconnect": | |
169 | ArrayFun.remove(this.players, p => p.id == data.uid); | |
03608482 BA |
170 | // TODO: also remove all challenges sent by this player, |
171 | // and all live games where he plays and no other opponent is online | |
9d58ef95 BA |
172 | break; |
173 | } | |
174 | }, | |
175 | socketCloseListener: function() { | |
176 | this.st.conn.addEventListener('message', socketMessageListener); | |
177 | this.st.conn.addEventListener('close', socketCloseListener); | |
178 | }, | |
179 | clickPlayer: function() { | |
180 | //this.newgameInfo.players[0].name = clickPlayer.name; | |
181 | //show modal; | |
182 | }, | |
fb54f098 | 183 | showGame: function(game) { |
5b020e73 BA |
184 | // NOTE: if we are an observer, the game will be found in main games list |
185 | // (sent by connected remote players) | |
186 | this.$router.push("/" + game.id) | |
fb54f098 BA |
187 | }, |
188 | challenge: function(player) { | |
fb54f098 BA |
189 | }, |
190 | clickChallenge: function(challenge) { | |
191 | const index = this.challenges.findIndex(c => c.id == challenge.id); | |
192 | const toIdx = challenge.to.findIndex(p => p.id == user.id); | |
193 | const me = {name:user.name,id:user.id}; | |
194 | if (toIdx >= 0) | |
195 | { | |
196 | // It's a multiplayer challenge I accepted: withdraw | |
197 | this.st.conn.send(JSON.stringify({code:"withdrawchallenge", | |
198 | cid:challenge.id, user:me})); | |
199 | this.challenges.to.splice(toIdx, 1); | |
200 | } | |
201 | else if (challenge.from.id == user.id) //it's my challenge: cancel it | |
202 | { | |
203 | this.st.conn.send(JSON.stringify({code:"cancelchallenge", cid:challenge.id})); | |
204 | this.challenges.splice(index, 1); | |
205 | } | |
206 | else //accept a challenge | |
207 | { | |
208 | this.st.conn.send(JSON.stringify({code:"acceptchallenge", | |
209 | cid:challenge.id, user:me})); | |
210 | this.challenges[index].to.push(me); | |
211 | } | |
212 | // TODO: accepter un challenge peut lancer une partie, il | |
213 | // faut alors supprimer challenge + creer partie + la retourner et l'ajouter ici | |
fb54f098 BA |
214 | // si pas le mien et FEN speciale :: (charger code variante et) |
215 | // montrer diagramme + couleur (orienté) | |
216 | }, | |
217 | // user: last person to accept the challenge | |
9d58ef95 | 218 | newGame: function(chall, user) { |
fb54f098 BA |
219 | const fen = chall.fen || V.GenRandInitFen(); |
220 | const game = {}; //TODO: fen, players, time ... | |
221 | //setStorage(game); //TODO | |
9d58ef95 | 222 | game.players.forEach(p => { //...even if game is by corr (could be played live, why not...) |
fb54f098 BA |
223 | this.conn.send( |
224 | JSON.stringify({code:"newgame", oppid:p.id, game:game})); | |
225 | }); | |
226 | if (this.settings.sound >= 1) | |
227 | new Audio("/sounds/newgame.mp3").play().catch(err => {}); | |
228 | }, | |
9d58ef95 BA |
229 | newChallenge: async function() { |
230 | const idxInVariants = | |
231 | this.st.variants.findIndex(v => v.id == this.newchallenge.vid); | |
03608482 | 232 | const vname = this.st.variants[idxInVariants].name; |
9d58ef95 BA |
233 | const vModule = await import("@/variants/" + vname + ".js"); |
234 | window.V = vModule.VariantRules; | |
03608482 | 235 | // checkChallenge side-effect = set FEN, and mainTime + increment in seconds |
9d58ef95 BA |
236 | const error = checkChallenge(this.newchallenge); |
237 | if (!!error) | |
238 | return alert(error); | |
03608482 BA |
239 | // Less than 3 days ==> live game (TODO: heuristic... 40 moves also) |
240 | const liveGame = | |
241 | this.newchallenge.mainTime + 40 * this.newchallenge.increment < 3*24*60*60; | |
242 | // Check that the players (if any indicated) are online | |
243 | for (let p of this.newchallenge.to) | |
9d58ef95 | 244 | { |
03608482 BA |
245 | if (p.name != "") |
246 | { | |
247 | const pIdx = this.players.findIndex(pl => pl.name == p.name); | |
248 | if (pIdx === -1) | |
249 | return alert(p.name + " is not connected"); | |
250 | p.id = this.players[pIdx].id; | |
251 | p.sid = this.players[pIdx].sid; | |
252 | } | |
253 | } | |
254 | const finishAddChallenge = (cid) => { | |
255 | const chall = Object.assign( | |
256 | {}, | |
9d58ef95 | 257 | this.newchallenge, |
03608482 BA |
258 | { |
259 | id: cid, | |
260 | from: this.st.user, | |
261 | added: Date.now(), | |
262 | vname: vname, | |
fb54f098 BA |
263 | } |
264 | ); | |
03608482 BA |
265 | this.challenges.push(chall); |
266 | document.getElementById("modalNewgame").checked = false; | |
267 | }; | |
268 | if (liveGame) | |
9d58ef95 | 269 | { |
03608482 BA |
270 | const chall = JSON.stringify({ |
271 | code: "sendchallenge", | |
272 | sender: {name:this.st.user.name, id:this.st.user.id, sid:this.st.user.sid}, | |
273 | }); | |
274 | if (this.newchallenge.to[0].id > 0) | |
9d58ef95 | 275 | { |
03608482 BA |
276 | // Challenge with targeted players |
277 | this.newchallenge.to.forEach(p => { | |
278 | if (p.id > 0) | |
279 | this.st.conn.send(Object.assign({}, chall, {receiver: p.sid})); | |
9d58ef95 BA |
280 | }); |
281 | } | |
282 | else | |
283 | { | |
284 | // Open challenge: send to all connected players | |
03608482 | 285 | this.players.forEach(p => { this.st.conn.send(chall); }); |
9d58ef95 | 286 | } |
03608482 BA |
287 | // Live challenges have cid = 0 |
288 | finishAddChallenge(0); | |
289 | } | |
290 | else //correspondance game: | |
291 | { | |
292 | // Possible (server) error if filled player does not exist | |
293 | ajax( | |
294 | "/challenges/" + this.newchallenge.vid, | |
295 | "POST", | |
296 | this.newchallenge, | |
297 | response => { finishAddChallenge(cid); } | |
298 | ); | |
9d58ef95 | 299 | } |
fb54f098 BA |
300 | }, |
301 | possibleNbplayers: function(nbp) { | |
9d58ef95 | 302 | if (this.newchallenge.vid == 0) |
fb54f098 | 303 | return false; |
85e5b5c1 | 304 | const variants = this.st.variants; |
fb54f098 | 305 | const idxInVariants = |
9d58ef95 | 306 | variants.findIndex(v => v.id == this.newchallenge.vid); |
fb54f098 BA |
307 | return NbPlayers[variants[idxInVariants].name].includes(nbp); |
308 | }, | |
309 | }, | |
85e5b5c1 | 310 | }; |
ccd4a2b7 | 311 | </script> |
85e5b5c1 BA |
312 | |
313 | <style lang="sass"> | |
314 | // TODO | |
315 | </style> |