From 775fa74f4fa303f876ba4a0e912c837addc59569 Mon Sep 17 00:00:00 2001 From: Brian White Date: Wed, 27 Apr 2011 15:26:56 -0400 Subject: [PATCH] Web frontend: Move CSS to separate files, escape player and game names, prevent animation of second card play during the same turn, and only show relevant buttons at various parts of the game IRC frontend: Remove extra 'error' event handler and add !help command Game Manager: Gameplay direction should reset to left to right instead of right to left --- lib/frontends/irc/index.js | 26 +++-- lib/frontends/web/index.js | 4 + lib/frontends/web/public/game.js | 90 ++++++++++------ lib/frontends/web/public/index.htm | 138 ++++++------------------- lib/frontends/web/public/style.css | 64 ++++++++++++ lib/frontends/web/public/style.ie6.css | 17 +++ lib/manager.js | 2 +- 7 files changed, 193 insertions(+), 148 deletions(-) create mode 100644 lib/frontends/web/public/style.css create mode 100644 lib/frontends/web/public/style.ie6.css diff --git a/lib/frontends/irc/index.js b/lib/frontends/irc/index.js index 7f8d6db..4cf2628 100644 --- a/lib/frontends/irc/index.js +++ b/lib/frontends/irc/index.js @@ -101,16 +101,17 @@ GameInterface.prototype.init = function() { var self = this, manager = this.manager; + self.log('Connecting to IRC server ...', LOG.INFO); conn = new IrcClient(this.config.server, this.config.nick, this.config) conn.on('ready', function() { - self.log('Connected to IRC server', LOG.INFO); + self.log('Connected to IRC server!', LOG.INFO); }); conn.on('error', function(err) { if (err.rawCommand === '401') { // Player disconnected? manager.delPlayer(err.args[1], IRCPlayer); } else - self.log('IRC Error: ' + util.inspect(err)); + self.log('Connection error: ' + util.inspect(err, false, 4), LOG.ERROR); }); conn.on('pm', function(from, msg) { if (msg.length) { @@ -118,13 +119,29 @@ GameInterface.prototype.init = function() { msg = msg.substring(1).toLowerCase(); if (msg === 'help') { // List commands + [ + '!help -- this listing', + '!games -- shows simple game stats', + '!points -- shows your current point count', + '!create [gameName] -- creates a new game', + '!start -- starts the game (if you are the owner)', + '!join -- joins a game', + '!exit -- leaves the game', + '!hand -- shows your current hand', + '!draw -- draws a single card', + '!pass -- passes play to the next player', + '!play [color] -- plays the specified card (if Wild, color must be specified)', + '(end of help)' + ].forEach(function(line) { + conn.say(from, line); + }); } else if (msg === 'games') { var stats = manager.gamesStats(); conn.say(from, stats[0] + ' game(s) waiting for players and ' + stats[1] + ' game(s) in progress'); } else if (msg === 'points') { if (ret = manager.findPlayer(from, IRCPlayer)) - conn.say(from, 'You currently have ' + ret.points + ' points'); + conn.say(from, 'You currently have ' + ret.points + ' point(s)'); else conn.say(from, 'You are not currently in a game'); } else if (msg === 'hand') { @@ -218,9 +235,6 @@ GameInterface.prototype.init = function() { } } }); - conn.on('error', function(msg) { - self.log('Connection error: ' + util.inspect(msg, false, 4), LOG.ERROR); - }); }; // ============================================================================= function formatCard(card) { diff --git a/lib/frontends/web/index.js b/lib/frontends/web/index.js index c4441cf..ed9b6ef 100644 --- a/lib/frontends/web/index.js +++ b/lib/frontends/web/index.js @@ -69,6 +69,8 @@ var GameInterface = module.exports = function(manager, fnLog) { var pubPath = __dirname + '/public', imgPath = pubPath + '/images'; localFiles['index.htm'] = fs.readFileSync(pubPath + '/index.htm'); + localFiles['style.css'] = fs.readFileSync(pubPath + '/style.css'); + localFiles['style.ie6.css'] = fs.readFileSync(pubPath + '/style.ie6.css'); localFiles['game.js'] = fs.readFileSync(pubPath + '/game.js'); localFiles['flashws.js'] = fs.readFileSync(pubPath + '/flashws.js'); localFiles['transport.js'] = fs.readFileSync(pubPath + '/transport.js'); @@ -110,6 +112,8 @@ GameInterface.prototype.init = function() { if (localFiles[file]) { if (ext === 'js') type = 'text/javascript'; + else if (ext === 'css') + type = 'text/css'; else if (ext === 'swf') type = 'application/x-shockwave-flash'; else if (ext === 'htm') diff --git a/lib/frontends/web/public/game.js b/lib/frontends/web/public/game.js index 55adf87..57492ce 100644 --- a/lib/frontends/web/public/game.js +++ b/lib/frontends/web/public/game.js @@ -1,10 +1,11 @@ var conn, callback, players = {}, me, imgBack = 'images/back.png', - inGame = false, isNewRound = false, isWild = false, elWild, dir = 1; + inGame = false, isNewRound = false, isWild = false, elWild, dir = 1, + isAnimating = false; /* Game functions */ function addPlayer(p) { players[p.id] = p; - $('#players').append('
' + p.name + '
'); + $('#players').append('
' + entities(p.name) + '
'); return 'player-' + p.id; } function delPlayer(p) { @@ -74,11 +75,11 @@ function toggleDir() { $('#dir').html('←'); } function reset() { - isWild = inGame = false; + isWild = inGame = isAnimating = false; dir = -1; - $('.playingarea').hide(); $('#players, #hand').empty(); - $('#piles, #pass, #showWC').hide(); + $('#piles, #pass, #showWC, #playingarea, #gameInfo, #btnLeave, #btnStart').hide(); + $('#btnCreate, #btnJoin').show(); $('.owner').removeClass('owner'); $('.turn').removeClass('turn'); $('#myscore').html('0'); @@ -89,14 +90,14 @@ function reset() { function handleEvent(res) { if (res.event === 'playerjoin') { addPlayer(res.player); - status(res.player.name + ' joined the game'); + status(entities(res.player.name) + ' joined the game'); } else if (res.event === 'playerquit') { delete players[res.player.id]; $('#player-' + res.player.id).remove(); if (res.newOwner) $('#player-' + res.newOwner.id).addClass('owner'); if (players.length > 1) - status(res.player.name + ' left the game'); + status(entities(res.player.name) + ' left the game'); } else if (res.event === 'start') { var msg; if (res.roundWinner) { @@ -104,14 +105,17 @@ function handleEvent(res) { msg = 'You'; $('#myscore').html(res.roundWinner.points); } else - msg = res.roundWinner.name; + msg = entities(res.roundWinner.name); msg += ' won this round. Next round started.'; + dir = -1; + toggleDir(); isNewRound = true; isWild = false; callback = undefined; $('#hand').empty(); $('#pass, #showWC').hide(); } else { + $('#gameInfo').show(); inGame = true; msg = 'Game started.'; } @@ -134,7 +138,7 @@ function handleEvent(res) { status(msg); } else if (res.event === 'play') { isNewRound = false; - var msg = res.player.name + ' played a ' + cardToText(res.card); + var msg = entities(res.player.name) + ' played a ' + cardToText(res.card); if (typeof res.wildColor !== 'undefined') { isWild = true; $('#wildColor').attr('class', 'center wildColor' + res.wildColor); @@ -149,7 +153,7 @@ function handleEvent(res) { animPlay('#player-' + res.player.id + ' div.cardcount', res.card); status(msg); } else if (res.event === 'end') { - status('Game ended' + (res.player ? '. Game winner: ' + res.player.name : '')); + status('Game ended' + (res.player ? '. Game winner: ' + entities(res.player.name) : '')); reset(); } else if (res.event === 'turn') { $('.turn').removeClass('turn'); @@ -157,12 +161,13 @@ function handleEvent(res) { status('Your turn'); $('#player-' + res.player.id).addClass('turn'); } else if (res.event === 'draw') { - var who = res.player.name; + var who = entities(res.player.name); if (res.drawnCards) { who = 'You'; var i = 0; animDraw('#player-' + me.id, res.drawnCards.length, function() { $('#hand').append(''); + addCardCount(me.id, 1); }); } else { animDraw('#player-' + res.player.id + ' div.cardcount', res.numCards, function() { @@ -170,13 +175,12 @@ function handleEvent(res) { }); } status(who + ' drew ' + res.numCards + ' card' + (res.numCards > 1 ? 's' : '')); - } else if (res.event === 'pass') { - status(res.player.name + ' passed'); - } else if (res.event === 'youknow') { - status(res.player.name + ' has one card left!'); - } else { + } else if (res.event === 'pass') + status(entities(res.player.name) + ' passed'); + else if (res.event === 'youknow') + status(entities(res.player.name) + ' has one card left!'); + else log('Received unexpected event \'' + res.event + '\': ' + data); - } } function animDraw(where, num, cbEach) { if (num <= 0) return; @@ -250,11 +254,13 @@ function animPlay(where, card, cbDone) { opacity: 1 }, 250, function() { $el.remove(); - $('#discard img').attr('src', src); + if (!isNewRound) + $('#discard img').attr('src', src); if ($handcard) $handcard.remove(); if (cbDone) cbDone(); + isAnimating = false; } ); } @@ -289,50 +295,57 @@ function preloadAssets() { $('')[0].src = imgBack; } function initUIHandlers() { - $('#btnConnect').click(function() { conn.connect(address); }); $('#btnRegister').click(function() { var name; if (name = prompt('Enter a nickname to use:')) { - send('register ' + name, fnEmpty); + send('register ' + name, function() { + status('Registered player name'); + $('#btnRegister').hide(); + }); } }); $('#btnCreate').click(function() { var gameName = prompt('Enter new game name (blank to autogenerate):'); if (typeof gameName === 'string') { send('create' + (gameName.length > 0 ? ' ' + gameName : ''), function(res) { - $('.playingarea').show(); + $('#playingarea').show(); me = res.me; var id = '#' + addPlayer(me); $(id).addClass('owner'); $(id + ' .playerName').css('text-decoration', 'underline'); status('Created game: ' + entities(res.gameName)); + $('#btnStart, #btnLeave').show(); + $('#btnJoin, #btnCreate').hide(); }); } }); $('#btnStart').click(function() { - send('start', fnEmpty); + send('start', function() { + $('#btnStart').hide(); + }); }); $('#btnJoin').click(function() { var gameName; if (gameName = prompt('Join which game?')) { send('join ' + gameName, function(res) { - $('.playingarea').show(); + $('#btnJoin, #btnCreate, #btnStart').hide(); + $('#playingarea, #btnLeave').show(); me = res.me; if (res.players) for (var i=0,len=res.players.length; i 3) { @@ -369,6 +386,9 @@ function initUIHandlers() { $('#colorchooser').modal({ overlayClose: true, opacity: 70 }); } else { send('play ' + idx, function() { + addCardCount(me.id, -1); + isWild = false; + $('#showWC').hide(); if (!isNewRound && inGame) status(' '); else @@ -384,7 +404,7 @@ function initUIHandlers() { /* Setup the connnection */ conn = initTransport(function() { - log('Connected!'); + status('Connected to server'); }, function(data) { log('Received: ' + data); @@ -398,21 +418,23 @@ conn = initTransport(function() { if (res.event) handleEvent(res); else if (callback) { - if (res.error) + if (res.error) { alert('Error: ' + res.error); - else + isAnimating = false; + } else callback(res.ret); callback = undefined; - } - else + } else { log('Received unexpected response: ' + data); + isAnimating = false; + } }, function() { // disconnected cb - log('Lost connection with the server'); - //reset(); + status('Lost connection with the server'); + reset(); }, function(msg) { // error cb - log('Unexpected error while communicating with server: ' + msg); + status('Comm Error: ' + msg); reset(); }); if (!conn.connect) { @@ -423,5 +445,7 @@ if (!conn.connect) { $(function() { initUIHandlers(); + $('#btnLeave, #btnStart').hide(); + conn.connect(address); }); } \ No newline at end of file diff --git a/lib/frontends/web/public/index.htm b/lib/frontends/web/public/index.htm index 29aba13..30d84b6 100644 --- a/lib/frontends/web/public/index.htm +++ b/lib/frontends/web/public/index.htm @@ -9,130 +9,52 @@ var address = '127.0.0.1:8000'; - - + + +