Newer
Older
wwwcats / public_html / game.js
var GameState = function() {
	// Websocket handle

	this.conn = null;

	this.started = false;
	this.defusing = false;
	this.ourTurn = false;
	this.locked = false;
	this.favouring = false;
	this.combo = 1;
	this.playerColorMap = {};
	this.playerColors = [
		"#BDE038", "#F2A71B", "#025E73", 
		"#BD2A2E", "#00B3AD", "#F2CB05", 
		"#0468BF", "#D99CD5", "#72583D",
		"#89A666", "#7365A6", "#8C1F1F"
	];

	this.servEvHandlers = new ServerEventsHandlers(this);

	// Player and lobby name

	this.name = "";
	this.lobby = "";

	this.nowPlaying = "";
	this.players = [];
	this.spectators = [];
	this.hand = [];

	// Assets

	this.assets = {};

	this.loadAsset = function(url, el) {
		this.assets[url] = el;
	}

	this.resetButtons = function() {
		let buttons = $(".combo-btn").toArray();
		buttons.forEach(function(btn) {
			$(btn).removeClass("active");
		});
		this.combo = 1;
	}

	this.start = function() {
		// Run the game!
		// Doesn't actually _start_ the game, but rather starts the game client

		$("#player-name").text(this.name);
		$("#lobby-name").text(this.lobby);

		// Scroll wheel hack - allows the user to scroll the card deck horizontally
		// WTF?
		$("#card-deck").mousewheel(function(ev, delta) {
			this.scrollLeft -= (delta * 30);
			ev.preventDefault();
		});

		// Send the contents of the chat box when enter is pressed
		// feat. a stupid scope hack
		(function (gameState) {
			$("#chat-message").keydown( function(ev) {
				if (ev.key === "Enter") {
					if ($( this ).val().startsWith("/")) {
						// Send as a command
						let msg = $( this ).val().substring(1);
						gameState.send(msg);
					} else {
						// Send as a message
						let msg = $( this ).val();
						gameState.send("chat " + msg);
					}

					// Clear the box
					setTimeout(() => {
						$( this ).val("");
						$( this ).html("");
					}, 50);
				}
			});
		})(this);

		// Draw a card
		(function(gameState) {
			$(".draw-pile-container").on('click', function() {
				if (gameState.ourTurn) {
					gameState.send("draw");
				}
			});
		})(this);

		// 2x and 3x buttons
		(function(gameState) {
			let buttons = $(".combo-btn").toArray();
			buttons.forEach(function(btn) {
				$(btn).on("click", function() {
					// deactive all the buttons, except this one
					buttons.forEach(function(b) {
						if (b != btn) {
							$(b).removeClass("active");
							$(b).removeClass("btn-light");
						}
					});
					$(this).toggleClass("active");
					$(this).toggleClass("btn-light");

					if ($(this).hasClass("active")) {
						gameState.combo = $(this).attr("id") == "2x-button" ? 2 : 3;
					} else {
						gameState.combo = 0;
					}
				});
			});
		})(this);

		// Sort button
		(function(gameState) {
			$("#sort-button").on("click", function() {
				gameState.send("sort");
			});
		})(this);

		// Mute button
		(function(gameState) {
			$("#mute-button").on("click", function() {
				if (gameState.assets["atomic.ogg"].muted) {
					gameState.assets["atomic.ogg"].muted = false;
					$("#mute-button").text("Mute sound");
				} else {
					gameState.assets["atomic.ogg"].muted = true;
					$("#mute-button").text("Unmute sound");
				}
			});
		})(this);

		(function(gameState) {
			window.onbeforeunload = function () {
				if (gameState.conn.readyState !== WebSocket.CLOSED) {
					gameState.conn.onclose = null;
					return ""; // Display confirmation message
				}
			};
		})(this);

		this.console("<span class=\"text-info\">Welcome to Detonating Cats!</span>");

		// We're ready to bring the game board into view
		$("#welcome").toggleClass("reveal");
		$("#game-view").toggleClass("reveal");

		this.started = true;
	}

	this.console = function(msg) {
		msg = msg.split(":");
		msg[0] = `<b>${msg[0]}</b>`;
		msg = msg.join(":");
		$("#game-log").append(`<div class="msg">${msg}</div>`);

		// Scroll to bottom
		$("#game-log").scrollTop($("#game-log")[0].scrollHeight);
	}

	this.drawClientsList = function(container, clientList, cl, statusIcon, withColor) {
		container.empty();

		let colorAddition = "";

		clientList.forEach(x => {
			if(withColor) {
				if(typeof this.playerColorMap[x] == "undefined") {
					const randomIndex = Math.floor(Math.random() * this.playerColors.length);
					const color = this.playerColors[randomIndex];
					this.playerColors.splice(randomIndex, 1);
					this.playerColorMap[x] = color;
				}

				colorAddition = `style="background-color: ${this.playerColorMap[x]}"`;
			}

			const firstLetter = x.slice(0, 2);
			const playerName = x;
			x = `<div class="user-icon" ${colorAddition}>${firstLetter}</div>${x}`;
			container.append(`<li class="${cl}" data-player-name="${playerName}">${x} ${statusIcon}</li>`);
		});
	}

	this.drawSpectatorsList = function() {
		this.drawClientsList(
			$("#spectator-list"),
			this.spectators,
			"spectator",
			`<span class="iconify" data-icon="mdi-eye-outline"></span>`,
			false
		);
	}

	this.drawPlayerList = function() {
		this.drawClientsList(
			$("#player-list"),
			this.players,
			"player",
			"",
			true
		);

		(function(gameState) {
			$("#player-list > li").each( function() {
				if (this.dataset.playerName == gameState.nowPlaying) {
					$( this ).addClass("active");
				}
			} );
		})(this);
	}

	this.readFromServer = function(ev) {
		var parts = ev.data.split(" ");

		const eventName = parts[0];
		console.log('Server Event', parts);
		
		if(
			parts.length 
			&& typeof eventName == "string" 
			&& eventName.length 
			&& eventName in this.servEvHandlers
			&& typeof this.servEvHandlers[eventName] == "function"
		) {
			parts.splice(0, 1).map(i => entities(i));
			const eventData = parts;
			return this.servEvHandlers[eventName](eventData);
		}

		console.warn("WARN: received unknown data from server: "+ev.data);
	}

	this.send = function(msg) {
		this.conn.send(msg);
	}

	this.addSpectator = function(nickname) {
		this.freePlayerColor(nickname);
		this.spectators.push(nickname);
		this.drawSpectatorsList();
	}

	this.removeSpectator = function(nickname) {
		this.spectators.splice(this.spectators.indexOf(nickname), 1);
		this.drawSpectatorsList();
	}

	this.addPlayer = function(nickname) { }

	this.removePlayer = function(nickname) { }

	this.freePlayerColor = function(nickname) {
		if(nickname in this.playerColorMap) {
			const color = this.playerColorMap[nickname];
			delete this.playerColorMap[nickname];
			this.playerColors.push(color);
		}
	}
}