content/hifi-content/thoys/dev/2017/whackAMole/whackAMoleConsoleES.js
2022-02-14 02:04:11 +01:00

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();
});