547 lines
21 KiB
PHP
547 lines
21 KiB
PHP
<?php
|
|
require_once 'Db.php';
|
|
|
|
$db = new Database('localhost', 'babyweb', 'root', '');
|
|
|
|
$ranking = $db->requestAll("SELECT * FROM players ORDER BY score DESC");
|
|
$players = $db->requestAll("SELECT * FROM players ORDER BY name");
|
|
|
|
?>
|
|
|
|
<html>
|
|
<head>
|
|
<title>BabyWeb</title>
|
|
<link rel="preconnect" href="https://fonts.gstatic.com">
|
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500&display=swap" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
|
<!-- development version, includes helpful console warnings -->
|
|
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
|
|
<!-- production version, optimized for size and speed -->
|
|
<!--<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>-->
|
|
<style>
|
|
body {
|
|
padding: 0;
|
|
margin: 0;
|
|
font-family: 'Montserrat', sans-serif;
|
|
}
|
|
|
|
.ranking table {
|
|
font-size: 40px;
|
|
text-align: center;
|
|
}
|
|
|
|
.ranking th, .ranking td {
|
|
padding: 10px;
|
|
}
|
|
|
|
.ranking tr:nth-child(2) {
|
|
color: gold;
|
|
}
|
|
|
|
.ranking tr:nth-child(3) {
|
|
color: silver;
|
|
}
|
|
|
|
.ranking tr:nth-child(4) {
|
|
color: saddlebrown;
|
|
}
|
|
|
|
.main {
|
|
height: 100vh;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.ranking, .add-match {
|
|
padding-top: 5vh;
|
|
display: flex;
|
|
justify-content: center;
|
|
flex: 1;
|
|
}
|
|
|
|
.add-match {
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
.match_type {
|
|
margin-bottom: 25px;
|
|
font-size: 2.5vw;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.add-btn {
|
|
height: 50px;
|
|
width: 100px;
|
|
font-size: 15px;
|
|
border: 2px solid;
|
|
border-radius: 5px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.score-input {
|
|
height: 40px;
|
|
width: 80px;
|
|
font-size: 1.5vw;
|
|
text-align: center;
|
|
text-align-last: center;
|
|
-moz-text-align-last: center;
|
|
}
|
|
|
|
.blue {
|
|
color: blue;
|
|
font-weight: bold;
|
|
}
|
|
.red {
|
|
color: red;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.add-match table td {
|
|
font-size: 2.3vw;
|
|
padding: 0 20px;
|
|
text-align: center;
|
|
}
|
|
.add-match table th {
|
|
font-size: 2.5vw;
|
|
padding: 0 20px;
|
|
}
|
|
|
|
.player-select {
|
|
height: 40px;
|
|
width: 20vw;
|
|
font-size: 1.5vw;
|
|
text-align: center;
|
|
text-align-last: center;
|
|
-moz-text-align-last: center;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<section class="main">
|
|
<div class="ranking" style="background-color: lightcoral">
|
|
<table>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Player</th>
|
|
<th>Score</th>
|
|
</tr>
|
|
<tr v-for="(rank, i) in ranking">
|
|
<td>{{ i + 1 }}</td>
|
|
<td>{{ rank.name }}</td>
|
|
<td>{{ rank.score }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="add-match" style="background-color: lightblue">
|
|
<div v-if="error.length">
|
|
<b>{{ error }}</b>
|
|
</div>
|
|
<div class="match_type">
|
|
<label for="1v1" style="margin-right: 30px;">
|
|
<input id="1v1" type="radio" v-model="match_type" value="1v1">
|
|
1 vs 1
|
|
</label>
|
|
<label for="2v2">
|
|
<input id="2v2" type="radio" v-model="match_type" value="2v2">
|
|
2 vs 2
|
|
</label>
|
|
</div>
|
|
<table>
|
|
<tr>
|
|
<th class="red">Joueur 1</th>
|
|
<th class="blue">Joueur 1</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<select class="player-select" v-model="red_p1">
|
|
<option v-for="player in players" :value="player.id">{{ player.name }}</option>
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<select class="player-select" v-model="blue_p1">
|
|
<option v-for="player in players" :value="player.id">{{ player.name }}</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<table v-show="match_type === '2v2'" style="margin-top: 20px;">
|
|
<tr>
|
|
<th class="red">Joueur 2</th>
|
|
<th class="blue">Joueur 2</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<select class="player-select" v-model="red_p2">
|
|
<option value="NULL">Vide.</option>
|
|
<option v-for="player in players" :value="player.id">{{ player.name }}</option>
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<select class="player-select" v-model="blue_p2">
|
|
<option value="NULL">Vide.</option>
|
|
<option v-for="player in players" :value="player.id">{{ player.name }}</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br><br>
|
|
<div>
|
|
<label style="margin-right: 20px;font-size: 2.3vw;">
|
|
<span class="red">Score</span>
|
|
<input class="score-input" type="number" v-model="red_score" min="-11" max="15">
|
|
</label>
|
|
<label style="font-size: 2.3vw">
|
|
<input class="score-input" type="number" v-model="blue_score" min="-11" max="15">
|
|
<span class="blue">Score</span>
|
|
</label>
|
|
</div>
|
|
<br>
|
|
<input class="add-btn" type="submit" value="AJOUTER" @click="addMatch">
|
|
</div>
|
|
</section>
|
|
</div>
|
|
<script>
|
|
let app = new Vue({
|
|
el: '#app',
|
|
data: {
|
|
players: <?= json_encode($players); ?>,
|
|
ranking: <?= json_encode($ranking); ?>,
|
|
match_type: '1v1',
|
|
red_p1: '',
|
|
red_p2: 'NULL',
|
|
blue_p1: '',
|
|
blue_p2: 'NULL',
|
|
red_score: 0,
|
|
blue_score: 0,
|
|
error: '',
|
|
utterance: null,
|
|
messages: {
|
|
'missing.red_p2': {
|
|
error: 'Selectionnez joueur rouge 2',
|
|
speech: 'Aqueu coucou bob !'
|
|
},
|
|
'missing.blue_p2': {
|
|
error: 'Selectionnez joueur bleu 2',
|
|
speech: 'Il manque la bleusaille !'
|
|
},
|
|
'missing.red_p1': {
|
|
error: 'Selectionnez joueur rouge 1',
|
|
speech: 'Rejoins le coté obscure de la force !'
|
|
},
|
|
'missing.blue_p1': {
|
|
error: 'Selectionnez joueur bleu 1',
|
|
speech: 'Aller les bleu !'
|
|
},
|
|
'need2differentplayers': {
|
|
error: 'Selectionnez des joueurs différents !',
|
|
speech: 'Un traitre se cache parmi vous !'
|
|
},
|
|
'needdifferentplayers': {
|
|
error: 'Selectionnez deux joueurs différents !',
|
|
speech: 'Même Chuck Norris ne sais pas jouer contre lui même !'
|
|
},
|
|
'noequals': {
|
|
error: 'Les égalités ne sont pas tolérés !',
|
|
speech: 'Il n\'en restera qu\'un ! Voici une balle, battez vous !'
|
|
},
|
|
'1v1': {
|
|
'forthewinner': [
|
|
'Le gagnant est :winner.',
|
|
':winner paye sa tournée !',
|
|
':winner peut gagner sans toucher les manettes !',
|
|
':winner as battu :looser !',
|
|
'Le baby aime :winner, ça cache quelque chose.',
|
|
'Avec les :winnercolor :winner est imbattable !',
|
|
(new Audio('sounds/champions.mp3')),
|
|
(new Audio('sounds/dading.mp3')),
|
|
(new Audio('sounds/dundunduuun.mp3')),
|
|
(new Audio('sounds/money.mp3')),
|
|
(new Audio('sounds/rasputin.mp3')),
|
|
(new Audio('sounds/sanandreas.mp3'))
|
|
],
|
|
'forthelooser': [
|
|
'Tu as perdu :looser !',
|
|
'Dommage :looser, essaye encore !',
|
|
':looser n\'est pas dans son assiette on dirais, réconforte le :winner',
|
|
'Laisse tomber les :loosercolor :looser, ça te porte pas chance !',
|
|
(new Audio('sounds/denied.mp3')),
|
|
(new Audio('sounds/punch.mp3')),
|
|
(new Audio('sounds/stillstanding.mp3')),
|
|
(new Audio('sounds/windauberror.mp3'))
|
|
],
|
|
},
|
|
'2v2': {
|
|
'forthewinner': [
|
|
'C\'est gagné pour :winners !',
|
|
'Les :winnercolor ont gagné !',
|
|
'Monster kill !',
|
|
'La prochaine partie :redP1 est avec :blueP2, :blueP1 avec :redP2, alea jacta este !',
|
|
':winnerP1 ne prends pas la grosse tête, c\'est :winnerp2 qui ai fait tout le travail !',
|
|
':winnerp2 ne prends pas la grosse tête, c\'est :winnerP1 qui ai fait tout le travail !',
|
|
':winnerP1 ta couleur fétiche est le :winnercolor, c\'est certain',
|
|
'C\est l\'histoire de :winners qui sont sur un bateau, :loosers tombent à l\'eau...',
|
|
':winners devraient surement signer au Paris Saint Germain',
|
|
(new Audio('sounds/denied.mp3')),
|
|
(new Audio('sounds/punch.mp3')),
|
|
(new Audio('sounds/stillstanding.mp3')),
|
|
(new Audio('sounds/windauberror.mp3'))
|
|
],
|
|
'forthelooser': [
|
|
'La team :loosers a perdu !',
|
|
'Les :loosercolor ont perdu !',
|
|
'La team :loosercolor craint !',
|
|
'La prochaine partie, :redP1 et avec :blueP2, :blueP1 avec :redP2, alea jacta este !',
|
|
':looserP1, devrais motiver :looserP2 !',
|
|
':looserP2, devrais motiver :looserP1 !',
|
|
':looserP1, les :loosercolor ne sont pas fait pour toi !',
|
|
'Activation du programme reconforter les loosers, :loosers à deux on est plus fort l\'important c\'est de jouer, ..., Fin du programme',
|
|
(new Audio('sounds/champions.mp3')),
|
|
(new Audio('sounds/dading.mp3')),
|
|
(new Audio('sounds/dundunduuun.mp3')),
|
|
(new Audio('sounds/money.mp3')),
|
|
(new Audio('sounds/rasputin.mp3')),
|
|
(new Audio('sounds/sanandreas.mp3'))
|
|
]
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.utterance = new SpeechSynthesisUtterance();
|
|
this.setBestVoice();
|
|
},
|
|
watch: {
|
|
match_type() {
|
|
if (this.match_type === '1v1') {
|
|
this.red_p2 = 'NULL';
|
|
this.blue_p2 = 'NULL';
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
redP1: function() {
|
|
let player = this.getPlayer(this.red_p1);
|
|
if(player) {
|
|
return player.name.slice(0, -3);
|
|
}
|
|
return '';
|
|
},
|
|
redP2: function() {
|
|
let player = this.getPlayer(this.red_p2);
|
|
if(player) {
|
|
return player.name.slice(0, -3);
|
|
}
|
|
return '';
|
|
},
|
|
blueP1: function() {
|
|
let player = this.getPlayer(this.blue_p1);
|
|
if(player) {
|
|
return player.name.slice(0, -3);
|
|
}
|
|
return '';
|
|
},
|
|
blueP2: function() {
|
|
let player = this.getPlayer(this.blue_p2);
|
|
if(player) {
|
|
return player.name.slice(0, -3);
|
|
}
|
|
return '';
|
|
},
|
|
winner: function() {
|
|
return this.red_score > this.blue_score ?
|
|
this.redP1 : this.blueP1;
|
|
},
|
|
looser: function() {
|
|
return this.red_score < this.blue_score ?
|
|
this.redP1 : this.blueP1;
|
|
},
|
|
winners: function() {
|
|
return this.red_score > this.blue_score ?
|
|
this.redP1 + (this.redP2.length && this.redP1 !== this.redP2 ? ' et ' + this.redP2 : ''):
|
|
this.blueP1 + (this.blueP2.length && this.blueP1 !== this.blueP2 ? ' et ' + this.blueP2 : '');
|
|
},
|
|
loosers: function() {
|
|
return this.red_score < this.blue_score ?
|
|
this.redP1 + (this.redP2.length && this.redP1 !== this.redP2 ? ' et ' + this.redP2 : ''):
|
|
this.blueP1 + (this.blueP2.length && this.blueP1 !== this.blueP2 ? ' et ' + this.blueP2 : '');
|
|
},
|
|
looserP1: function() {
|
|
return this.red_score < this.blue_score ? this.redP1 : this.blueP1 ;
|
|
},
|
|
looserP2: function() {
|
|
return this.red_score < this.blue_score ? this.redP2 : this.blueP2;
|
|
},
|
|
winnerP1: function() {
|
|
return this.red_score > this.blue_score ? this.redP1 : this.blueP1 ;
|
|
},
|
|
winnerP2: function() {
|
|
return this.red_score > this.blue_score ? this.redP2 : this.blueP2;
|
|
},
|
|
winnercolor: function() {
|
|
return this.red_score > this.blue_score ? 'rouge' : 'bleu';
|
|
},
|
|
loosercolor: function() {
|
|
return this.red_score < this.blue_score ? 'rouge' : 'bleu';
|
|
},
|
|
},
|
|
methods: {
|
|
checkSubmission() {
|
|
this.error = '';
|
|
switch(this.match_type) {
|
|
case '2v2':
|
|
if(!this.red_p2 || this.red_p2 === '') {
|
|
this.sendMessage('missing.red_p2');
|
|
return false;
|
|
}
|
|
if(!this.blue_p2 || this.blue_p2 === '') {
|
|
this.sendMessage('missing.blue_p2');
|
|
return false;
|
|
}
|
|
if(!this.red_p1 || this.red_p1 === '') {
|
|
this.sendMessage('missing.red_p1');
|
|
return false;
|
|
}
|
|
if(!this.blue_p1 || this.blue_p1 === '') {
|
|
this.sendMessage('missing.blue_p1');
|
|
return false;
|
|
}
|
|
if(
|
|
(this.red_p1 === this.blue_p1 || this.red_p1 === this.blue_p2 ||
|
|
this.red_p2 === this.blue_p1 || this.red_p2 === this.blue_p2) &&
|
|
this.blue_p2 !== 'NULL' && this.red_p2 !== 'NULL'
|
|
) {
|
|
this.sendMessage('need2differentplayers');
|
|
return false;
|
|
}
|
|
default:
|
|
if(!this.red_p1 || this.red_p1 === '') {
|
|
this.sendMessage('missing.red_p1');
|
|
return false;
|
|
}
|
|
if(!this.blue_p1 || this.blue_p1 === '') {
|
|
this.sendMessage('missing.blue_p1');
|
|
return false;
|
|
}
|
|
if(this.red_p1 === this.blue_p1) {
|
|
this.sendMessage('needdifferentplayers');
|
|
return false;
|
|
}
|
|
if(this.red_score === this.blue_score) {
|
|
this.sendMessage('noequals');
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
},
|
|
addMatch() {
|
|
if (this.checkSubmission()) {
|
|
let self = this;
|
|
axios.post('/add_score.php', {
|
|
red_score: self.red_score,
|
|
blue_score: self.blue_score,
|
|
red_p1: self.red_p1,
|
|
red_p2: self.red_p2,
|
|
blue_p1: self.blue_p1,
|
|
blue_p2: self.blue_p2,
|
|
}).then(function (response) {
|
|
console.log(response);
|
|
self.ranking = response.data;
|
|
self.commentMatch.call(self);
|
|
self.red_p1 = 0;
|
|
self.red_p2 = 'NULL';
|
|
self.blue_p1 = 0;
|
|
self.blue_p2 = 'NULL';
|
|
self.red_score = 0;
|
|
self.blue_score = 0;
|
|
}).catch(function (error) {
|
|
console.error(error);
|
|
this.say('Une erreur est survenue.');
|
|
alert('Une erreur est survenue.');
|
|
});
|
|
}
|
|
},
|
|
commentMatch() {
|
|
let self = this,
|
|
vars,
|
|
message,
|
|
messages = this.messages[this.match_type][Math.floor(Math.random()*2) ?
|
|
'forthewinner' : 'forthelooser'];
|
|
|
|
if(messages.length) {
|
|
message = messages[Math.floor(Math.random() * messages.length)];
|
|
console.log(message);
|
|
if( message.constructor.name === 'HTMLAudioElement') {
|
|
this.play(message);
|
|
} else {
|
|
vars = message.match(/:[0-9A-Za-z_]*/g);
|
|
if(vars) {
|
|
for(let match of vars) {
|
|
try {
|
|
message = message.replace(new RegExp(match, 'g'), self[match.substr(1)]);
|
|
} catch(e) {
|
|
console.error('String replace failed ', e);
|
|
}
|
|
}
|
|
}
|
|
this.say(message);
|
|
}
|
|
}
|
|
},
|
|
sendMessage(messageKey) {
|
|
this.error = this.messages[messageKey].error;
|
|
this.say(this.messages[messageKey].speech);
|
|
},
|
|
setBestVoice() {
|
|
(new Promise(
|
|
function (resolve, reject) {
|
|
let synth = window.speechSynthesis;
|
|
let id;
|
|
id = setInterval(() => {
|
|
if (synth.getVoices().length !== 0) {
|
|
resolve(synth.getVoices());
|
|
clearInterval(id);
|
|
}
|
|
}, 10);
|
|
}
|
|
)).then((function(voices) {
|
|
let frVoices = {};
|
|
for(let voice of window.speechSynthesis.getVoices()) {
|
|
if(voice.lang.indexOf('fr') !== -1) {
|
|
if(voice.name === 'Google français') {
|
|
frVoices.google = voice;
|
|
}
|
|
if(voice.name.indexOf('Microsoft') !== -1) {
|
|
frVoices.microsoft = voice;
|
|
}
|
|
frVoices.unknown = voice;
|
|
}
|
|
}
|
|
this.utterance.voice = frVoices.google ? frVoices.google : (frVoices.microsoft ? frVoices.microsoft : frVoices.unknown)
|
|
}).bind(this));
|
|
},
|
|
say(text) {
|
|
console.info('Saying : ' + text);
|
|
this.utterance.text = text;
|
|
window.speechSynthesis.speak(this.utterance);
|
|
},
|
|
play(audio) {
|
|
console.info('Playing : ' + audio.src);
|
|
audio.play();
|
|
},
|
|
getPlayer(id) {
|
|
for(let player of this.players) {
|
|
if(player.id === id) {
|
|
return player;
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
}
|
|
})
|
|
</script>
|
|
</body>
|
|
</html>
|