You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

292 lines
10 KiB

//===== Constructor
const Controls = function() {
this.names = {};
this.playerId = null;
this.countdownTimer = null;
// "Local" and "Global" messages
document.addEventListener('L-conn-error', this.msgConnectionError.bind(this));
document.addEventListener('L-complete', this.msgComplete.bind(this));
document.addEventListener('L-join', this.msgJoin.bind(this));
document.addEventListener('L-skip', this.msgSkip.bind(this));
document.addEventListener('L-stack', this.msgStack.bind(this));
document.addEventListener('G-connected', this.msgConnected.bind(this));
document.addEventListener('G-countdown', this.msgCountdown.bind(this));
document.addEventListener('G-players', this.msgPlayers.bind(this));
document.addEventListener('G-state', this.msgState.bind(this));
// Click handlers
document.getElementById('controls-moves-reset').addEventListener('click', this.onClickMovesReset.bind(this));
document.getElementById('controls-moves-undo').addEventListener('click', this.onClickMovesUndo.bind(this));
document.getElementById('controls-moves-solve').addEventListener('click', this.onClickMovesSolve.bind(this));
document.getElementById('controls-options-objective').addEventListener('click', this.onClickOptionsObjective.bind(this));
document.getElementById('controls-options-robots').addEventListener('click', this.onClickOptionsRobots.bind(this));
document.getElementById('controls-options-walls').addEventListener('click', this.onClickOptionsWalls.bind(this));
document.getElementById('controls-countdown-skip').addEventListener('click', this.onClickSkip.bind(this));
this.setState('CONNECTING');
}
//===== Countdown
Controls.prototype.countdownStart = function(seconds) {
clearTimeout(this.countdownTimer);
this.countdownTimer = this.countdownTick.bind(this);
const countdown = document.getElementById('controls-countdown-value');
countdown.dataset.tick = seconds * 1;
this.countdownTick();
};
Controls.prototype.countdownTick = function() {
const countdown = document.getElementById('controls-countdown-value');
const tick = countdown.dataset.tick * 1;
countdown.dataset.tick = tick - 1;
countdown.innerHTML = tick;
if (tick === 0) {
this.countdownComplete();
return;
}
this.countdownTimer = setTimeout(this.countdownTick.bind(this), 1000);
};
Controls.prototype.countdownComplete = function() {
clearTimeout(this.countdownTimer);
document.getElementById('controls-countdown-value').innerHTML = 0;
};
//===== UI
Controls.prototype.setState = function(state) {
const blocks = [
'controls-connection',
'controls-countdown',
'controls-moves',
'controls-options',
'controls-players',
'controls-solution',
];
blocks.forEach(id => document.getElementById(id).style.display = 'none');
// IDs to show for each state.
const STATE = {
CONNECTING: ['controls-connection'],
PLAY: ['controls-players', 'controls-moves', 'controls-options'],
COUNTDOWN: ['controls-players', 'controls-moves', 'controls-countdown'],
SOLUTION: ['controls-players', 'controls-solution']
};
(STATE[state] || []).forEach(id => document.getElementById(id).style.display = 'block');
};
//===== Message handlers
Controls.prototype.msgJoin = function() {
this.setState('CONNECTING');
document.querySelector('#controls-connection .controls-message').innerHTML = 'Connecting...';
};
Controls.prototype.msgComplete = function(evt) {
document.getElementById('controls-moves-solve').style.display = (evt.detail.complete ? 'block' : 'none');
}
Controls.prototype.msgConnected = function(evt) {
this.playerId = evt.detail.body;
console.log("Setting player id to " + this.playerId)
};
Controls.prototype.msgConnectionError = function() {
this.setState('CONNECTING');
document.querySelector('#controls-connection .controls-message').innerHTML = "Can't reach the server.";
};
Controls.prototype.msgCountdown = function(evt) {
this.setState('COUNTDOWN');
document.getElementById('controls-countdown-moves').innerHTML = evt.detail.body.moveCount;
document.getElementById('controls-countdown-player').innerHTML = this.names[evt.detail.body.id];
this.countdownStart(evt.detail.body.duration);
};
Controls.prototype.msgSkip = function() {
this.countdownComplete();
};
Controls.prototype.msgStack = function(evt) {
const robots = evt.detail.reduce((acc, { id }) => acc.has(id) ? acc : acc.add(id), new Set());
const moveCount = evt.detail.length - robots.size;
document.getElementById('controls-moves-solve').style.display = 'none';
document.getElementById('controls-moves-count').innerHTML = moveCount;
document.getElementById('controls-moves-reset').style.display = moveCount > 0 ? 'block' : 'none';
document.getElementById('controls-moves-undo').style.display = moveCount > 0 ? 'block' : 'none';
};
Controls.prototype.msgPlayers = function(evt) {
this.names = evt.detail.body;
const container = document.getElementById('controls-players');
container.querySelectorAll('.controls-player').forEach(el => {
container.removeChild(el);
});
const keys = Object.keys(this.names);
if (keys.length > 1) {
keys.forEach(connectionId => {
const n = document.createElement('div');
n.innerHTML = this.playerId === connectionId ? `${this.names[connectionId]} (you)` : this.names[connectionId];
n.className = 'controls-player';
container.appendChild(n)
});
}
const msg = container.querySelector('.controls-message');
msg.innerHTML = (keys.length > 1 ? '' : 'Nobody is in the game yet.');
msg.style.display = (keys.length > 1 ? 'none' : 'block');
};
Controls.prototype.msgState = function(evt) {
this.setState(evt.detail.body);
};
//===== Click handlers
Controls.prototype.dispatch = function(evt, data) {
const e = (data ? new CustomEvent(evt, { detail: data }) : new Event(evt));
document.dispatchEvent(e);
};
// Options block
Controls.prototype.onClickOptionsObjective = function() {
this.dispatch('L-objective');
};
Controls.prototype.onClickOptionsRobots = function() {
this.dispatch('L-robots');
};
Controls.prototype.onClickOptionsWalls = function() {
this.dispatch('L-walls');
};
// Moves block
Controls.prototype.onClickMovesReset = function() {
this.dispatch('L-reset');
};
Controls.prototype.onClickMovesSolve = function() {
this.dispatch('L-submit');
};
Controls.prototype.onClickMovesUndo = function() {
this.dispatch('L-undo');
};
// Countdown block
Controls.prototype.onClickSkip = function() {
this.dispatch('L-skip');
};
//===== THE TRASH BIN OF HISTORY
// Controls.prototype.msgRobots = function(evt) {
// this.starts = [];
// this.moves = [];
// evt.detail.body.forEach(({ id, i, j}) => {
// this.starts.push({ id, i, j });
// this.moves.push({ id, i, j });
// });
// };
// Controls.prototype.msgGuess = function(evt) {
// const blurbs = [ " has a solution: ", " can do it in ", " says, maybe ", " wagers ",
// " reckons ", " is pretty sure it's ", ", confidently: ", " wants it to be ",
// " says ", " hazards ", " guesses ", " thinks it might be "];
// const blurb = blurbs[Math.floor(Math.random() * blurbs.length)];
// const msg = evt.detail;
// const guess = msg.guess;
// this.currentWinningGuess = guess;
// document.getElementById('controls-panic').querySelector('.controls-alert-urgent').innerHTML = (`${this.names[msg.id]}${blurb}${guess} moves.`);
// this.showPanic();
// this.countdownStart(5);
// }
// Controls.prototype.msgReset = function() {
// // Broadcast starting locations.
// this.moves = [];
// this.starts.forEach(move => {
// const evtMove = new CustomEvent('L-move', { detail: move });
// document.dispatchEvent(evtMove);
// });
// };
// Controls.prototype.msgUndo = function(evt) {
// if (this.moves.length <= this.starts.length) {
// return;
// }
// const { id } = this.moves.pop();
// const indexOfPreviousMove = this.moves.reduce((acc, v, i) => (v.id === id ? i : acc), -1);
// const previousMove = this.moves.splice(indexOfPreviousMove, 1);
// const evtMove = new CustomEvent('L-move', { detail: previousMove[0] });
// document.dispatchEvent(evtMove);
// };
// Controls.prototype.msgAttempt = function() {
// alert("Ready for winning attempt!");
// };
// Controls.prototype.showWaiting = function() {
// document.getElementById('controls-start').parentNode.style.display = '';
// document.getElementById('controls-walls').parentNode.style.display = '';
// document.getElementById('controls-robots').parentNode.style.display = '';
// document.getElementById('controls-stop').parentNode.style.display = 'none';
// // document.getElementById('controls-moves-reset').parentNode.style.display = 'none';
// document.getElementById('controls-guesses').style.display = 'none';
// document.getElementById('controls-panic').style.display = 'none';
// };
// Controls.prototype.showPanic = function() {
// this.showGuessing();
// document.getElementById('controls-panic').style.display = '';
// };
// Controls.prototype.onClickStart = function() {
// this.dispatch('L-start');
// };
// Controls.prototype.onClickStop = function() {
// this.dispatch('L-stop');
// };
// Controls.prototype.msgStop = function() {
//
// }
// document.addEventListener('L-reset', this.msgReset.bind(this));
// document.addEventListener('L-undo', this.msgUndo.bind(this));
// document.addEventListener('G-stop', this.msgStop.bind(this));
// document.addEventListener('G-start', this.msgStart.bind(this));
// document.addEventListener('G-guess', this.msgGuess.bind(this));
// document.getElementById('controls-start').addEventListener('click', this.onClickStart.bind(this));
// document.getElementById('controls-stop').addEventListener('click', this.onClickStop.bind(this));