Permalink
Browse files

Track unlocked levels and best scores (# of stars per altitude).

  • Loading branch information...
1 parent becbc38 commit d4421fc63907463f7bf245ddca7d2e6825a1e7cd @cscott committed May 25, 2012
Showing with 86 additions and 68 deletions.
  1. +46 −25 assets/www/index.js
  2. +40 −43 assets/www/score.js
View
@@ -20,6 +20,11 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
var refresh;
var SPROUTS;
+ var ALTITUDES = ['ground', 'troposphere', 'stratosphere', 'mesosphere'];
+ // make reverse mapping as well.
+ ALTITUDES.forEach(function(a, i) { ALTITUDES[a] = i; });
+ ALTITUDES.toNum = function(a) { return ALTITUDES[a]; };
+
var AWARDS = [['a1', 1/2+1/2],
['a2', 1/4+1/4],
['a3', 1/8+1/6],
@@ -72,25 +77,30 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
if (GameMode.currentMode !== GameMode.Playing) {
return; /* we're already transitioning */
}
+ // record sprouts sizes
+ var sproutsizes = AWARDS.map(function(a) {
+ return SPROUTS[a[0]].size;
+ });
+ // tell funf about completion
funf.record('mode', {
name: 'playing',
type: 'levelcomplete',
stars: Ruler.stars,
streak: Ruler.streak,
smoothedHeight: Ruler.smoothedHeight,
+ sprouts: sproutsizes,
level: GameMode.Playing.currentLevel.num,
- altitude: GameLevel.altitude2num(GameMode.Playing.currentAltitude)
+ altitude: ALTITUDES.toNum(GameMode.Playing.currentAltitude)
});
- stopMusic();
+ // unlock next level
+ score.setCompleted(GameMode.Playing.currentLevel.levelClass,
+ GameMode.Playing.currentAltitude,
+ Ruler.stars);
// play congratulatory sound!
+ stopMusic();
LEVEL_SOUNDS[0].play();
- // record sprouts sizes
- var sproutsizes = AWARDS.map(function(a) {
- return SPROUTS[a[0]].size;
- });
- // XXX award stars!
+ // award stars!
GameMode.StarThrob.push();
- // XXX save score, award stars, etc!
};
var ColoredElement = function(element, color) {
@@ -481,9 +491,9 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
altitudeStars = [];
var createMenuTags = function() {
- ['ground', 'troposphere', 'stratosphere', 'mesosphere'].forEach(function(altitude) {
+ ALTITUDES.forEach(function(altitude) {
var s = new MenuTag(altitude);
- s.attach(document.querySelector('#menu .awards .'+altitude));
+ s.attach(document.querySelector('#menu .awards > .'+altitude));
altitudeStars.push(s);
});
};
@@ -605,6 +615,8 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
return function() {
superEnter.call(this);
funf.record('mode', { name: 'menu' });
+ // sync the exposed altitudes from the current score object
+ this.syncExposed();
};
})(GameMode.Menu.enter);
GameMode.Menu.start = function(altitude) {
@@ -621,19 +633,38 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
name: 'playing',
type: 'levelstart',
level: GameMode.Playing.currentLevel.num,
- altitude: GameLevel.altitude2num(GameMode.Playing.currentAltitude)
+ altitude: ALTITUDES.toNum(GameMode.Playing.currentAltitude)
});
};
GameMode.Menu.switchLevel = function(level) {
var levelElem = document.querySelector('#menu .level');
this.currentLevel = _switchClass(levelElem, this.currentLevel, level,
'levelClass');
};
- GameMode.Menu.setExposed = function(altitude) {
+ GameMode.Menu.syncExposed = function() {
+ for (i=0; i < ALTITUDES.length; i++) {
+ var numStars =
+ score.numStars(this.currentLevel.levelClass, ALTITUDES[i]);
+ this.setExposed(ALTITUDES[i], numStars);
+ if (!score.isCompleted(this.currentLevel.levelClass, ALTITUDES[i])){
+ break;
+ }
+ }
+ };
+ GameMode.Menu.setExposed = function(altitude, stars) {
var shadeElem = document.querySelector('#menu .level');
var old = this.currentExposed && ('exposed-'+this.currentExposed);
_switchClass(shadeElem, old, 'exposed-'+altitude);
this.currentExposed = altitude;
+ // set the # of stars
+ var starsElem = document.querySelector('#menu .awards > .'+altitude+' > .stars');
+ ['zero','one','two','three'].forEach(function(name, num) {
+ if (stars===num) {
+ starsElem.classList.add(name);
+ } else {
+ starsElem.classList.remove(name);
+ }
+ });
};
MenuTag.prototype.altitudeClicked =
GameMode.Menu.start.bind(GameMode.Menu);
@@ -749,7 +780,6 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
var sprout = SPROUTS[a[0]];
sprout.setTime('0s', '1s');
});
- GameMode.Menu.setExposed(GameMode.Playing.currentAltitude);//XXX HACK
} else {
GameMode.Menu.switchLevel(GameMode.Playing.currentLevel);
GameMode.switchTo(GameMode.Menu);
@@ -797,15 +827,15 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
this.currentAltitude, altitude);
};
GameMode.Playing.nextAltitude = function() {
- var a = (GameLevel.altitude2num(this.currentAltitude) + 1) % 4;
+ var a = (ALTITUDES.toNum(this.currentAltitude) + 1) % ALTITUDES.length;
if (a === 0) {
var l = this.currentLevel.nextLevel();
if (l===null) {
return false; // no more levels.
}
this.switchLevel(l);
}
- this.switchAltitude(GameLevel.num2altitude(a));
+ this.switchAltitude(ALTITUDES[a]);
return true;
};
GameMode.Playing.pause = (function(superPause) {
@@ -854,14 +884,6 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
GameLevel.prototype.nextLevel = function() { return null; };
GameLevel.prototype.soundFor = function(altitude, color) {
};
- GameLevel.altitude2num = (function() {
- var table = {ground: 0, troposphere: 1, stratosphere: 2, mesosphere: 3};
- return function(a) { return table[a]; };
- })();
- GameLevel.num2altitude = (function() {
- var table = [ 'ground', 'troposphere', 'stratosphere', 'mesosphere'];
- return function(n) { return table[n]; };
- })();
var LEVELS = [ new GameLevel('grass') ]; // XXX
LEVELS.forEach(function(l, i) {
@@ -927,7 +949,7 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
this.height = this.smoothedHeight *
Math.max(0.28, Math.pow(0.98, this.streak));
- var pct = 25 * (this.height + GameLevel.altitude2num(altitude));
+ var pct = 25 * (this.height + ALTITUDES.toNum(altitude));
this.domElement.style.height = pct+'%';
// light up one, two, or three stars
var nStars = (this.height < 0.28) ? 3 :
@@ -1159,7 +1181,6 @@ define(['domReady!', './alea', './compat', './funf', 'nell!', 'score!', 'sound',
// start in menu screen
window.GameMode = GameMode;
GameMode.Menu.switchLevel(LEVELS[0]);
- GameMode.Menu.setExposed('ground');
GameMode.switchTo(GameMode.Menu);
if (HTML5_HISTORY) {
history.replaceState(GameMode.currentMode.toJSON(),
View
@@ -12,58 +12,55 @@ define(['./lawnchair/lawnchair'], function(Lawnchair) {
});
};
- var compare = function(scorea, scoreb) {
- // scores are arrays. compare from last element to first
- if (scorea.length !== scoreb.length) {
- return scorea.length - scoreb.length;
+ var Score = function(lawnchair, unlocked) {
+ this.lawnchair = lawnchair;
+ this.unlocked = unlocked || {};
+ };
+ Score.prototype = {};
+ Score.prototype._get = function(level, altitude, create) {
+ if (!this.unlocked[level]) {
+ if (!create) { return {}; }
+ this.unlocked[level] = {};
}
- var n = scorea.length-1;
- for ( ; n>=0; n--) {
- if (scorea[n] !== scoreb[n]) {
- return scorea[n] - scoreb[n];
- }
+ if (!this.unlocked[level][altitude]) {
+ if (!create) { return {}; }
+ this.unlocked[level][altitude] = {};
}
- return 0;
+ return this.unlocked[level][altitude];
};
-
- var Score = function(lawnchair, best, bestTime, recent, recentTime) {
- this.lawnchair = lawnchair;
- this.best = best;
- this.bestTime = bestTime;
- this.recent = recent;
- this.recentTime = recentTime;
+ Score.prototype.isCompleted = function(level, altitude) {
+ return !!(this._get(level, altitude).firstCompleted);
};
- Score.prototype = {};
- Score.prototype.save = function(nscore) {
- this.recent = nscore;
- this.recentTime = Date.now();
- this.lawnchair.save({key: 'recent', value: this.recent,
- timestamp: this.recentTime});
- // is this a new high score?
- if ((!this.best) || compare(nscore, this.best) > 0) {
- this.best = this.recent;
- this.bestTime = this.recentTime;
- this.lawnchair.save({key: 'best', value: this.best,
- timestamp: this.bestTime});
- if (this.funf) {
- // XXX work around bug in db2csv script which flattens
- // the array into 10 separate 'highscore' entries if
- // we don't convert this.best from an array to a string
- this.funf.record('highscore', ""+this.best);
- }
+ Score.prototype.numStars = function(level, altitude) {
+ return this._get(level, altitude).numStars || 0;
+ };
+ Score.prototype.setCompleted = function(level, altitude, numStars) {
+ var info = this._get(level, altitude, true/*create*/);
+ var prevStars = (info.numStars || 0);
+ var isNew = (!info.firstCompleted) || (numStars > prevStars);
+ if (!isNew) { return; }
+ // new high score / not previously unlocked
+ if (!info.firstCompleted) { info.firstCompleted = Date.now(); }
+ info.lastCompleted = Date.now();
+ info.numStars = numStars;
+ if (this.funf) {
+ this.funf.record('unlocked', {
+ level:level,
+ altitude:altitude,
+ numStars: numStars,
+ firstCompleted: info.firstCompleted
+ });
}
+ this.save();
+ };
+ Score.prototype.save = function() {
+ this.lawnchair.save({key: 'unlocked', value: this.unlocked});
};
var makeScoreAsync = function(callback) {
var withLawnchair = function(lawnchair) {
- getDefault(lawnchair, 'best', null, function(best) {
- getDefault(lawnchair, 'recent', null, function(recent) {
- callback(new Score(lawnchair,
- best && best.value,
- best && best.timestamp,
- recent && recent.value,
- recent && recent.timestamp));
- });
+ getDefault(lawnchair, 'unlocked', {}, function(unlocked) {
+ callback(new Score(lawnchair, unlocked.value));
});
};
Lawnchair({name:'score'}, function() { withLawnchair(this); });

0 comments on commit d4421fc

Please sign in to comment.