324 lines
14 KiB
JavaScript
324 lines
14 KiB
JavaScript
//
|
|
// whackAMole/whackAMoleConsoleES.js
|
|
//
|
|
// Created by Thijs Wenker on 5/8/17.
|
|
// Copyright 2017 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
(function() {
|
|
var _this;
|
|
|
|
var constants = Script.require('./constants.js');
|
|
var helpers = Script.require('./helpers.js');
|
|
var Mole = Script.require('./mole.js');
|
|
var ScoreBoard = Script.require('./scoreBoard.js');
|
|
|
|
var MOLE_STATE = constants.MOLE_STATE;
|
|
|
|
var DEFAULT_MOLE_IDLE_TIME = 2000; // seconds
|
|
var GAME_SPEED_START = 1.0; // Speed at which the game begins before beginning to increases towards the end speed:
|
|
var GAME_SPEED_END = 3.0;
|
|
|
|
var GAME_FPS = 60; // updater
|
|
|
|
var BACKGROUND_MUSIC_URL = helpers.getSoundURL('223196__rap2h__3-revoltant.wav');
|
|
|
|
// This is the state in which the machine is when not all entities required are loaded yet
|
|
var STATE_INITIALIZING = 0;
|
|
// Mode in which the game is trying to lure a player to join
|
|
var STATE_LURE = 1;
|
|
// The mode the game is in while someone plays it
|
|
var STATE_PLAYING = 2;
|
|
|
|
var WAM_READOUTS_PREFIX = 'wam-readout_';
|
|
var WAM_READOUTS_REGEX = new RegExp('^' + WAM_READOUTS_PREFIX + '[0-9]$');
|
|
var WAM_READOUTS_ORDER = [[1, 2], [3, 4]];
|
|
|
|
var WhackAMoleEntityServer = function() {
|
|
_this = this;
|
|
};
|
|
|
|
WhackAMoleEntityServer.prototype = {
|
|
consoleEntityID: null,
|
|
moles: null,
|
|
musicClip: null,
|
|
musicInjector: null,
|
|
scoreBoards: null,
|
|
state: null,
|
|
channel: null,
|
|
updateTimer: null,
|
|
gameSpeed: null,
|
|
previousMoleIndex: null,
|
|
currentMole: null,
|
|
changeMoleAt: null,
|
|
currentMoleWhacked: null,
|
|
mainPlayerSessionUUID: null,
|
|
playerScores: null,
|
|
gameStartedAt: null,
|
|
gameEndsAt: null,
|
|
lastStartupCheck: null,
|
|
preload: function(entityID) {
|
|
_this.consoleEntityID = entityID;
|
|
_this.moles = [];
|
|
_this.scoreBoards = [];
|
|
_this.entityID = entityID;
|
|
_this.musicClip = SoundCache.getSound(BACKGROUND_MUSIC_URL);
|
|
_this.previousMoleIndex = -1;
|
|
_this.state = STATE_LURE;
|
|
_this.currentMole = null;
|
|
_this.playerScores = [0, 0];
|
|
_this.gameStartedAt = -1;
|
|
_this.gameEndsAt = -1;
|
|
|
|
_this.channel = constants.SERVER_CHANNEL_PREFIX + _this.consoleEntityID;
|
|
helpers.debugPrint('_this.channel = ' + _this.channel);
|
|
Messages.messageReceived.connect(_this.onMessage);
|
|
Messages.subscribe(_this.channel);
|
|
|
|
_this.refreshMoles();
|
|
_this.refreshScoreBoard();
|
|
|
|
_this.updateTimer = Script.setInterval(_this.onUpdate, constants.MILLISECONDS_PER_SECOND / GAME_FPS);
|
|
|
|
_this.setState(STATE_INITIALIZING, true);
|
|
_this.setState(STATE_LURE, true);
|
|
},
|
|
getMasterVolume: function() {
|
|
var defaultMasterVolume = 1.0;
|
|
try {
|
|
var userData = JSON.parse(Entities.getEntityProperties(_this.consoleEntityID, 'userData').userData);
|
|
if (userData.whackAMole.masterVolume !== undefined) {
|
|
return userData.whackAMole.masterVolume;
|
|
}
|
|
} catch (e) {
|
|
// e
|
|
}
|
|
return defaultMasterVolume;
|
|
},
|
|
getRandomMole: function() {
|
|
var moleCount = constants.MOLE_GRID_COLUMNS * constants.MOLE_GRID_ROWS;
|
|
var freeMoles = [];
|
|
for (var i = 0; i < moleCount; i++) {
|
|
if (i !== _this.previousMoleIndex) {
|
|
freeMoles.push(i);
|
|
}
|
|
}
|
|
var randomMoleIndex = freeMoles[Math.floor(Math.random() * freeMoles.length)];
|
|
return {
|
|
index: randomMoleIndex,
|
|
column: Math.floor(randomMoleIndex / constants.MOLE_GRID_COLUMNS),
|
|
row: randomMoleIndex % constants.MOLE_GRID_ROWS
|
|
};
|
|
},
|
|
nextRandomMole: function() {
|
|
var randomMole = _this.getRandomMole();
|
|
_this.previousMoleIndex = randomMole.index;
|
|
_this.currentMole = _this.moles[randomMole.column][randomMole.row];
|
|
return _this.currentMole;
|
|
},
|
|
nextAttract: function(nowMilliseconds) {
|
|
var mole =_this.nextRandomMole();
|
|
var runtimeMilliseconds = mole.attract();
|
|
_this.changeMoleAt = nowMilliseconds + runtimeMilliseconds;
|
|
},
|
|
nextPopUp: function(nowMilliseconds, gameSpeed) {
|
|
var mole =_this.nextRandomMole();
|
|
var runtimeMilliseconds = mole.beginMove(nowMilliseconds, gameSpeed);
|
|
_this.changeMoleAt = nowMilliseconds + runtimeMilliseconds;
|
|
_this.currentMoleWhacked = false;
|
|
},
|
|
resetMoles: function() {
|
|
for (var column = 0; column < constants.MOLE_GRID_COLUMNS; column++) {
|
|
for (var row = 0; row < constants.MOLE_GRID_ROWS; row++) {
|
|
_this.moles[column][row].reset();
|
|
}
|
|
}
|
|
},
|
|
setScore: function(player, score) {
|
|
_this.playerScores[player] = score;
|
|
_this.scoreBoards[player].setScore(_this.playerScores[player]);
|
|
},
|
|
incrementScore: function (player) {
|
|
helpers.debugPrint('Player ' + (player === constants.PLAYER_ONE ? 'one': 'two')
|
|
+ _this.playerScores[player] + ' + ' + '1');
|
|
_this.setScore(player, _this.playerScores[player] + 1);
|
|
},
|
|
setState: function(newState, reset) {
|
|
if (newState === _this.state && !reset) {
|
|
helpers.debugPrint('State was already set to ' + newState);
|
|
return;
|
|
}
|
|
if (_this.musicInjector !== null && _this.musicInjector.playing) {
|
|
_this.musicInjector.stop();
|
|
}
|
|
_this.resetMoles();
|
|
helpers.debugPrint('Switching state from ' + _this.state + ' to ' + newState);
|
|
if (newState === STATE_LURE) {
|
|
_this.nextAttract(Date.now());
|
|
} else if (newState === STATE_PLAYING) {
|
|
|
|
var currentMilliseconds = Date.now();
|
|
_this.gameSpeed = GAME_SPEED_START;
|
|
_this.nextPopUp(currentMilliseconds, _this.gameSpeed);
|
|
|
|
_this.setScore(constants.PLAYER_ONE, 0);
|
|
_this.setScore(constants.PLAYER_TWO, 0);
|
|
|
|
_this.gameStartedAt = currentMilliseconds;
|
|
_this.gameEndsAt = currentMilliseconds + (constants.SESSION_TIME * constants.MILLISECONDS_PER_SECOND);
|
|
|
|
if (constants.PLAY_SOUND && _this.musicClip.downloaded) {
|
|
var options = {
|
|
volume: 0.1 * _this.getMasterVolume(),
|
|
loop: true,
|
|
position: Entities.getEntityProperties(_this.consoleEntityID, 'position').position
|
|
};
|
|
_this.musicInjector = Audio.playSound(_this.musicClip, options);
|
|
}
|
|
}
|
|
_this.state = newState;
|
|
},
|
|
onUpdate: function() {
|
|
var currentMilliseconds = Date.now();
|
|
if (_this.state === STATE_PLAYING) {
|
|
if (currentMilliseconds >= _this.gameEndsAt) {
|
|
_this.setState(STATE_LURE);
|
|
return;
|
|
}
|
|
var gameProgress = (Date.now() - _this.gameStartedAt) / (_this.gameEndsAt - _this.gameStartedAt);
|
|
_this.gameSpeed = helpers.mix(GAME_SPEED_START, GAME_SPEED_END, gameProgress);
|
|
if (_this.currentMole === undefined || _this.currentMole.state === MOLE_STATE.DOWN) {
|
|
_this.nextPopUp(currentMilliseconds, _this.gameSpeed);
|
|
} else if (currentMilliseconds >= _this.currentMole.nextMoveAt) {
|
|
_this.currentMole.nextMove(currentMilliseconds);
|
|
if (_this.currentMole.state === MOLE_STATE.DOWN) {
|
|
_this.nextPopUp(currentMilliseconds, _this.gameSpeed);
|
|
}
|
|
}
|
|
} else if (_this.state === STATE_LURE) {
|
|
if (currentMilliseconds >= _this.changeMoleAt) {
|
|
_this.nextAttract(currentMilliseconds);
|
|
}
|
|
}
|
|
},
|
|
onMessage: function(channel, message, sender) {
|
|
if (channel !== _this.channel) {
|
|
return;
|
|
}
|
|
var data = JSON.parse(message);
|
|
if (data.action === 'start') {
|
|
helpers.debugPrint('Starting mole sequence.');
|
|
_this.mainPlayerSessionUUID = sender;
|
|
_this.refreshMoles();
|
|
_this.setState(STATE_PLAYING, true);
|
|
|
|
Script.setTimeout(function () {
|
|
_this.resetMoles();
|
|
}, constants.SESSION_TIME * constants.MILLISECONDS_PER_SECOND);
|
|
} else if (data.action === 'debugFindMole') {
|
|
var foundMole = _this.getMoleByEntityID(data.entityID);
|
|
if (foundMole !== null) {
|
|
helpers.debugPrint('found mole: ' + JSON.stringify(foundMole));
|
|
}
|
|
} else if (data.action === 'whackMole' && _this.state === STATE_PLAYING && !_this.currentMoleWhacked) {
|
|
var whackedMole = _this.getMoleByEntityID(data.entityID);
|
|
if (whackedMole !== null && whackedMole === _this.currentMole) {
|
|
helpers.debugPrint('found mole: ' + JSON.stringify(whackedMole));
|
|
whackedMole.hit();
|
|
_this.currentMoleWhacked = true;
|
|
_this.incrementScore(data.player);
|
|
}
|
|
} else {
|
|
helpers.debugPrint('Could not find action (`' + data.action + '`) with message: ' + message);
|
|
}
|
|
},
|
|
unload: function() {
|
|
Script.clearInterval(_this.updateTimer);
|
|
if (_this.musicInjector !== null && _this.musicInjector.playing) {
|
|
_this.musicInjector.stop();
|
|
}
|
|
Messages.unsubscribe(_this.channel);
|
|
},
|
|
getMoleByEntityID: function(entityID) {
|
|
for (var column = 0; column < constants.MOLE_GRID_COLUMNS; column++) {
|
|
for (var row = 0; row < constants.MOLE_GRID_ROWS; row++) {
|
|
helpers.debugPrint('column ' + column + ' row ' + row);
|
|
helpers.debugPrint(JSON.stringify(_this.moles[column][row]));
|
|
var mole = _this.moles[column][row];
|
|
if (mole.moleEntityID === entityID || mole.colliderID === entityID) {
|
|
return mole;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
refreshScoreBoard: function() {
|
|
var scoreDigits = {};
|
|
Entities.getChildrenIDs(_this.consoleEntityID).forEach(function(entityID) {
|
|
var name = Entities.getEntityProperties(entityID, ['name']).name;
|
|
if (WAM_READOUTS_REGEX.test(name)) {
|
|
var readoutIndex = name.substring(WAM_READOUTS_PREFIX.length);
|
|
helpers.debugPrint(name + ' ' + readoutIndex);
|
|
scoreDigits[Number(readoutIndex)] = entityID;
|
|
}
|
|
});
|
|
var newScoreBoardsList = [];
|
|
for (var i = 0; i < WAM_READOUTS_ORDER.length; i++) {
|
|
var board = WAM_READOUTS_ORDER[i];
|
|
var digits = [];
|
|
for (var j = 0; j < board.length; j++) {
|
|
digits.push(scoreDigits[board[j]]);
|
|
}
|
|
if (digits.length === board.length) {
|
|
newScoreBoardsList.push(new ScoreBoard(digits));
|
|
}
|
|
}
|
|
if (newScoreBoardsList.length === WAM_READOUTS_ORDER.length) {
|
|
_this.scoreBoards = newScoreBoardsList;
|
|
}
|
|
},
|
|
refreshMoles: function() {
|
|
var newMoleList = [];
|
|
var masterVolume = _this.getMasterVolume();
|
|
Entities.getChildrenIDs(_this.consoleEntityID).forEach(function(entityID) {
|
|
var properties = Entities.getEntityProperties(entityID, ['name']);
|
|
if (properties.name.indexOf(constants.MOLE_IDENTIFIER_PREFIX) === 0 &&
|
|
properties.name.length === constants.MOLE_IDENTIFIER_NUM_CHARS &&
|
|
properties.name[constants.MOLE_IDENTIFIER_SEPARATOR] === '_') {
|
|
var column = parseInt(properties.name[constants.MOLE_IDENTIFIER_COLUMN_INDEX]) - 1;
|
|
var row = parseInt(properties.name[constants.MOLE_IDENTIFIER_ROW_INDEX]) - 1;
|
|
helpers.debugPrint(column + ' ' + row);
|
|
if (column >= 0 && column < constants.MOLE_GRID_COLUMNS && row >= 0 && row < constants.MOLE_GRID_ROWS) {
|
|
newMoleList.push(new Mole(entityID, column, row, DEFAULT_MOLE_IDLE_TIME, masterVolume));
|
|
helpers.debugPrint(properties.name);
|
|
}
|
|
}
|
|
});
|
|
if (newMoleList.length !== (constants.MOLE_GRID_COLUMNS * constants.MOLE_GRID_ROWS)) {
|
|
helpers.debugPrint('Incorrect number of moles. Probably still loading the game.');
|
|
return;
|
|
}
|
|
|
|
_this.moles = [];
|
|
for (var column = 0; column < constants.MOLE_GRID_COLUMNS; column++) {
|
|
var rowArray = [];
|
|
for (var row = 0; row < constants.MOLE_GRID_ROWS; row++) {
|
|
rowArray.push(null);
|
|
}
|
|
_this.moles.push(rowArray);
|
|
}
|
|
|
|
helpers.debugPrint(JSON.stringify(_this.moles));
|
|
for (var i = 0; i < newMoleList.length; i++) {
|
|
var mole = newMoleList[i];
|
|
helpers.debugPrint(mole.column + ', ' + mole.row);
|
|
_this.moles[mole.column][mole.row] = mole;
|
|
}
|
|
helpers.debugPrint(JSON.stringify(_this.moles));
|
|
}
|
|
};
|
|
return new WhackAMoleEntityServer();
|
|
});
|