next level and id refactor

This commit is contained in:
Peter Cottle 2013-01-09 13:38:13 -08:00
parent d406317788
commit f0a9c66056
8 changed files with 416 additions and 210 deletions

View file

@ -10,6 +10,8 @@ var Main = require('../app');
function LevelArbiter() {
this.levelMap = {};
this.levelSequences = levelSequences;
this.sequences = [];
this.init();
var solvedMap;
@ -26,24 +28,30 @@ function LevelArbiter() {
LevelArbiter.prototype.init = function() {
var previousLevelID;
_.each(levelSequences, function(levels, levelSequenceName) {
_.each(this.levelSequences, function(levels, levelSequenceName) {
this.sequences.push(levelSequenceName);
if (!levels || !levels.length) {
throw new Error('no empty sequences allowed');
}
// for this particular sequence...
_.each(levels, function(level, index) {
this.validateLevel(level);
this.levelMap[level.id] = _.extend(
var id = levelSequenceName + String(index);
var compiledLevel = _.extend(
{},
level,
{
index: index,
id: levelSequenceName + String(index)
id: levelSequenceName + String(index),
sequenceName: levelSequenceName
}
);
// build up the chaining between levels
if (previousLevelID) {
this.levelMap[previousLevelID]['nextLevelID'] = level.id;
}
previousLevelID = level.id;
// update our internal data
this.levelMap[id] = compiledLevel;
this.levelSequences[levelSequenceName][index] = compiledLevel;
}, this);
}, this);
};
@ -56,10 +64,18 @@ LevelArbiter.prototype.isLevelSolved = function(id) {
};
LevelArbiter.prototype.levelSolved = function(id) {
// called without an id when we reset solved status
if (!id) { return; }
this.solvedMap[id] = true;
this.syncToStorage();
};
LevelArbiter.prototype.resetSolvedMap = function() {
this.solvedMap = {};
this.syncToStorage();
};
LevelArbiter.prototype.syncToStorage = function() {
try {
localStorage.setItem('solvedMap', JSON.stringify(this.solvedMap));
@ -87,24 +103,21 @@ LevelArbiter.prototype.validateLevel = function(level) {
throw new Error('I need this field for a level: ' + field);
}
});
if (this.levelMap[level.id]) {
throw new Error('woah that level already exists!');
}
};
LevelArbiter.prototype.getSequenceToLevels = function() {
return levelSequences;
return this.levelSequences;
};
LevelArbiter.prototype.getSequences = function() {
return _.keys(levelSequences);
return _.keys(this.levelSequences);
};
LevelArbiter.prototype.getLevelsInSequence = function(sequenceName) {
if (!levelSequences[sequenceName]) {
if (!this.levelSequences[sequenceName]) {
throw new Error('that sequecne name ' + sequenceName + 'does not exist');
}
return levelSequences[sequenceName];
return this.levelSequences[sequenceName];
};
LevelArbiter.prototype.getSequenceInfo = function(sequenceName) {
@ -119,12 +132,28 @@ LevelArbiter.prototype.getNextLevel = function(id) {
if (!this.levelMap[id]) {
throw new Error('that level doesnt exist!');
}
var nextID = this.levelMap[id]['nextLevelID'];
return this.levelMap[nextID];
};
LevelArbiter.prototype.getNextLevelID = function(id) {
return this.getNextLevel(id)['id'];
// meh, this method could be better. It's a tradeoff between
// having the sequence structure be really simple JSON
// and having no connectivity information between levels, which means
// you have to build that up yourself on every query
var level = this.levelMap[id];
var sequenceName = level.sequenceName;
var sequence = this.levelSequences[sequenceName];
var nextIndex = level.index + 1;
if (nextIndex < sequence.length) {
return sequence[nextIndex];
}
var nextSequenceIndex = this.sequences.indexOf(sequenceName) + 1;
if (nextSequenceIndex < this.sequences.length) {
var nextSequenceName = this.sequences[nextSequenceIndex];
return this.levelSequences[nextSequenceName][0];
}
// they finished the last level!
return null;
};
exports.LevelArbiter = LevelArbiter;

View file

@ -56,7 +56,8 @@ var LevelBuilder = Level.extend({
LevelBuilder.__super__.initialize.apply(this, [options]);
this.initStartVisualization();
this.startDialog = undefined;
this.initStartDialog();
// we wont be using this stuff, and its to delete to ensure we overwrite all functions that
// include that functionality
@ -216,7 +217,19 @@ var LevelBuilder = Level.extend({
if (this.level.hint === undefined) {
this.setHint();
}
console.log(this.level);
var compiledLevel = _.extend(
{},
this.level
);
// the start dialog now is just our help intro thing
delete compiledLevel.startDialog;
if (this.startDialog) {
compiledLevel.startDialog = this.startDialog;
}
console.log(compiledLevel);
command.finishWith(deferred);
},

View file

@ -23,6 +23,8 @@ var LevelToolbar = require('../views').LevelToolbar;
var TreeCompare = require('../git/treeCompare').TreeCompare;
var regexMap = {
'level help': /^level help$/,
'start dialog': /^start dialog$/,
'show goal': /^show goal$/,
'hide goal': /^hide goal$/,
'show solution': /^show solution$/
@ -50,11 +52,11 @@ var Level = Sandbox.extend({
Level.__super__.initialize.apply(this, [options]);
this.startOffCommand();
this.handleOpen();
this.handleOpen(options.deferred);
},
handleOpen: function() {
this.options.deferred = this.options.deferred || Q.defer();
handleOpen: function(deferred) {
deferred = deferred || Q.defer();
// if there is a multiview in the beginning, open that
// and let it resolve our deferred
@ -62,15 +64,28 @@ var Level = Sandbox.extend({
new MultiView(_.extend(
{},
this.level.startDialog,
{ deferred: this.options.deferred }
{ deferred: deferred }
));
return;
}
// otherwise, resolve after a 700 second delay
setTimeout(_.bind(function() {
this.options.deferred.resolve();
}, this), this.getAnimationTime() * 1.2);
// otherwise, resolve after a 700 second delay to allow
// for us to animate easily
setTimeout(function() {
deferred.resolve();
}, this.getAnimationTime() * 1.2);
},
startDialog: function(command, deferred) {
if (!this.level.startDialog) {
command.set('error', new Errors.GitError({
msg: 'There is no start dialog to show for this level!'
}));
deferred.resolve();
return;
}
this.handleOpen(deferred);
},
initName: function() {
@ -290,11 +305,10 @@ var Level = Sandbox.extend({
this.mainVis.gitVisuals.finishAnimation()
.then(function() {
// TODO if there is no future level...
// we want to ask if they will move onto the next level...
// we want to ask if they will move onto the next level
// while giving them their results...
var nextDialog = new NextLevelConfirm({
nextLevelName: nextLevel.name,
nextLevel: nextLevel,
numCommands: numCommands,
best: best
});
@ -302,10 +316,12 @@ var Level = Sandbox.extend({
return nextDialog.getPromise();
})
.then(function() {
Main.getEventBaton().trigger(
'commandSubmitted',
'level ' + nextLevel.id
);
if (nextLevel) {
Main.getEventBaton().trigger(
'commandSubmitted',
'level ' + nextLevel.id
);
}
})
.fail(function() {
// nothing to do, we will just close
@ -341,6 +357,12 @@ var Level = Sandbox.extend({
"Hmm, there doesn't seem to be a hint for this level :-/";
return [
[/^help$/, function() {
throw new Errors.CommandResult({
msg: 'You are in a level, so multiple forms of help are available. Please select either ' +
'"level help" or "general help"'
});
}],
[/^hint$/, function() {
throw new Errors.CommandResult({
msg: hintMsg
@ -388,7 +410,9 @@ var Level = Sandbox.extend({
var methodMap = {
'show goal': this.showGoal,
'hide goal': this.hideGoal,
'show solution': this.showSolution
'show solution': this.showSolution,
'start dialog': this.startDialog,
'level help': this.startDialog
};
var method = methodMap[command.get('method')];
if (!method) {

View file

@ -180,8 +180,18 @@ var Sandbox = Backbone.View.extend({
});
},
resetSolved: function(command, deferred) {
Main.getLevelArbiter().resetSolvedMap();
command.addWarning(
"Solved map was reset, you are starting from a clean slate!"
);
deferred.resolve();
},
processSandboxCommand: function(command, deferred) {
var commandMap = {
'reset solved': this.resetSolved,
'general help': this.helpDialog,
'help': this.helpDialog,
'reset': this.reset,
'delay': this.delay,

View file

@ -45,6 +45,8 @@ var instantCommands = [
];
var regexMap = {
'reset solved': /^reset solved($|\s)/,
'general help': /^general help($|\s)/,
'help': /^help($|\s)|\?/,
'reset': /^reset($|\s)/,
'delay': /^delay (\d+)$/,

View file

@ -367,7 +367,7 @@ var ConfirmCancelTerminal = Backbone.View.extend({
var NextLevelConfirm = ConfirmCancelTerminal.extend({
initialize: function(options) {
options = options || {};
this.nextLevelName = options.nextLevelName || 'The mysterious next level';
var nextLevelName = (options.nextLevel) ? options.nextLevel.name : '';
var markdowns = [
'## Great Job!!',
@ -386,11 +386,18 @@ var NextLevelConfirm = ConfirmCancelTerminal.extend({
);
}
markdowns = markdowns.concat([
'',
'Would you like to move onto "',
this.nextLevelName + '", the next level?'
]);
if (options.nextLevel) {
markdowns = markdowns.concat([
'',
'Would you like to move onto "',
nextLevelName + '", the next level?'
]);
} else {
markdowns = markdowns.concat([
'',
'Wow!!! You finished the last level, congratulations!'
]);
}
options.modalAlert = {
markdowns: markdowns

View file

@ -150,13 +150,8 @@ var LevelDropdownView = ContainedBase.extend({
},
getSequenceIndex: function(name) {
var index;
_.each(this.sequences, function(_name, _index) {
if (_name == name) {
index = _index;
}
});
if (index === undefined) { throw new Error('didnt find'); }
var index = this.sequences.indexOf(name);
if (index < 0) { throw new Error('didnt find'); }
return index;
},