596 lines
16 KiB
JavaScript
Executable File
596 lines
16 KiB
JavaScript
Executable File
var $ = jQuery;
|
|
const getElement = (id) => document.getElementById(id);
|
|
const ws = new WebSocket('ws://bwc.ryanpandya.com/socket');
|
|
var username = "unnamed";
|
|
var pId = 0;
|
|
var cards = [];
|
|
var lastCard = false;
|
|
var players = [];
|
|
var gameMode = "draw";
|
|
const timeFormat = 'h:mm a [PDT]';
|
|
const notification_pos = "top-right";
|
|
|
|
function range(size, startAt = 0) {
|
|
return [...Array(size).keys()].map(i => i + startAt);
|
|
}
|
|
|
|
function heartbeat() {
|
|
clearTimeout(this.pingTimeout);
|
|
console.log("Ping");
|
|
this.pingTimeout = setTimeout(() => {
|
|
this.terminate();
|
|
}, 30000 + 1000);
|
|
}
|
|
|
|
ws.onopen = (moot) => {
|
|
heartbeat;
|
|
var urlParams = new URLSearchParams(window.location.search);
|
|
console.log('Connected to websocket.');
|
|
username = urlParams.get('username');
|
|
UIkit.notification({
|
|
message: 'Connected!',
|
|
status: 'success',
|
|
pos: notification_pos,
|
|
timeout: 1000
|
|
});
|
|
if(username == null || username == ""){
|
|
window.location = "/";
|
|
}
|
|
else{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const addMessage = (e) => {
|
|
var self_marker = "";
|
|
if(e.pId == pId){
|
|
self_marker = "self";
|
|
}
|
|
$("ul#chatbox").append(
|
|
'<li class="message uk-margin-top">\
|
|
<p class="uk-text-muted uk-text-small uk-margin-small">\
|
|
<span class="uk-float-right uk-margin-right">'+e.timestamp+'</span>\
|
|
<span class="uk-text-primary uk-text-bold username '+self_marker+'" pId='+e.pId+'>'+e.username+'</span>\
|
|
<p style="font-size:12px;">'+e.message+'</p>\
|
|
</p>\
|
|
</li>'
|
|
);
|
|
}
|
|
|
|
const addUser = (newPlayer) => {
|
|
var picker = "";
|
|
var existing = false;
|
|
players.forEach(function(p){ // Check if we already know about this player (is this a reconnection attempt)
|
|
if(p.pId == newPlayer.pId){ // Looks like it is
|
|
existing = true; console.log("Hit on " + newPlayer.username); // Make note
|
|
}
|
|
});
|
|
|
|
if(existing){
|
|
// What to do if this is a duplicate
|
|
|
|
}else{
|
|
// Otherwise
|
|
notice(newPlayer.username + " has joined the game.");
|
|
players.push(newPlayer);
|
|
if(newPlayer.username == username){ // This user is actually us, so make the username editable
|
|
picker = '<div class="uk-overlay uk-position-center"><span class="change-profile uk-icon uk-overlay-icon" uk-overlay-icon="icon: camera" uk-toggle="target: #profileModal"></span></div>';
|
|
u = '<input class="uk-form-blank uk-text-primary play-mode-username input-username" onKeyUp="javascript:playModeChangeUsername();" id="username" value="'+username+'">';
|
|
}
|
|
else{ // Otherwise just display the username
|
|
u = newPlayer.username;
|
|
}
|
|
|
|
var el = '\
|
|
<li class="player" data-pId="'+newPlayer.pId+'"><div class="uk-inline"><img data-pId="'+newPlayer.pId+'" class="uk-border-circle player" src="'+newPlayer.profilepic+'" alt="" width="100" height="100">'+picker+'</div><div class="player-username">'+u+'</div></li>';
|
|
|
|
$("ul.players-list").append(el);
|
|
$("span#number-of-players").text(parseInt($("span#number-of-players").text())+1); // This is probably wrong and will cause duplicates
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const delUser = (username) => {
|
|
|
|
}
|
|
|
|
const changeMode = (data) => {
|
|
$("#pick-first-turn").css({'display':'flex'});
|
|
$("#card-view").hide();
|
|
$(".active-card-controls").hide();
|
|
|
|
if(data.playerTurn.pId == pId){
|
|
notice("The game has started. Your move!");
|
|
}
|
|
else{
|
|
notice("The game has started. Move: " + data.playerTurn.username);
|
|
}
|
|
gameMode = data.mode;
|
|
changeActivePlayer(data.playerTurn, data.incompleteCard);
|
|
}
|
|
|
|
const decrementCardsCount = () => {
|
|
var el = $("#toggle_play > .uk-badge");
|
|
var newNumber = parseInt(el.text()) - 1;
|
|
console.log(newNumber);
|
|
if(newNumber < 2){
|
|
el.text("last card").css({'background':'maroon',color:'white'});
|
|
}
|
|
if(newNumber == 0 || newNumber == NaN){
|
|
el.text("out of cards").css({'background':'black',color:'white'});
|
|
}
|
|
else{
|
|
el.html(newNumber + " cards").css({'background':'#eee',color:'#666'});;
|
|
}
|
|
};
|
|
|
|
const changeActivePlayer = (player, card) => {
|
|
clearActiveCard();
|
|
if(player.pId == pId){
|
|
// Our turn!
|
|
$(".active-card-controls").css({'display':'flex'});
|
|
if(card){
|
|
console.log("There's a card in memory already.");
|
|
pullCard(card);
|
|
}
|
|
else{
|
|
console.log("Requesting a card from the server...");
|
|
request = {
|
|
'type': 'pullCard',
|
|
'player': player
|
|
}
|
|
decrementCardsCount();
|
|
ws.send(JSON.stringify(request));
|
|
}
|
|
$("#game-status").text("your turn").css({'background':'palegoldenrod','color':'#666'}).fadeIn();
|
|
}
|
|
else{
|
|
$("#game-status").text(player.username+"'s turn").fadeIn();
|
|
$(".turn-indicator").css({"display":"inherit"});
|
|
if(!card){
|
|
decrementCardsCount();
|
|
}
|
|
else{
|
|
if(card.revealed){
|
|
$(".revealed-card-notice").show();
|
|
pullCard(card);
|
|
}
|
|
}
|
|
}
|
|
$("b.currentPlayer").text(player.username);
|
|
$("li.current-player").removeClass("current-player");
|
|
$("li[data-pId="+player.pId+"]").addClass("current-player");
|
|
|
|
}
|
|
|
|
const revealCard = () => {
|
|
card.revealed = true;
|
|
packet = {
|
|
'type': 'revealCard',
|
|
'card': card
|
|
}
|
|
markRevealedCard();
|
|
ws.send(JSON.stringify(packet));
|
|
}
|
|
const clearActiveCard = () => {
|
|
var empty = "";
|
|
$(".active-card").hide().attr('data-author',empty);
|
|
$("#pick-first-turn").css({'display':'flex'});
|
|
$(".revealed-card-notice").hide();
|
|
$(".active-card-controls").hide();
|
|
$(".active-card h1.card-title").text(empty);
|
|
$(".active-card img.card-picture").attr('src',empty);
|
|
$(".active-card div.card-content").text(empty);
|
|
$("li.reveal-card > a").text("Reveal Card").removeClass('uk-disabled').removeClass('revealed');
|
|
}
|
|
const doneWithCard = () => {
|
|
clearActiveCard();
|
|
$("#game-status").css({"background":"#1e87f0","color":"#fff"});
|
|
packet = {
|
|
'type': 'endTurn'
|
|
}
|
|
ws.send(JSON.stringify(packet));
|
|
}
|
|
|
|
const addVote = (i) => {
|
|
var el = $(".play-list-vote[data-pId="+i+"]");
|
|
el.text(parseInt(el.text()) + 1).css({"display":"grid", "float":"right"});
|
|
}
|
|
|
|
const pullCard = (pulledCard) => {
|
|
card = pulledCard;
|
|
|
|
const cardAuthor = pulledCard.author;
|
|
const cardTitle = pulledCard.title;
|
|
const cardImage = pulledCard.image;
|
|
const cardContent = pulledCard.content;
|
|
|
|
$(".active-card").attr('data-author',cardAuthor);
|
|
$(".active-card h1.card-title").text(cardTitle); if(cardTitle == ""){$(".active-card h1.card-title").hide()}
|
|
$(".active-card img.card-picture").attr('src',cardImage);
|
|
$(".active-card div.card-content").text(cardContent);
|
|
|
|
if(cardAuthor == username){
|
|
$(".your-card").show();
|
|
}
|
|
|
|
$("#pick-first-turn").hide();
|
|
$("#card-view").css({'display':'flex'});
|
|
if(card.revealed){
|
|
markRevealedCard();
|
|
}
|
|
}
|
|
|
|
const markRevealedCard = () => {
|
|
$("li.reveal-card > a").text("revealed").addClass('uk-disabled revealed');
|
|
}
|
|
|
|
const viewRevealedCard = (card) => {
|
|
pullCard(card);
|
|
if($("b.currentPlayer").first().text() != username){$(".revealed-card-notice").show()};
|
|
}
|
|
|
|
const updateUsername = (i, uname) => {
|
|
$(".input-username").val(uname);
|
|
const url = window.location.origin + window.location.pathname;
|
|
$("span.username[pId='"+i+"']").text(uname);
|
|
$(".input-username").val(uname);
|
|
history.pushState({},
|
|
"rename",
|
|
url + "?username=" + uname
|
|
);
|
|
}
|
|
|
|
ws.onmessage = (event) => {
|
|
event = JSON.parse(event.data);
|
|
switch(event.type){
|
|
case 'init':
|
|
if(event.mode == "error"){
|
|
window.location = window.origin + "?error=username";
|
|
}
|
|
console.log(">> Initializing game...");
|
|
pId = event.id;
|
|
console.log("You are in the game as '" + username + "' (Player " + pId + ").");
|
|
$(".input-username").val(username);
|
|
event.players.forEach(function(p){
|
|
addUser(p);
|
|
});
|
|
$("#toggle_play > .uk-badge").text(event.cards+1 +" cards");
|
|
decrementCardsCount();
|
|
if(event.mode == "play"){
|
|
changeMode(event);
|
|
$("#toggle_play").click();
|
|
}
|
|
$(".input-username").value = username;
|
|
$("span#number-of-players").text(event.players.length);
|
|
event.messages.forEach(function(e){
|
|
addMessage(e);
|
|
});
|
|
break;
|
|
case 'changeMode':
|
|
changeMode(event);
|
|
addMessage(event.message);
|
|
break;
|
|
case 'changeUsername':
|
|
console.log('Got an updated username: Player %s is now "%s".', event.pId, event.username);
|
|
updateUsername(event.pId, event.username);
|
|
break;
|
|
case 'updateCardsList':
|
|
if(username == event.author){
|
|
notice("Your card was submitted.");
|
|
}else{
|
|
notice(event.author + " submitted a card.");
|
|
}
|
|
var el = $("#toggle_play > .uk-badge");
|
|
el.html(parseInt(el.text()) + 1 +" cards");
|
|
break;
|
|
case 'error':
|
|
console.log(">> Error: " + event.content);
|
|
if(event.err_username){
|
|
|
|
}
|
|
UIkit.notification({
|
|
message: event.content,
|
|
status: 'warning',
|
|
pos: notification_pos,
|
|
timeout: 1000
|
|
});
|
|
break;
|
|
case 'notification':
|
|
console.log(">> Notification: " + event.content);
|
|
UIkit.notification({
|
|
message: event.content,
|
|
status: 'success',
|
|
pos: notification_pos,
|
|
timeout: 1000
|
|
});
|
|
break;
|
|
case 'gameOver':
|
|
console.log(">> GAME OVER: " + event.content);
|
|
UIkit.notification({
|
|
message: event.content,
|
|
status: 'success',
|
|
pos: notification_pos,
|
|
timeout: 1000
|
|
});
|
|
$("#game-status").html("game over");
|
|
$("#play_mode").html(
|
|
"<h1>Game over, thanks for playing!</h1>"
|
|
);
|
|
break;
|
|
case 'message':
|
|
console.log(">> Got a message.");
|
|
addMessage(event);
|
|
break;
|
|
case 'changeProfilePic':
|
|
updateProfPic(event.player, event.href);
|
|
break;
|
|
case 'vote':
|
|
addVote(event.pId);
|
|
if(firstPlayerPicked){
|
|
notice("First turn starting!");
|
|
$("#draw_mode").html("");
|
|
}
|
|
break;
|
|
case 'revealCard':
|
|
viewRevealedCard(event.card);
|
|
break;
|
|
case 'pulledCard':
|
|
if(event.last){
|
|
notice("Last card!");
|
|
lastCard = true;
|
|
}
|
|
pullCard(event.card);
|
|
break;
|
|
case 'nextTurn':
|
|
changeActivePlayer(event.playerTurn, null);
|
|
break;
|
|
case 'newPlayer':
|
|
var player = event.player;
|
|
if(player.pId != pId){
|
|
addUser(player);
|
|
}
|
|
break;
|
|
default:
|
|
console.log('Unknown event. Pasting:');
|
|
console.log(event);
|
|
}
|
|
|
|
};
|
|
|
|
const changeUsername = (name) => {
|
|
packet = {
|
|
"type": "changeUsername",
|
|
"pId": pId,
|
|
"username": name
|
|
}
|
|
console.log("Changing username to: '"+name+"'");
|
|
username = name;
|
|
ws.send(JSON.stringify(packet));
|
|
};
|
|
|
|
const notice = (message) => {
|
|
UIkit.notification({
|
|
message: message,
|
|
status: 'primary',
|
|
pos: notification_pos,
|
|
timeout: 2000
|
|
});
|
|
}
|
|
|
|
const error = (message) => {
|
|
UIkit.notification({
|
|
message: message,
|
|
status: 'danger',
|
|
pos: notification_pos,
|
|
timeout: 2000
|
|
});
|
|
}
|
|
|
|
const urlify = (text) => {
|
|
var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
|
|
//var urlRegex = /(https?:\/\/[^\s]+)/g;
|
|
return text.replace(urlRegex, function(url,b,c) {
|
|
var url2 = (c == 'www.') ? 'http://' +url : url;
|
|
return '<a href="' +url2+ '" target="_blank">' + url + '</a>';
|
|
})
|
|
};
|
|
|
|
const submitMessage = () => {
|
|
message = $("#message").val();
|
|
if(message.trim()){
|
|
const timestamp = new Date();
|
|
packet = {
|
|
"type": "message",
|
|
"pId": pId,
|
|
"username": username,
|
|
"message": urlify(message.trim()),
|
|
"timestamp": new Date()
|
|
}
|
|
console.log("Sending message.");
|
|
ws.send(JSON.stringify(packet));
|
|
$("#message").val("");
|
|
}};
|
|
|
|
const chooseGiphy = (url) => {
|
|
$("img.card-picture").attr("src", url);
|
|
$(".uk-close").click();
|
|
}
|
|
|
|
const chooseProfile = (url) => {
|
|
packet = {
|
|
'type': 'changeProfilePic',
|
|
'player': {
|
|
'pId': pId,
|
|
'username': username
|
|
},
|
|
'href': url
|
|
}
|
|
$(".change-profile > svg").hide();
|
|
$(".uk-close").click();
|
|
ws.send(JSON.stringify(packet));
|
|
}
|
|
|
|
const updateProfPic = (player, url) => {
|
|
$("img[data-pId="+player.pId+"]").attr('src',url);
|
|
}
|
|
|
|
const giphySearch = () => {
|
|
var query = $("#giphySearch").val().trim().replace(/ /g, "+");
|
|
const api_url = "https://api.giphy.com/v1/gifs/search?api_key=GUHvLYHRcNgPAIKt4PNZcjYw5FBeBX0F&q="+query+"&limit=25&offset=0&rating=R&lang=en";
|
|
$.ajax({url: api_url, method: 'GET'}).done(function(response){
|
|
|
|
// This is the API response data. It's a JSON object of 25 gifs
|
|
console.log(response.data);
|
|
$("#giphySearchResults").html("");
|
|
response.data.forEach(function(i){
|
|
var giphyURL = i.images.fixed_height.url;
|
|
$("#giphySearchResults").append(
|
|
"<a href='javascript:chooseGiphy("
|
|
+ '"'
|
|
+ giphyURL
|
|
+ '"'
|
|
+");'><img class='search-result' src='"+giphyURL+"'/></a>"
|
|
);
|
|
});
|
|
|
|
});
|
|
};
|
|
|
|
const voteForPlayer = (i) => {
|
|
console.log("Sending in a vote.");
|
|
packet = {
|
|
'type': "vote",
|
|
'pId': i
|
|
}
|
|
|
|
ws.send(JSON.stringify(packet));
|
|
}
|
|
|
|
const playModeChangeUsername = (e) => {
|
|
if(e.keyCode === 13){
|
|
changeUsername($(".player-username > input").val());
|
|
};
|
|
}
|
|
|
|
$().ready(function() {
|
|
$("#toggle_chat").on('click', function(e){
|
|
$(this).closest("li").toggleClass("uk-active");
|
|
});
|
|
|
|
$(".input-username").keydown(function(e){
|
|
if(e.keyCode === 13){
|
|
changeUsername(this.value);
|
|
};
|
|
});
|
|
$(".input-username").focusout(function(e){
|
|
changeUsername(this.value);
|
|
});
|
|
$("#message").keyup(function(e){
|
|
if(e.keyCode === 13){
|
|
submitMessage();
|
|
};
|
|
});
|
|
$("a#toggle_draw").on('click', function(e){
|
|
if(gameMode == "play"){
|
|
// Switch tabs
|
|
$("#play_mode").hide();$("a#toggle_play").closest("li").removeClass("uk-active");
|
|
$("#draw_mode").show();$("a#toggle_draw").closest("li").addClass("uk-active")
|
|
}
|
|
});
|
|
$("a#toggle_play").on('click', function(e){
|
|
if(gameMode == "play"){
|
|
// Switch tabs
|
|
$("#draw_mode").hide();$("a#toggle_draw").closest("li").removeClass("uk-active");
|
|
$("#play_mode").css({"display":"flex"});$("a#toggle_play").closest("li").addClass("uk-active")
|
|
}
|
|
else{
|
|
// Request server to start game
|
|
console.log("Asking server to start game...");
|
|
packet = {
|
|
"type": "startPlayMode",
|
|
"player": username
|
|
}
|
|
ws.send(JSON.stringify(packet));
|
|
setTimeout(function(e){
|
|
if(gameMode == "play"){
|
|
// Switch tabs
|
|
console.log("Switching tabs");
|
|
$("#draw_mode").hide();$("a#toggle_draw").closest("li").removeClass("uk-active");
|
|
$("#play_mode").css({"display":"flex"});$("a#toggle_play").closest("li").addClass("uk-active")
|
|
}
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
$("#submitCard").on('click', function(e){
|
|
submitCard();
|
|
clearCard();
|
|
});
|
|
$("#newCard").on('click', function(e) {
|
|
clearCard();
|
|
});
|
|
|
|
$("#giphySearch").keyup(function(e){
|
|
if(e.keyCode == "13"){
|
|
giphySearch();
|
|
}
|
|
});
|
|
|
|
$("#giphySearchButton").click(function(e){
|
|
giphySearch();
|
|
});
|
|
|
|
|
|
$("#imageInsta").click(function(e){
|
|
notice("TODO: Add insta feature");
|
|
});
|
|
$("#imageUpload").click(function(e){
|
|
notice("TODO: Add upload feature");
|
|
});
|
|
$("#imageDraw").click(function(e){
|
|
notice("TODO: Add draw feature");
|
|
});
|
|
|
|
range(22).forEach(function(e){
|
|
var profURL = "/img/profiles/"+e+".jpg";
|
|
$("#profile-options").append(
|
|
"<a href='javascript:chooseProfile("
|
|
+ '"'
|
|
+ profURL
|
|
+ '"'
|
|
+");'><img class='search-result' src='"+profURL+"'/></a>"
|
|
);
|
|
});
|
|
$('#imageModalContent').on('keyup keypress', function(e) {
|
|
var keyCode = e.keyCode || e.which;
|
|
if (keyCode === 13) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
$("#manualProfile").on('keyup', function(e){
|
|
if(e.keyCode == 13){
|
|
const url = $(this).val();
|
|
|
|
$("#manual-img").attr("src", url).show();
|
|
$("#manual-img-href").attr('href',
|
|
"javascript:chooseProfile("
|
|
+ '"'
|
|
+ url
|
|
+ '"'
|
|
+");"
|
|
);
|
|
}
|
|
else{
|
|
$("#manual-img").attr("src", "").hide();
|
|
|
|
}
|
|
});
|
|
|
|
});
|