primus = refs.primus;
sparks = refs.sparks;
config.rooms.forEach(function(room) {
- room = rooms[room] = new Room(room);
- room.start();
+ rooms[room] = new Room(room);
});
};
*/
function Room(roomname) {
+ this.artist = null; // Artists in lowercase
+ this.artistName = null; // Artists of the track
+ this.artworkUrl = null; // The URL of the album cover
+ this.feat = null; // Featured artists
+ this.finishline = 1; // A counter to handle the 3 fastest answers
+ this.playedtracks = []; // The list of already played songs
+ this.previewUrl = null; // The URL for the preview of the track
+ this.roomname = roomname;
+ this.songcounter = 0; // A counter for the track of the current game
+ this.songtimeleft = 0; // Remaining time for the current playing track
+ this.status = 3; // The room status
+ this.title = null; // Title in lowercase
+ this.trackName = null; // Title of the track
+ this.trackViewUrl = null; // The iTunes URL of the track
+ this.trackscount = 0; // The number of available tracks in the room
+ this.totusers = 0; // The number of players in the room
+ this.usersData = Object.create(null);
+
+ this.initialize();
+}
- var artist // Artists in lowercase
- , artistName
- , artworkUrl
- , feat // Featured artists
- , finishline = 1
- , playedtracks = [] // The list of already played songs
- , previewUrl
- , songcounter = 0
- , songtimeleft // Milliseconds
- , status
- , title // Title in lowercase
- , trackName
- , trackViewUrl
- , trackscount // Number of tracks in the room
- , totusers = 0
- , usersData = Object.create(null);
-
- // User points and statistics
- var addPointsAndStats = function(nickname, allinone) {
- usersData[nickname].guesstime = 30000 - songtimeleft;
- var stats = {};
- switch (finishline) {
- case 1:
- finishline++;
- usersData[nickname].roundpoints = 6;
- if (allinone) {
- usersData[nickname].points += 6;
- stats.points = 6;
- }
- else {
- usersData[nickname].points += 5;
- stats.points = 5;
- }
- usersData[nickname].golds++;
- stats.gold = true;
- break;
- case 2:
- finishline++;
- usersData[nickname].roundpoints = 5;
- if (allinone) {
- usersData[nickname].points += 5;
- stats.points = 5;
- }
- else {
- usersData[nickname].points += 4;
- stats.points = 4;
- }
- usersData[nickname].silvers++;
- stats.silver = true;
- break;
- case 3:
- finishline++;
- usersData[nickname].roundpoints = 4;
- if (allinone) {
- usersData[nickname].points += 4;
- stats.points = 4;
- }
- else {
- usersData[nickname].points += 3;
- stats.points = 3;
- }
- usersData[nickname].bronzes++;
- stats.bronze = true;
- break;
- default:
- usersData[nickname].roundpoints = 3;
- if (allinone) {
- usersData[nickname].points += 3;
- stats.points = 3;
- }
- else {
- usersData[nickname].points += 2;
- stats.points = 2;
- }
+/**
+ * Room states.
+ */
+
+Room.PLAYING = 0; // A track is playing
+Room.LOADING = 1; // A track is loading
+Room.ENDING = 2; // The game is over
+Room.STARTING = 3; // A new game is about to start
+
+/**
+ * Add points and collect players' statistics.
+ */
+
+Room.prototype.addPointsAndStats = function(nickname, allinone) {
+ var stats = {}
+ , userData = this.usersData[nickname];
+
+ switch (this.finishline) {
+ case 1:
+ this.finishline++;
+ if (allinone) {
+ stats.points = 6;
+ userData.points += 6;
+ } else {
+ stats.points = 5;
+ userData.points += 5;
+ }
+ stats.gold = true;
+ userData.golds++;
+ userData.roundpoints = 6;
+ break;
+ case 2:
+ this.finishline++;
+ if (allinone) {
+ stats.points = 5;
+ userData.points += 5;
+ } else {
+ stats.points = 4;
+ userData.points += 4;
+ }
+ stats.silver = true;
+ userData.silvers++;
+ userData.roundpoints = 5;
+ break;
+ case 3:
+ this.finishline++;
+ if (allinone) {
+ stats.points = 4;
+ userData.points += 4;
+ } else {
+ stats.points = 3;
+ userData.points += 3;
+ }
+ stats.bronze = true;
+ userData.bronzes++;
+ userData.roundpoints = 4;
+ break;
+ default:
+ if (allinone) {
+ stats.points = 3;
+ userData.points += 3;
+ } else {
+ stats.points = 2;
+ userData.points += 2;
+ }
+ userData.roundpoints = 3;
+ }
+
+ userData.guessed++;
+ userData.guesstime = 30000 - this.songtimeleft;
+ userData.matched = 'both';
+ userData.totguesstime += userData.guesstime;
+
+ if (userData.registered) {
+ stats.guesstime = userData.guesstime;
+ stats.userscore = userData.points;
+ updateStats(nickname, stats);
+ }
+};
+
+/**
+ * Add a new player in the room.
+ */
+
+Room.prototype.addUser = function(spark, loggedin) {
+ var nickname = spark.nickname
+ , usersData = this.usersData;
+
+ sparks[nickname] = spark;
+
+ usersData[nickname] = {
+ bronzes: 0,
+ golds: 0,
+ guessed: 0,
+ guesstime: null,
+ matched: null,
+ nickname: nickname,
+ points: 0,
+ registered: loggedin,
+ roundpoints: 0,
+ silvers: 0,
+ totguesstime: 0
+ };
+
+ this.totusers++;
+
+ // Broadcast new user event
+ primus.send('updateoverview', this.roomname, this.totusers);
+ spark.send('ready', usersData, this.trackscount, loggedin);
+ primus.room(this.roomname).except(spark.id).send('newuser', nickname, usersData);
+};
+
+/**
+ * Build the podium and start a new game.
+ */
+
+Room.prototype.gameOver = function() {
+ var podium = []
+ , usersData = this.usersData;
+
+ // Build podium
+ for (var key in usersData) {
+ podium.push(usersData[key]);
+ }
+ podium.sort(function(a, b) {
+ return b.points - a.points;
+ });
+ podium.splice(3);
+
+ primus.room(this.roomname).send('gameover', podium);
+
+ // Collect podium stats
+ podium.forEach(function(user, index) {
+ if (user.registered) {
+ updateStats(user.nickname, { podiumplace: index + 1 });
}
- usersData[nickname].matched = 'both';
- usersData[nickname].guessed++;
- usersData[nickname].totguesstime += usersData[nickname].guesstime;
-
- if (usersData[nickname].registered) {
- stats.userscore = usersData[nickname].points;
- stats.guesstime = usersData[nickname].guesstime;
- updateStats(nickname, stats);
+ });
+
+ this.resetPoints(false);
+ this.songcounter = 0;
+
+ // Check if FIFO is full
+ if (this.playedtracks.length === fifolength) {
+ this.playedtracks.splice(0, config.songsinarun);
+ }
+
+ // Start a new game
+ this.status = Room.STARTING;
+ setTimeout(this.sendLoadTrack.bind(this), 5000);
+};
+
+/**
+ * Initialize the room.
+ */
+
+Room.prototype.initialize = function() {
+ var room = this;
+
+ songsdb.zcard([this.roomname], function(err, card) {
+ if (err) {
+ console.error(err.message);
+ process.exit(1);
}
- };
- // Add a new user in the room
- var addUser = function(spark, loggedin) {
- sparks[spark.nickname] = spark;
- usersData[spark.nickname] = {
- nickname: spark.nickname,
- registered: loggedin,
- points: 0,
- roundpoints: 0,
- matched: null,
- guessed: 0,
- guesstime: null,
- totguesstime: 0,
- golds: 0,
- silvers: 0,
- bronzes: 0
- };
- totusers++;
- // Broadcast new user event
- primus.send('updateoverview', roomname, totusers);
- spark.send('ready', usersData, trackscount, loggedin);
- primus.room(roomname).except(spark.id).send('newuser', spark.nickname, usersData);
- };
+ room.trackscount = card;
+ room.sendLoadTrack();
+ });
+};
- var gameOver = function() {
- status = 3; // Game over
+/**
+ * Send a chat message.
+ */
- // Build podium
- var users = [];
- for (var key in usersData) {
- users.push(usersData[key]);
+Room.prototype.onChatMessage = function(msg, spark, to) {
+ var from = spark.nickname;
+
+ if (isString(to)) {
+ // Check if the recipient is in the room
+ if (this.usersData[to]) {
+ spark.send('chatmsg', msg, from, to);
+ sparks[to].send('chatmsg', msg, from, to);
}
- users.sort(function(a, b) {return b.points - a.points;});
- var podium = users.slice(0,3);
- primus.room(roomname).send('gameover', podium);
+ return;
+ }
+
+ // Censor answers from chat
+ var feat = this.feat
+ , msglcase = msg.toLowerCase();
+
+ if (this.status === Room.PLAYING && (amatch(this.artist, msglcase, true) ||
+ (feat && amatch(feat, msglcase, true)) || amatch(this.title, msglcase))) {
+ var notice = 'You are probably right, but you have to use the box above.';
+ spark.send('chatmsg', notice, 'binb', from);
+ return;
+ }
+
+ primus.room(this.roomname).send('chatmsg', msg, from);
+};
+
+/**
+ * Handle players' guesses.
+ */
+
+Room.prototype.onGuess = function(spark, guess) {
+ if (this.status !== Room.PLAYING) {
+ return;
+ }
- // Collect podium stats
- if (podium[0] && podium[0].registered) {
- updateStats(podium[0].nickname, {firstplace:true});
+ var artist = this.artist
+ , feat = this.feat
+ , title = this.title
+ , userData = this.usersData[spark.nickname];
+
+ // The user hasn't guessed anything
+ if (!userData.matched) {
+ if ((artist === title) && amatch(title, guess, true)) {
+ return this.onPair(spark, true);
}
- if (podium[1] && podium[1].registered) {
- updateStats(podium[1].nickname, {secondplace:true});
+ if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
+ return this.onMatch(spark, 'artist');
}
- if (podium[2] && podium[2].registered) {
- updateStats(podium[2].nickname, {thirdplace:true});
+ if (amatch(title, guess)) {
+ return this.onMatch(spark, 'title');
}
-
- resetPoints(false);
- songcounter = 0;
- // Check if FIFO is full
- if (playedtracks.length === fifolength) {
- playedtracks.splice(0, config.songsinarun);
+ return spark.send('nomatch');
+ }
+
+ // The user has guessed the track or the artist
+ if (userData.matched !== 'both') {
+ if (userData.matched === 'artist') {
+ if (amatch(title, guess)) {
+ return this.onPair(spark);
+ }
+ return spark.send('nomatch');
}
+ if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
+ return this.onPair(spark);
+ }
+ return spark.send('nomatch');
+ }
- // Start a new game
- setTimeout(sendLoadTrack, 5000);
- };
+ // The user has guessed both track and artist
+ return spark.send('stoptrying');
+};
- // Return the number of users in the room
- this.getPopulation = function() {
- return totusers;
- };
+/**
+ * Inform a player that he/she is being ignored.
+ */
- // A user is sending a guess
- this.guess = function(spark, guess) {
- if (status === 0) {
- if (!usersData[spark.nickname].matched) { // No track no artist
- if ((artist === title) && amatch(title, guess, true)) {
- addPointsAndStats(spark.nickname, true);
- spark.send('bothmatched');
- primus.room(roomname).send('updateusers', usersData);
- }
- else if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
- usersData[spark.nickname].roundpoints++;
- usersData[spark.nickname].points++;
- usersData[spark.nickname].matched = 'artist';
- spark.send('artistmatched');
- primus.room(roomname).send('updateusers', usersData);
- if (usersData[spark.nickname].registered) {
- var stats = {points:1, userscore:usersData[spark.nickname].points};
- updateStats(spark.nickname, stats);
- }
- }
- else if (amatch(title, guess)) {
- usersData[spark.nickname].roundpoints++;
- usersData[spark.nickname].points++;
- usersData[spark.nickname].matched = 'title';
- spark.send('titlematched');
- primus.room(roomname).send('updateusers', usersData);
- if (usersData[spark.nickname].registered) {
- var stats = {points:1, userscore:usersData[spark.nickname].points};
- updateStats(spark.nickname, stats);
- }
- }
- else {
- spark.send('nomatch');
- }
- }
- else if (usersData[spark.nickname].matched !== 'both') { // Track or artist
- if (usersData[spark.nickname].matched === 'artist') {
- if (amatch(title, guess)) {
- addPointsAndStats(spark.nickname, false);
- spark.send('bothmatched');
- primus.room(roomname).send('updateusers', usersData);
- }
- else {
- spark.send('nomatch');
- }
- }
- else {
- if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
- addPointsAndStats(spark.nickname, false);
- spark.send('bothmatched');
- primus.room(roomname).send('updateusers', usersData);
- }
- else {
- spark.send('nomatch');
- }
- }
- }
- else { // The user has guessed both track and artist
- spark.send('stoptrying');
- }
+Room.prototype.onIgnore = function(who, executor, callback) {
+ // Check if the player to be ignored is in the room
+ if (this.usersData[who]) {
+ sparks[who].send('chatmsg', executor + ' is ignoring you.', 'binb', who);
+ return callback(true, who);
+ }
+ callback(false);
+};
+
+/**
+ * Kick a player.
+ */
+
+Room.prototype.onKick = function(who, why, executor, callback) {
+ var room = this;
+
+ usersdb.hget(['user:' + executor, 'role'], function(err, role) {
+ if (err) {
+ console.error(err.message);
+ return callback(true);
}
- };
- this.ignore = function(who, executor, callback) {
- // Check if the player to be ignored is in the room
- if (usersData[who]) {
- // Inform the bad player that he/she is being ignored
- var recipient = sparks[who];
- recipient.send('chatmsg', executor + ' is ignoring you.', 'binb', who);
- return callback(true, who);
+ // Check role
+ if (role > 0) {
+ if (room.usersData[who]) {
+ if (why) {
+ why = ' (' + why + ')';
+ }
+ var notice = 'you have been kicked by ' + executor + why + '.'
+ , recipient = sparks[who];
+ recipient.send('chatmsg', notice, 'binb', who);
+ recipient.end();
+ }
+ return callback(true);
}
callback(false);
- };
+ });
+};
- this.joinRoom = function(spark) {
- spark.join(roomname);
- addUser(spark, true);
- };
+/**
+ * Handle cases where the player has guessed title or artist.
+ */
- // Kick a user
- this.kick = function(who, why, executor, callback) {
- usersdb.hget(['user:' + executor, 'role'], function(err, role) {
- if (err) {
- console.error(err.message);
- return callback(true);
- }
- if (role > 0) { // Check role
- if (usersData[who]) {
- if (why) {
- why = ' (' + why + ')';
- }
- var notice = 'you have been kicked by ' + executor + why + '.';
- var recipient = sparks[who];
- recipient.send('chatmsg', notice, 'binb', who);
- recipient.end();
- }
- return callback(true);
- }
- callback(false);
+Room.prototype.onMatch = function(spark, what) {
+ var nickname = spark.nickname
+ , usersData = this.usersData
+ , userData = usersData[nickname];
+
+ userData.matched = what;
+ userData.points++;
+ userData.roundpoints++;
+ spark.send(what + 'matched');
+ primus.room(this.roomname).send('updateusers', usersData);
+
+ if (userData.registered) {
+ updateStats(nickname, {
+ points: 1,
+ userscore: userData.points
});
- };
+ }
+};
- // A user has left (DCed, etc.)
- this.removeUser = function(nickname) {
- // Delete the references
- delete sparks[nickname];
- delete usersData[nickname];
- totusers--;
- // Broadcast the event
- primus.send('updateoverview', roomname, totusers);
- primus.room(roomname).send('userleft', nickname, usersData);
- };
+/**
+ * Handle cases where the player has guessed both title and artist.
+ */
- var resetPoints = function(roundonly) {
- for (var key in usersData) {
- if (!roundonly) {
- usersData[key].points = 0;
- usersData[key].guessed = 0;
- usersData[key].totguesstime = 0;
- usersData[key].golds = 0;
- usersData[key].silvers = 0;
- usersData[key].bronzes = 0;
- }
- usersData[key].roundpoints = 0;
- usersData[key].matched = null;
- usersData[key].guesstime = null;
- }
- };
+Room.prototype.onPair = function(spark, allinone) {
+ this.addPointsAndStats(spark.nickname, allinone);
+ spark.send('bothmatched');
+ primus.room(this.roomname).send('updateusers', this.usersData);
+};
- // A user is sending a chat message
- this.sendChatMessage = function(msg, spark, to) {
- if (isString(to)) {
- // Check if the recipient is in the room
- if (usersData[to]) {
- spark.send('chatmsg', msg, spark.nickname, to);
- var recipient = sparks[to];
- recipient.send('chatmsg', msg, spark.nickname, to);
- }
- return;
+/**
+ * Add an unauthenticated player in the room after checking that his/her
+ * nickname is valid.
+ */
+
+Room.prototype.onUnauthenticatedJoin = function(spark, nickname) {
+ var feedback
+ , room = this;
+
+ if (nickname === 'binb') {
+ feedback = 'That name is reserved.';
+ }
+ else if (!isUsername(nickname)) {
+ feedback = 'Name must contain only alphanumeric characters.';
+ }
+ else if (sparks[nickname]) {
+ feedback = 'Name already taken.';
+ }
+
+ if (feedback) {
+ return spark.send('invalidnickname', feedback);
+ }
+
+ // Check if requested nickname belongs to a registered user
+ usersdb.exists(['user:' + nickname], function(err, exists) {
+ if (err) {
+ console.error(err.message);
+ feedback = 'Could not check name availability.';
+ return spark.send('invalidnickname', feedback);
}
- // Censor answers from chat
- var msglcase = msg.toLowerCase();
- if (status === 0 && (amatch(artist, msglcase, true) ||
- (feat && amatch(feat, msglcase, true)) || amatch(title, msglcase))) {
- var notice = 'You are probably right, but you have to use the box above.';
- spark.send('chatmsg', notice, 'binb', spark.nickname);
- return;
+
+ if (exists) {
+ feedback = 'That name belongs to a registered user.';
+ return spark.send('invalidnickname', feedback);
}
- primus.room(roomname).send('chatmsg', msg, spark.nickname);
- };
- // Extract a random track from the database and send the load event
- var sendLoadTrack = function() {
- var index = randInt(trackscount);
- songsdb.zrange([roomname, index, index], function(err, res) {
- if (err) {
- console.error(err.message);
- process.exit(1);
- }
- var id = res[0];
- // Check if extracted track is in the list of already played tracks
- if (~playedtracks.indexOf(id)) {
- return sendLoadTrack();
- }
- playedtracks.push(id);
- var args = [
- 'song:' + id
- , 'artistName'
- , 'trackName'
- , 'previewUrl'
- , 'artworkUrl60'
- , 'trackViewUrl'
- ];
- songsdb.hmget(args, function(err, replies) {
- if (err) {
- console.error(err.message);
- process.exit(1);
- }
- artistName = replies[0];
- artist = artistName.toLowerCase();
- trackName = replies[1];
- title = trackName.toLowerCase();
- feat = /feat\. (.+?)[)\]]/.test(title) ? RegExp.$1 : null;
- previewUrl = replies[2];
- artworkUrl = replies[3];
- trackViewUrl = replies[4];
- primus.room(roomname).send('loadtrack', previewUrl);
- setTimeout(sendPlayTrack, 5000);
- });
- });
- status = 1; // Loading next song
- };
+ spark.nickname = nickname;
+ spark.join(room.roomname);
+ room.addUser(spark, false);
+ });
+};
- var sendPlayTrack = function() {
- songcounter++;
- status = 0; // Playing track
- var data = {
- counter: songcounter,
- tot: config.songsinarun,
- users: usersData
- };
- primus.room(roomname).send('playtrack', data);
- songTimeLeft(Date.now() + 30000, 50);
- setTimeout(sendTrackInfo, 30000);
- };
+/**
+ * Inform a player that he/she is no longer ignored.
+ */
- // Send the room status
- this.sendStatus = function(callback) {
- var data = {
- status: status,
- timeleft: songtimeleft,
- previewUrl: previewUrl
- };
- callback(data);
- };
+Room.prototype.onUnignore = function(who, executor) {
+ if (this.usersData[who]) {
+ var notice = executor + ' has stopped ignoring you.';
+ sparks[who].send('chatmsg', notice, 'binb', who);
+ }
+};
- var sendTrackInfo = function() {
- var trackinfo = {
- artworkUrl: artworkUrl,
- artistName: artistName,
- trackName: trackName,
- trackViewUrl: trackViewUrl,
- };
- primus.room(roomname).send('trackinfo', trackinfo);
- finishline = 1;
-
- if (songcounter < config.songsinarun) {
- resetPoints(true);
- sendLoadTrack();
- return;
- }
+/**
+ * Remove a player from the room.
+ */
- status = 2; // Sending last track info
- setTimeout(gameOver, 5000);
- };
+Room.prototype.removeUser = function(nickname) {
+ var usersData = this.usersData;
- // A user is submitting a name
- this.setNickName = function(spark, nickname) {
- var feedback;
+ // Delete the references
+ delete sparks[nickname];
+ delete usersData[nickname];
- if (nickname === 'binb') {
- feedback = '<span class="label label-important">That name ' +
- 'is reserved.</span>';
- }
- else if (!isUsername(nickname)) {
- feedback = '<span class="label label-important">Name must ' +
- 'contain only alphanumeric characters.</span>';
- }
- else if (sparks[nickname]) {
- feedback = '<span class="label label-important">Name ' +
- 'already taken.</span>';
- }
+ this.totusers--;
- if (feedback) {
- return spark.send('invalidnickname', feedback);
+ // Broadcast the event
+ primus.send('updateoverview', this.roomname, this.totusers);
+ primus.room(this.roomname).send('userleft', nickname, usersData);
+};
+
+/**
+ * Clean up users' data.
+ */
+
+Room.prototype.resetPoints = function(roundonly) {
+ var usersData = this.usersData
+ , userData;
+
+ for (var key in usersData) {
+ userData = usersData[key];
+ if (!roundonly) {
+ userData.points = 0;
+ userData.guessed = 0;
+ userData.totguesstime = 0;
+ userData.golds = 0;
+ userData.silvers = 0;
+ userData.bronzes = 0;
}
+ userData.roundpoints = 0;
+ userData.matched = null;
+ userData.guesstime = null;
+ }
+};
- // Check if requested nickname belongs to a registered user
- var key = 'user:' + nickname;
- usersdb.exists([key], function(err, exists) {
- if (err) {
- console.error(err.message);
- feedback = '<span class="label label-important">Could not ' +
- 'check name availability.</span>';
- return spark.send('invalidnickname', feedback);
- }
- if (exists) {
- feedback = '<span class="label label-important">That name ' +
- 'belongs to a registered user.</span>';
- return spark.send('invalidnickname', feedback);
- }
- spark.nickname = nickname;
- spark.join(roomname);
- addUser(spark, false);
- });
- };
+/**
+ * Extract a random track and send the load event to all connected clients.
+ */
+
+Room.prototype.sendLoadTrack = function() {
+ this.status = Room.LOADING;
+
+ var index = randInt(this.trackscount)
+ , room = this;
- // Timer for the playing song
- var songTimeLeft = function(end, delay) {
- songtimeleft = end - Date.now();
- if (songtimeleft < delay) {
- return;
+ songsdb.zrange([this.roomname, index, index], function(err, res) {
+ if (err) {
+ console.error(err.message);
+ process.exit(1);
+ }
+
+ var id = res[0];
+ // Check if extracted track is in the list of already played tracks
+ if (~room.playedtracks.indexOf(id)) {
+ return room.sendLoadTrack();
}
- setTimeout(songTimeLeft, delay, end, delay);
- };
- // Start the room
- this.start = function() {
- songsdb.zcard([roomname], function(err, card) {
+ room.playedtracks.push(id);
+
+ songsdb.hmget([
+ 'song:' + id
+ , 'artistName'
+ , 'trackName'
+ , 'previewUrl'
+ , 'artworkUrl60'
+ , 'trackViewUrl'
+ ], function(err, replies) {
if (err) {
console.error(err.message);
process.exit(1);
}
- trackscount = card;
- sendLoadTrack();
+
+ room.artistName = replies[0];
+ room.artist = room.artistName.toLowerCase();
+ room.trackName = replies[1];
+ room.title = room.trackName.toLowerCase();
+ room.feat = /feat\. (.+?)[)\]]/.test(room.title) ? RegExp.$1 : null;
+ room.previewUrl = replies[2];
+ room.artworkUrl = replies[3];
+ room.trackViewUrl = replies[4];
+ primus.room(room.roomname).send('loadtrack', room.previewUrl);
+
+ setTimeout(room.sendPlayTrack.bind(room), 5000);
});
- };
+ });
+};
- // Return the number of tracks in the room
- this.tracksCount = function() {
- return trackscount;
- };
+/**
+ * Send the play event to all connected clients.
+ */
+
+Room.prototype.sendPlayTrack = function() {
+ this.status = Room.PLAYING;
+ this.songcounter++;
+
+ primus.room(this.roomname).send('playtrack', {
+ counter: this.songcounter,
+ tot: config.songsinarun,
+ users: this.usersData
+ });
+
+ this.startTimer(Date.now() + 30000, 50);
+ setTimeout(this.sendTrackInfo.bind(this), 30000);
+};
+
+/**
+ * Send the room status to the client that asked for it.
+ */
+
+Room.prototype.sendStatus = function(callback) {
+ callback({
+ status: this.status,
+ timeleft: this.songtimeleft,
+ previewUrl: this.previewUrl
+ });
+};
+
+/**
+ * Send the track info to all connected clients.
+ */
+
+Room.prototype.sendTrackInfo = function() {
+ primus.room(this.roomname).send('trackinfo', {
+ artworkUrl: this.artworkUrl,
+ artistName: this.artistName,
+ trackName: this.trackName,
+ trackViewUrl: this.trackViewUrl,
+ });
- this.unignore = function(who, executor) {
- if (usersData[who]) {
- // Inform the bad player that he/she is no longer ignored
- var notice = executor + ' has stopped ignoring you.';
- var recipient = sparks[who];
- recipient.send('chatmsg', notice, 'binb', who);
+ this.finishline = 1;
+
+ if (this.songcounter < config.songsinarun) {
+ this.resetPoints(true);
+ return this.sendLoadTrack();
+ }
+
+ this.status = Room.ENDING;
+ setTimeout(this.gameOver.bind(this), 5000);
+};
+
+/**
+ * Start a timer to periodically update the remaining time of the playing song.
+ */
+
+Room.prototype.startTimer = function(end, delay) {
+ var interval
+ , room = this;
+
+ room.songtimeleft = end - Date.now();
+
+ interval = setInterval(function() {
+ room.songtimeleft = end - Date.now();
+ if (room.songtimeleft < delay) {
+ clearInterval(interval);
}
- };
-}
+ }, delay);
+};